Blender  V2.93
fsmenu.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_blenlib.h"
32 #include "BLI_ghash.h"
33 #include "BLI_utildefines.h"
34 
35 #include "BLT_translation.h"
36 
37 #include "BKE_appdir.h"
38 
39 #include "ED_fileselect.h"
40 
41 #ifdef WIN32
42 /* Need to include windows.h so _WIN32_IE is defined. */
43 # include <windows.h>
44 /* For SHGetSpecialFolderPath, has to be done before BLI_winstuff
45  * because 'near' is disabled through BLI_windstuff. */
46 # include "BLI_winstuff.h"
47 # include <shlobj.h>
48 #endif
49 
50 #include "UI_interface_icons.h"
51 #include "UI_resources.h"
52 #include "WM_api.h"
53 #include "WM_types.h"
54 
55 #ifdef __APPLE__
56 # include <Carbon/Carbon.h>
57 #endif /* __APPLE__ */
58 
59 #ifdef __linux__
60 # include "BLI_fileops_types.h"
61 # include <mntent.h>
62 #endif
63 
64 #include "fsmenu.h" /* include ourselves */
65 
66 /* FSMENU HANDLING */
67 
68 typedef struct FSMenu {
75 
76 static FSMenu *g_fsmenu = NULL;
77 
79 {
80  if (!g_fsmenu) {
81  g_fsmenu = MEM_callocN(sizeof(struct FSMenu), "fsmenu");
82  }
83  return g_fsmenu;
84 }
85 
86 struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
87 {
88  FSMenuEntry *fsm_head = NULL;
89 
90  switch (category) {
91  case FS_CATEGORY_SYSTEM:
92  fsm_head = fsmenu->fsmenu_system;
93  break;
95  fsm_head = fsmenu->fsmenu_system_bookmarks;
96  break;
98  fsm_head = fsmenu->fsmenu_bookmarks;
99  break;
100  case FS_CATEGORY_RECENT:
101  fsm_head = fsmenu->fsmenu_recent;
102  break;
103  case FS_CATEGORY_OTHER:
104  fsm_head = fsmenu->fsmenu_other;
105  break;
106  }
107  return fsm_head;
108 }
109 
110 /* -------------------------------------------------------------------- */
120 static GHash *fsmenu_xdg_user_dirs_parse(const char *home)
121 {
122  /* Add to the default for variable, equals & quotes. */
123  char l[128 + FILE_MAXDIR];
124  FILE *fp;
125 
126  /* Check if the config file exists. */
127  {
128  char filepath[FILE_MAX];
129  const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
130  if (xdg_config_home != NULL) {
131  BLI_path_join(filepath, sizeof(filepath), xdg_config_home, "user-dirs.dirs", NULL);
132  }
133  else {
134  BLI_path_join(filepath, sizeof(filepath), home, ".config", "user-dirs.dirs", NULL);
135  }
136  fp = BLI_fopen(filepath, "r");
137  if (!fp) {
138  return NULL;
139  }
140  }
141  /* By default there are 8 paths. */
142  GHash *xdg_map = BLI_ghash_str_new_ex(__func__, 8);
143  while (fgets(l, sizeof(l), fp) != NULL) { /* read a line */
144 
145  /* Avoid inserting invalid values. */
146  if (STRPREFIX(l, "XDG_")) {
147  char *l_value = strchr(l, '=');
148  if (l_value != NULL) {
149  *l_value = '\0';
150  l_value++;
151 
152  BLI_str_rstrip(l_value);
153  const uint l_value_len = strlen(l_value);
154  if ((l_value[0] == '"') && (l_value_len > 0) && (l_value[l_value_len - 1] == '"')) {
155  l_value[l_value_len - 1] = '\0';
156  l_value++;
157 
158  char l_value_expanded[FILE_MAX];
159  char *l_value_final = l_value;
160 
161  /* This is currently the only variable used.
162  * Based on the 'user-dirs.dirs' man page,
163  * there is no need to resolve arbitrary environment variables. */
164  if (STRPREFIX(l_value, "$HOME" SEP_STR)) {
165  BLI_path_join(l_value_expanded, sizeof(l_value_expanded), home, l_value + 6, NULL);
166  l_value_final = l_value_expanded;
167  }
168 
169  BLI_ghash_insert(xdg_map, BLI_strdup(l), BLI_strdup(l_value_final));
170  }
171  }
172  }
173  }
174  fclose(fp);
175 
176  return xdg_map;
177 }
178 
179 static void fsmenu_xdg_user_dirs_free(GHash *xdg_map)
180 {
181  if (xdg_map != NULL) {
183  }
184 }
185 
194 static void fsmenu_xdg_insert_entry(GHash *xdg_map,
195  struct FSMenu *fsmenu,
196  const char *key,
197  const char *default_path,
198  int icon,
199  const char *home)
200 {
201  char xdg_path_buf[FILE_MAXDIR];
202  const char *xdg_path = xdg_map ? BLI_ghash_lookup(xdg_map, key) : NULL;
203  if (xdg_path == NULL) {
204  BLI_path_join(xdg_path_buf, sizeof(xdg_path_buf), home, default_path, NULL);
205  xdg_path = xdg_path_buf;
206  }
208  fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, xdg_path, N_(default_path), icon, FS_INSERT_LAST);
209 }
210 
213 void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
214 {
215  switch (category) {
216  case FS_CATEGORY_SYSTEM:
217  fsmenu->fsmenu_system = fsm_head;
218  break;
220  fsmenu->fsmenu_system_bookmarks = fsm_head;
221  break;
223  fsmenu->fsmenu_bookmarks = fsm_head;
224  break;
225  case FS_CATEGORY_RECENT:
226  fsmenu->fsmenu_recent = fsm_head;
227  break;
228  case FS_CATEGORY_OTHER:
229  fsmenu->fsmenu_other = fsm_head;
230  break;
231  }
232 }
233 
234 int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category)
235 {
236  FSMenuEntry *fsm_iter;
237  int count = 0;
238 
239  for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter; fsm_iter = fsm_iter->next) {
240  count++;
241  }
242 
243  return count;
244 }
245 
246 FSMenuEntry *ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
247 {
248  FSMenuEntry *fsm_iter;
249 
250  for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && idx;
251  fsm_iter = fsm_iter->next) {
252  idx--;
253  }
254 
255  return fsm_iter;
256 }
257 
258 char *ED_fsmenu_entry_get_path(struct FSMenuEntry *fsentry)
259 {
260  return fsentry->path;
261 }
262 
263 void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
264 {
265  if ((!fsentry->path || !path || !STREQ(path, fsentry->path)) && (fsentry->path != path)) {
266  char tmp_name[FILE_MAXFILE];
267 
268  MEM_SAFE_FREE(fsentry->path);
269 
270  fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL;
271 
272  BLI_join_dirfile(tmp_name,
273  sizeof(tmp_name),
276  fsmenu_write_file(ED_fsmenu_get(), tmp_name);
277  }
278 }
279 
281 {
282  return (fsentry->icon) ? fsentry->icon : ICON_FILE_FOLDER;
283 }
284 
285 void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon)
286 {
287  fsentry->icon = icon;
288 }
289 
290 static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
291 {
292  int offset = 0;
293  int len = name_size;
294 
295  if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) {
296  /* use as size */
297  len += 1;
298  }
299 
300  BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size));
301  if (!name[0]) {
302  name[0] = '/';
303  name[1] = '\0';
304  }
305 }
306 
307 char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry)
308 {
309  if (fsentry->name[0]) {
310  return fsentry->name;
311  }
312 
313  /* Here we abuse fsm_iter->name, keeping first char NULL. */
314  char *name = fsentry->name + 1;
315  size_t name_size = sizeof(fsentry->name) - 1;
316 
317  fsmenu_entry_generate_name(fsentry, name, name_size);
318  return name;
319 }
320 
321 void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name)
322 {
323  if (!STREQ(name, fsentry->name)) {
324  char tmp_name[FILE_MAXFILE];
325  size_t tmp_name_size = sizeof(tmp_name);
326 
327  fsmenu_entry_generate_name(fsentry, tmp_name, tmp_name_size);
328  if (!name[0] || STREQ(tmp_name, name)) {
329  /* reset name to default behavior. */
330  fsentry->name[0] = '\0';
331  }
332  else {
333  BLI_strncpy(fsentry->name, name, sizeof(fsentry->name));
334  }
335 
336  BLI_join_dirfile(tmp_name,
337  sizeof(tmp_name),
340  fsmenu_write_file(ED_fsmenu_get(), tmp_name);
341  }
342 }
343 
345 {
346  if (fsentry->path && fsentry->path[0]) {
347 #ifdef WIN32
348  /* XXX Special case, always consider those as valid.
349  * Thanks to Windows, which can spend five seconds to perform a mere stat() call on those paths
350  * See T43684. */
351  const char *exceptions[] = {"A:\\", "B:\\", NULL};
352  const size_t exceptions_len[] = {strlen(exceptions[0]), strlen(exceptions[1]), 0};
353  int i;
354 
355  for (i = 0; exceptions[i]; i++) {
356  if (STRCASEEQLEN(fsentry->path, exceptions[i], exceptions_len[i])) {
357  fsentry->valid = true;
358  return;
359  }
360  }
361 #endif
362  fsentry->valid = BLI_is_dir(fsentry->path);
363  }
364  else {
365  fsentry->valid = false;
366  }
367 }
368 
369 short fsmenu_can_save(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
370 {
371  FSMenuEntry *fsm_iter;
372 
373  for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && idx;
374  fsm_iter = fsm_iter->next) {
375  idx--;
376  }
377 
378  return fsm_iter ? fsm_iter->save : 0;
379 }
380 
381 void fsmenu_insert_entry(struct FSMenu *fsmenu,
382  FSMenuCategory category,
383  const char *path,
384  const char *name,
385  int icon,
386  FSMenuInsert flag)
387 {
388  const uint path_len = strlen(path);
389  BLI_assert(path_len > 0);
390  if (path_len == 0) {
391  return;
392  }
393  const bool has_trailing_slash = (path[path_len - 1] == SEP);
394  FSMenuEntry *fsm_prev;
395  FSMenuEntry *fsm_iter;
396  FSMenuEntry *fsm_head;
397 
398  fsm_head = ED_fsmenu_get_category(fsmenu, category);
399  fsm_prev = fsm_head; /* this is odd and not really correct? */
400 
401  for (fsm_iter = fsm_head; fsm_iter; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) {
402  if (fsm_iter->path) {
403  /* Compare, with/without the trailing slash in 'path'. */
404  const int cmp_ret = BLI_path_ncmp(path, fsm_iter->path, path_len);
405  if (cmp_ret == 0 && STREQ(fsm_iter->path + path_len, has_trailing_slash ? "" : SEP_STR)) {
406  if (flag & FS_INSERT_FIRST) {
407  if (fsm_iter != fsm_head) {
408  fsm_prev->next = fsm_iter->next;
409  fsm_iter->next = fsm_head;
410  ED_fsmenu_set_category(fsmenu, category, fsm_iter);
411  }
412  }
413  return;
414  }
415  if ((flag & FS_INSERT_SORTED) && cmp_ret < 0) {
416  break;
417  }
418  }
419  else {
420  /* if we're bookmarking this, file should come
421  * before the last separator, only automatically added
422  * current dir go after the last separator. */
423  if (flag & FS_INSERT_SAVE) {
424  break;
425  }
426  }
427  }
428 
429  fsm_iter = MEM_mallocN(sizeof(*fsm_iter), "fsme");
430  if (has_trailing_slash) {
431  fsm_iter->path = BLI_strdup(path);
432  }
433  else {
434  fsm_iter->path = BLI_strdupn(path, path_len + 1);
435  fsm_iter->path[path_len] = SEP;
436  fsm_iter->path[path_len + 1] = '\0';
437  }
438  fsm_iter->save = (flag & FS_INSERT_SAVE) != 0;
439 
440  /* If entry is also in another list, use that icon and maybe name. */
441  /* On macOS we get icons and names for System Bookmarks from the FS_CATEGORY_OTHER list. */
443 
444  const FSMenuCategory cats[] = {
449  };
450  int i = ARRAY_SIZE(cats);
451  if (category == FS_CATEGORY_BOOKMARKS) {
452  i--;
453  }
454 
455  while (i--) {
456  FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]);
457  for (; tfsm; tfsm = tfsm->next) {
458  if (STREQ(tfsm->path, fsm_iter->path)) {
459  icon = tfsm->icon;
460  if (tfsm->name[0] && (!name || !name[0])) {
461  name = tfsm->name;
462  }
463  break;
464  }
465  }
466  if (tfsm) {
467  break;
468  }
469  }
470  }
471 
472  if (name && name[0]) {
473  BLI_strncpy(fsm_iter->name, name, sizeof(fsm_iter->name));
474  }
475  else {
476  fsm_iter->name[0] = '\0';
477  }
478 
479  ED_fsmenu_entry_set_icon(fsm_iter, icon);
480 
481  fsmenu_entry_refresh_valid(fsm_iter);
482 
483  if (fsm_prev) {
484  if (flag & FS_INSERT_FIRST) {
485  fsm_iter->next = fsm_head;
486  ED_fsmenu_set_category(fsmenu, category, fsm_iter);
487  }
488  else {
489  fsm_iter->next = fsm_prev->next;
490  fsm_prev->next = fsm_iter;
491  }
492  }
493  else {
494  fsm_iter->next = fsm_head;
495  ED_fsmenu_set_category(fsmenu, category, fsm_iter);
496  }
497 }
498 
499 void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
500 {
501  FSMenuEntry *fsm_prev = NULL;
502  FSMenuEntry *fsm_iter;
503  FSMenuEntry *fsm_head;
504 
505  fsm_head = ED_fsmenu_get_category(fsmenu, category);
506 
507  for (fsm_iter = fsm_head; fsm_iter && idx; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) {
508  idx--;
509  }
510 
511  if (fsm_iter) {
512  /* you should only be able to remove entries that were
513  * not added by default, like windows drives.
514  * also separators (where path == NULL) shouldn't be removed */
515  if (fsm_iter->save && fsm_iter->path) {
516 
517  /* remove fsme from list */
518  if (fsm_prev) {
519  fsm_prev->next = fsm_iter->next;
520  }
521  else {
522  fsm_head = fsm_iter->next;
523  ED_fsmenu_set_category(fsmenu, category, fsm_head);
524  }
525  /* free entry */
526  MEM_freeN(fsm_iter->path);
527  MEM_freeN(fsm_iter);
528  }
529  }
530 }
531 
532 void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
533 {
534  FSMenuEntry *fsm_iter = NULL;
535  char fsm_name[FILE_MAX];
536  int nwritten = 0;
537 
538  FILE *fp = BLI_fopen(filename, "w");
539  if (!fp) {
540  return;
541  }
542 
543  fprintf(fp, "[Bookmarks]\n");
544  for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsm_iter;
545  fsm_iter = fsm_iter->next) {
546  if (fsm_iter->path && fsm_iter->save) {
547  fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
548  if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
549  fprintf(fp, "!%s\n", fsm_iter->name);
550  }
551  fprintf(fp, "%s\n", fsm_iter->path);
552  }
553  }
554  fprintf(fp, "[Recent]\n");
555  for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT);
556  fsm_iter && (nwritten < FSMENU_RECENT_MAX);
557  fsm_iter = fsm_iter->next, nwritten++) {
558  if (fsm_iter->path && fsm_iter->save) {
559  fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
560  if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
561  fprintf(fp, "!%s\n", fsm_iter->name);
562  }
563  fprintf(fp, "%s\n", fsm_iter->path);
564  }
565  }
566  fclose(fp);
567 }
568 
569 void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
570 {
571  char line[FILE_MAXDIR];
572  char name[FILE_MAXFILE];
574  FILE *fp;
575 
576  fp = BLI_fopen(filename, "r");
577  if (!fp) {
578  return;
579  }
580 
581  name[0] = '\0';
582 
583  while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */
584  if (STRPREFIX(line, "[Bookmarks]")) {
585  category = FS_CATEGORY_BOOKMARKS;
586  }
587  else if (STRPREFIX(line, "[Recent]")) {
588  category = FS_CATEGORY_RECENT;
589  }
590  else if (line[0] == '!') {
591  int len = strlen(line);
592  if (len > 0) {
593  if (line[len - 1] == '\n') {
594  line[len - 1] = '\0';
595  }
596  BLI_strncpy(name, line + 1, sizeof(name));
597  }
598  }
599  else {
600  int len = strlen(line);
601  if (len > 0) {
602  if (line[len - 1] == '\n') {
603  line[len - 1] = '\0';
604  }
605  /* don't do this because it can be slow on network drives,
606  * having a bookmark from a drive that's ejected or so isn't
607  * all _that_ bad */
608 #if 0
609  if (BLI_exists(line))
610 #endif
611  {
612  fsmenu_insert_entry(fsmenu, category, line, name, ICON_FILE_FOLDER, FS_INSERT_SAVE);
613  }
614  }
615  /* always reset name. */
616  name[0] = '\0';
617  }
618  }
619  fclose(fp);
620 }
621 
622 #ifdef WIN32
623 /* Add a Windows known folder path to the System list. */
624 static void fsmenu_add_windows_folder(struct FSMenu *fsmenu,
625  FSMenuCategory category,
626  REFKNOWNFOLDERID rfid,
627  const char *name,
628  const int icon,
629  FSMenuInsert flag)
630 {
631  LPWSTR pPath;
632  char line[FILE_MAXDIR];
633  if (SHGetKnownFolderPath(rfid, 0, NULL, &pPath) == S_OK) {
635  CoTaskMemFree(pPath);
636  fsmenu_insert_entry(fsmenu, category, line, name, icon, flag);
637  }
638 }
639 #endif
640 
641 void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
642 {
643  char line[FILE_MAXDIR];
644 #ifdef WIN32
645  /* Add the drive names to the listing */
646  {
647  wchar_t wline[FILE_MAXDIR];
648  __int64 tmp;
649  char tmps[4], *name;
650 
651  tmp = GetLogicalDrives();
652 
653  for (int i = 0; i < 26; i++) {
654  if ((tmp >> i) & 1) {
655  tmps[0] = 'A' + i;
656  tmps[1] = ':';
657  tmps[2] = '\\';
658  tmps[3] = '\0';
659  name = NULL;
660 
661  /* Flee from horrible win querying hover floppy drives! */
662  if (i > 1) {
663  /* Try to get a friendly drive description. */
664  SHFILEINFOW shFile = {0};
665  BLI_strncpy_wchar_from_utf8(wline, tmps, 4);
666  if (SHGetFileInfoW(wline, 0, &shFile, sizeof(SHFILEINFOW), SHGFI_DISPLAYNAME)) {
667  BLI_strncpy_wchar_as_utf8(line, shFile.szDisplayName, FILE_MAXDIR);
668  name = line;
669  }
670  }
671  if (name == NULL) {
672  name = tmps;
673  }
674 
675  int icon = ICON_DISK_DRIVE;
676  switch (GetDriveType(tmps)) {
677  case DRIVE_REMOVABLE:
678  icon = ICON_EXTERNAL_DRIVE;
679  break;
680  case DRIVE_CDROM:
681  icon = ICON_DISC;
682  break;
683  case DRIVE_FIXED:
684  case DRIVE_RAMDISK:
685  icon = ICON_DISK_DRIVE;
686  break;
687  case DRIVE_REMOTE:
688  icon = ICON_NETWORK_DRIVE;
689  break;
690  }
691 
693  }
694  }
695 
696  /* Get Special Folder Locations. */
697  if (read_bookmarks) {
698 
699  /* These items are shown in System List. */
700  fsmenu_add_windows_folder(fsmenu,
702  &FOLDERID_Profile,
703  N_("Home"),
704  ICON_HOME,
706  fsmenu_add_windows_folder(fsmenu,
708  &FOLDERID_Desktop,
709  N_("Desktop"),
710  ICON_DESKTOP,
712  fsmenu_add_windows_folder(fsmenu,
714  &FOLDERID_Documents,
715  N_("Documents"),
716  ICON_DOCUMENTS,
718  fsmenu_add_windows_folder(fsmenu,
720  &FOLDERID_Downloads,
721  N_("Downloads"),
722  ICON_IMPORT,
724  fsmenu_add_windows_folder(fsmenu,
726  &FOLDERID_Music,
727  N_("Music"),
728  ICON_FILE_SOUND,
730  fsmenu_add_windows_folder(fsmenu,
732  &FOLDERID_Pictures,
733  N_("Pictures"),
734  ICON_FILE_IMAGE,
736  fsmenu_add_windows_folder(fsmenu,
738  &FOLDERID_Videos,
739  N_("Videos"),
740  ICON_FILE_MOVIE,
742  fsmenu_add_windows_folder(fsmenu,
744  &FOLDERID_Fonts,
745  N_("Fonts"),
746  ICON_FILE_FONT,
748 
749  /* These items are just put in path cache for thumbnail views and if bookmarked. */
750 
751  fsmenu_add_windows_folder(
752  fsmenu, FS_CATEGORY_OTHER, &FOLDERID_UserProfiles, NULL, ICON_COMMUNITY, FS_INSERT_LAST);
753 
754  fsmenu_add_windows_folder(
755  fsmenu, FS_CATEGORY_OTHER, &FOLDERID_SkyDrive, NULL, ICON_URL, FS_INSERT_LAST);
756  }
757  }
758 #elif defined(__APPLE__)
759  {
760  /* We store some known macOS system paths and corresponding icons
761  * and names in the FS_CATEGORY_OTHER (not displayed directly) category. */
763  fsmenu, FS_CATEGORY_OTHER, "/Library/Fonts/", N_("Fonts"), ICON_FILE_FONT, FS_INSERT_LAST);
764  fsmenu_insert_entry(fsmenu,
766  "/Applications/",
767  N_("Applications"),
768  ICON_FILE_FOLDER,
770 
771  const char *home = BLI_getenv("HOME");
772 
773 # define FS_MACOS_PATH(path, name, icon) \
774  BLI_snprintf(line, sizeof(line), path, home); \
775  fsmenu_insert_entry(fsmenu, FS_CATEGORY_OTHER, line, name, icon, FS_INSERT_LAST);
776 
777  FS_MACOS_PATH("%s/", NULL, ICON_HOME)
778  FS_MACOS_PATH("%s/Desktop/", N_("Desktop"), ICON_DESKTOP)
779  FS_MACOS_PATH("%s/Documents/", N_("Documents"), ICON_DOCUMENTS)
780  FS_MACOS_PATH("%s/Downloads/", N_("Downloads"), ICON_IMPORT)
781  FS_MACOS_PATH("%s/Movies/", N_("Movies"), ICON_FILE_MOVIE)
782  FS_MACOS_PATH("%s/Music/", N_("Music"), ICON_FILE_SOUND)
783  FS_MACOS_PATH("%s/Pictures/", N_("Pictures"), ICON_FILE_IMAGE)
784  FS_MACOS_PATH("%s/Library/Fonts/", N_("Fonts"), ICON_FILE_FONT)
785 
786 # undef FS_MACOS_PATH
787 
788  /* Get mounted volumes better method OSX 10.6 and higher, see:
789  * https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html
790  */
791 
792  /* We get all volumes sorted including network and do not relay
793  * on user-defined finder visibility, less confusing. */
794 
795  CFURLRef cfURL = NULL;
796  CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
797  CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(
798  NULL, kCFURLEnumeratorSkipInvisibles, NULL);
799 
800  while (result != kCFURLEnumeratorEnd) {
801  char defPath[FILE_MAX];
802 
803  result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL);
804  if (result != kCFURLEnumeratorSuccess) {
805  continue;
806  }
807 
808  CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX);
809 
810  /* Get name of the volume. */
811  char name[FILE_MAXFILE] = "";
812  CFStringRef nameString = NULL;
813  CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeLocalizedNameKey, &nameString, NULL);
814  if (nameString != NULL) {
815  CFStringGetCString(nameString, name, sizeof(name), kCFStringEncodingUTF8);
816  CFRelease(nameString);
817  }
818 
819  /* Set icon for regular, removable or network drive. */
820  int icon = ICON_DISK_DRIVE;
821  CFBooleanRef localKey = NULL;
822  CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeIsLocalKey, &localKey, NULL);
823  if (localKey != NULL) {
824  if (!CFBooleanGetValue(localKey)) {
825  icon = ICON_NETWORK_DRIVE;
826  }
827  else {
828  CFBooleanRef ejectableKey = NULL;
829  CFURLCopyResourcePropertyForKey(cfURL, kCFURLVolumeIsEjectableKey, &ejectableKey, NULL);
830  if (ejectableKey != NULL) {
831  if (CFBooleanGetValue(ejectableKey)) {
832  icon = ICON_EXTERNAL_DRIVE;
833  }
834  CFRelease(ejectableKey);
835  }
836  }
837  CFRelease(localKey);
838  }
839 
841  fsmenu, FS_CATEGORY_SYSTEM, defPath, name[0] ? name : NULL, icon, FS_INSERT_SORTED);
842  }
843 
844  CFRelease(volEnum);
845 
846  /* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15.
847  * Will have to find a new method to sync the Finder Favorites with File Browser. */
848 # pragma GCC diagnostic push
849 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
850  /* Finally get user favorite places */
851  if (read_bookmarks) {
852  UInt32 seed;
853  LSSharedFileListRef list = LSSharedFileListCreate(
854  NULL, kLSSharedFileListFavoriteItems, NULL);
855  CFArrayRef pathesArray = LSSharedFileListCopySnapshot(list, &seed);
856  CFIndex pathesCount = CFArrayGetCount(pathesArray);
857 
858  for (CFIndex i = 0; i < pathesCount; i++) {
859  LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(
860  pathesArray, i);
861 
862  CFURLRef cfURL = NULL;
863  OSErr err = LSSharedFileListItemResolve(itemRef,
864  kLSSharedFileListNoUserInteraction |
865  kLSSharedFileListDoNotMountVolumes,
866  &cfURL,
867  NULL);
868  if (err != noErr || !cfURL) {
869  continue;
870  }
871 
872  CFStringRef pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
873 
874  if (pathString == NULL ||
875  !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8)) {
876  continue;
877  }
878 
879  /* Exclude "all my files" as it makes no sense in blender fileselector */
880  /* Exclude "airdrop" if wlan not active as it would show "" ) */
881  if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
883  fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, ICON_FILE_FOLDER, FS_INSERT_LAST);
884  }
885 
886  CFRelease(pathString);
887  CFRelease(cfURL);
888  }
889 
890  CFRelease(pathesArray);
891  CFRelease(list);
892  }
893 # pragma GCC diagnostic pop
894  }
895 #else
896  /* unix */
897  {
898  const char *home = BLI_getenv("HOME");
899 
900  if (read_bookmarks && home) {
901 
903  fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, home, N_("Home"), ICON_HOME, FS_INSERT_LAST);
904 
905  /* Follow the XDG spec, check if these are available. */
906  GHash *xdg_map = fsmenu_xdg_user_dirs_parse(home);
907 
908  struct {
909  const char *key;
910  const char *default_path;
911  BIFIconID icon;
912  } xdg_items[] = {
913  {"XDG_DESKTOP_DIR", "Desktop", ICON_DESKTOP},
914  {"XDG_DOCUMENTS_DIR", "Documents", ICON_DOCUMENTS},
915  {"XDG_DOWNLOAD_DIR", "Downloads", ICON_IMPORT},
916  {"XDG_VIDEOS_DIR", "Videos", ICON_FILE_MOVIE},
917  {"XDG_PICTURES_DIR", "Pictures", ICON_FILE_IMAGE},
918  {"XDG_MUSIC_DIR", "Music", ICON_FILE_SOUND},
919  };
920 
921  for (int i = 0; i < ARRAY_SIZE(xdg_items); i++) {
923  xdg_map, fsmenu, xdg_items[i].key, xdg_items[i].default_path, xdg_items[i].icon, home);
924  }
925 
926  fsmenu_xdg_user_dirs_free(xdg_map);
927  }
928 
929  {
930  int found = 0;
931 # ifdef __linux__
932  /* loop over mount points */
933  struct mntent *mnt;
934  FILE *fp;
935 
936  fp = setmntent(MOUNTED, "r");
937  if (fp == NULL) {
938  fprintf(stderr, "could not get a list of mounted file-systems\n");
939  }
940  else {
941  while ((mnt = getmntent(fp))) {
942  if (STRPREFIX(mnt->mnt_dir, "/boot")) {
943  /* Hide share not usable to the user. */
944  continue;
945  }
946  if (!STRPREFIX(mnt->mnt_fsname, "/dev")) {
947  continue;
948  }
949  if (STRPREFIX(mnt->mnt_fsname, "/dev/loop")) {
950  /* The dev/loop* entries are SNAPS used by desktop environment
951  * (Gnome) no need for them to show up in the list. */
952  continue;
953  }
954 
956  fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
957 
958  found = 1;
959  }
960  if (endmntent(fp) == 0) {
961  fprintf(stderr, "could not close the list of mounted filesystems\n");
962  }
963  }
964  /* Check gvfs shares. */
965  const char *const xdg_runtime_dir = BLI_getenv("XDG_RUNTIME_DIR");
966  if (xdg_runtime_dir != NULL) {
967  struct direntry *dir;
968  char name[FILE_MAX];
969  BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/");
970  const uint dir_len = BLI_filelist_dir_contents(name, &dir);
971  for (uint i = 0; i < dir_len; i++) {
972  if ((dir[i].type & S_IFDIR)) {
973  const char *dirname = dir[i].relname;
974  if (dirname[0] != '.') {
975  /* Dir names contain a lot of unwanted text.
976  * Assuming every entry ends with the share name */
977  const char *label = strstr(dirname, "share=");
978  if (label != NULL) {
979  /* Move pointer so "share=" is trimmed off
980  * or use full dirname as label. */
981  const char *label_test = label + 6;
982  label = *label_test ? label_test : dirname;
983  }
984  BLI_snprintf(line, sizeof(line), "%s%s", name, dirname);
986  fsmenu, FS_CATEGORY_SYSTEM, line, label, ICON_NETWORK_DRIVE, FS_INSERT_SORTED);
987  found = 1;
988  }
989  }
990  }
991  BLI_filelist_free(dir, dir_len);
992  }
993 # endif
994 
995  /* fallback */
996  if (!found) {
998  fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, ICON_DISK_DRIVE, FS_INSERT_SORTED);
999  }
1000  }
1001  }
1002 #endif
1003 
1004 #if defined(WIN32) || defined(__APPLE__)
1005  /* Quiet warnings. */
1007 #endif
1008 
1009  /* For all platforms, we add some directories from User Preferences to
1010  * the FS_CATEGORY_OTHER category so that these directories
1011  * have the appropriate icons when they are added to the Bookmarks. */
1012 #define FS_UDIR_PATH(dir, icon) \
1013  if (BLI_strnlen(dir, 3) > 2) { \
1014  fsmenu_insert_entry(fsmenu, FS_CATEGORY_OTHER, dir, NULL, icon, FS_INSERT_LAST); \
1015  }
1016 
1017  FS_UDIR_PATH(U.fontdir, ICON_FILE_FONT)
1018  FS_UDIR_PATH(U.textudir, ICON_FILE_IMAGE)
1019  FS_UDIR_PATH(U.pythondir, ICON_FILE_SCRIPT)
1020  FS_UDIR_PATH(U.sounddir, ICON_FILE_SOUND)
1021  FS_UDIR_PATH(U.tempdir, ICON_TEMP)
1022 
1023 #undef FS_UDIR_PATH
1024 }
1025 
1026 static void fsmenu_free_category(struct FSMenu *fsmenu, FSMenuCategory category)
1027 {
1028  FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category);
1029 
1030  while (fsm_iter) {
1031  FSMenuEntry *fsm_next = fsm_iter->next;
1032 
1033  if (fsm_iter->path) {
1034  MEM_freeN(fsm_iter->path);
1035  }
1036  MEM_freeN(fsm_iter);
1037 
1038  fsm_iter = fsm_next;
1039  }
1040 }
1041 
1043 {
1046 
1049 
1050  /* Add all entries to system category */
1051  fsmenu_read_system(fsmenu, true);
1052 }
1053 
1054 static void fsmenu_free_ex(FSMenu **fsmenu)
1055 {
1056  if (*fsmenu != NULL) {
1062  MEM_freeN(*fsmenu);
1063  }
1064 
1065  *fsmenu = NULL;
1066 }
1067 
1068 void fsmenu_free(void)
1069 {
1071 }
1072 
1073 static void fsmenu_copy_category(struct FSMenu *fsmenu_dst,
1074  struct FSMenu *fsmenu_src,
1075  const FSMenuCategory category)
1076 {
1077  FSMenuEntry *fsm_dst_prev = NULL, *fsm_dst_head = NULL;
1078  FSMenuEntry *fsm_src_iter = ED_fsmenu_get_category(fsmenu_src, category);
1079 
1080  for (; fsm_src_iter != NULL; fsm_src_iter = fsm_src_iter->next) {
1081  FSMenuEntry *fsm_dst = MEM_dupallocN(fsm_src_iter);
1082  if (fsm_dst->path != NULL) {
1083  fsm_dst->path = MEM_dupallocN(fsm_dst->path);
1084  }
1085 
1086  if (fsm_dst_prev != NULL) {
1087  fsm_dst_prev->next = fsm_dst;
1088  }
1089  else {
1090  fsm_dst_head = fsm_dst;
1091  }
1092  fsm_dst_prev = fsm_dst;
1093  }
1094 
1095  ED_fsmenu_set_category(fsmenu_dst, category, fsm_dst_head);
1096 }
1097 
1098 static FSMenu *fsmenu_copy(FSMenu *fsmenu)
1099 {
1100  FSMenu *fsmenu_copy = MEM_dupallocN(fsmenu);
1101 
1107 
1108  return fsmenu_copy;
1109 }
1110 
1111 int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir)
1112 {
1113  FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category);
1114  int i;
1115 
1116  for (i = 0; fsm_iter; fsm_iter = fsm_iter->next, i++) {
1117  if (BLI_path_cmp(dir, fsm_iter->path) == 0) {
1118  return i;
1119  }
1120  }
1121 
1122  return -1;
1123 }
1124 
1125 /* Thanks to some bookmarks sometimes being network drives that can have tens of seconds of delay
1126  * before being defined as unreachable by the OS, we need to validate the bookmarks in an async
1127  * job...
1128  */
1130  void *fsmenuv,
1131  /* Cannot be const, this function implements wm_jobs_start_callback.
1132  * NOLINTNEXTLINE: readability-non-const-parameter. */
1133  short *stop,
1134  short *do_update,
1135  float *UNUSED(progress))
1136 {
1137  FSMenu *fsmenu = fsmenuv;
1138 
1139  int categories[] = {
1141 
1142  for (size_t i = ARRAY_SIZE(categories); i--;) {
1143  FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]);
1144  for (; fsm_iter; fsm_iter = fsm_iter->next) {
1145  if (*stop) {
1146  return;
1147  }
1148  /* Note that we do not really need atomics primitives or thread locks here, since this only
1149  * sets one short, which is assumed to be 'atomic'-enough for us here. */
1150  fsmenu_entry_refresh_valid(fsm_iter);
1151  *do_update = true;
1152  }
1153  }
1154 }
1155 
1156 static void fsmenu_bookmark_validate_job_update(void *fsmenuv)
1157 {
1158  FSMenu *fsmenu_job = fsmenuv;
1159 
1160  int categories[] = {
1162 
1163  for (size_t i = ARRAY_SIZE(categories); i--;) {
1164  FSMenuEntry *fsm_iter_src = ED_fsmenu_get_category(fsmenu_job, categories[i]);
1165  FSMenuEntry *fsm_iter_dst = ED_fsmenu_get_category(ED_fsmenu_get(), categories[i]);
1166  for (; fsm_iter_dst != NULL; fsm_iter_dst = fsm_iter_dst->next) {
1167  while (fsm_iter_src != NULL && !STREQ(fsm_iter_dst->path, fsm_iter_src->path)) {
1168  fsm_iter_src = fsm_iter_src->next;
1169  }
1170  if (fsm_iter_src == NULL) {
1171  return;
1172  }
1173  fsm_iter_dst->valid = fsm_iter_src->valid;
1174  }
1175  }
1176 }
1177 
1178 static void fsmenu_bookmark_validate_job_end(void *fsmenuv)
1179 {
1180  /* In case there would be some dangling update... */
1182 }
1183 
1184 static void fsmenu_bookmark_validate_job_free(void *fsmenuv)
1185 {
1186  FSMenu *fsmenu = fsmenuv;
1187  fsmenu_free_ex(&fsmenu);
1188 }
1189 
1191 {
1192  wmJob *wm_job;
1193  FSMenu *fsmenu_job = fsmenu_copy(g_fsmenu);
1194 
1195  /* setup job */
1196  wm_job = WM_jobs_get(
1197  wm, wm->winactive, wm, "Validating Bookmarks...", 0, WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE);
1200  WM_jobs_callbacks(wm_job,
1202  NULL,
1205 
1206  /* start the job */
1207  WM_jobs_start(wm, wm_job);
1208 }
1209 
1211 {
1213 }
1214 
1216 {
1217  BLI_assert(fsmenu == ED_fsmenu_get());
1218  UNUSED_VARS_NDEBUG(fsmenu);
1219 
1222 }
@ BLENDER_USER_CONFIG
Definition: BKE_appdir.h:81
const char * BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
Definition: appdir.c:735
#define BLENDER_BOOKMARK_FILE
Definition: BKE_appdir.h:102
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:349
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
Definition: BLI_filelist.c:467
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist)
Definition: BLI_filelist.c:238
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:436
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
Some types for dealing with directories.
GHash * BLI_ghash_str_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
#define BLI_path_ncmp
#define FILE_MAXFILE
#define FILE_MAX
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1737
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
const char * BLI_getenv(const char *env) ATTR_NONNULL(1)
Definition: path_util.c:1313
#define SEP
bool BLI_path_name_at_index(const char *__restrict path, const int index, int *__restrict r_offset, int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1883
#define FILE_MAXDIR
#define BLI_path_cmp
void BLI_str_rstrip(char *str) ATTR_NONNULL()
Definition: string.c:915
char * BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:54
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string_utf8.c:295
size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string_utf8.c:393
unsigned int uint
Definition: BLI_sys_types.h:83
#define STRPREFIX(a, b)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define STRCASEEQLEN(a, b, n)
#define ELEM(...)
#define MIN2(a, b)
#define STREQ(a, b)
Compatibility-like things for windows.
const char * dirname(char *path)
#define N_(msgid)
FSMenuCategory
@ FS_CATEGORY_RECENT
@ FS_CATEGORY_BOOKMARKS
@ FS_CATEGORY_SYSTEM_BOOKMARKS
@ FS_CATEGORY_OTHER
@ FS_CATEGORY_SYSTEM
FSMenuInsert
@ FS_INSERT_SAVE
@ FS_INSERT_FIRST
@ FS_INSERT_SORTED
@ FS_INSERT_LAST
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
BIFIconID
Definition: UI_resources.h:34
@ WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE
Definition: WM_api.h:755
#define NC_SPACE
Definition: WM_types.h:293
#define ND_SPACE_FILE_LIST
Definition: WM_types.h:419
ATTR_WARN_UNUSED_RESULT const BMLoop * l
unsigned int U
Definition: btGjkEpa3.h:78
static unsigned long seed
Definition: btSoftBody.h:39
const char * label
static FT_Error err
Definition: freetypefont.c:52
FSMenu * ED_fsmenu_get(void)
Definition: fsmenu.c:78
static void fsmenu_copy_category(struct FSMenu *fsmenu_dst, struct FSMenu *fsmenu_src, const FSMenuCategory category)
Definition: fsmenu.c:1073
static void fsmenu_bookmark_validate_job_startjob(void *fsmenuv, short *stop, short *do_update, float *UNUSED(progress))
Definition: fsmenu.c:1129
static void fsmenu_free_ex(FSMenu **fsmenu)
Definition: fsmenu.c:1054
static void fsmenu_bookmark_validate_job_start(wmWindowManager *wm)
Definition: fsmenu.c:1190
static void fsmenu_bookmark_validate_job_free(void *fsmenuv)
Definition: fsmenu.c:1184
void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition: fsmenu.c:499
void fsmenu_refresh_system_category(struct FSMenu *fsmenu)
Definition: fsmenu.c:1042
static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
Definition: fsmenu.c:290
void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, int icon, FSMenuInsert flag)
Definition: fsmenu.c:381
short fsmenu_can_save(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition: fsmenu.c:369
static void fsmenu_bookmark_validate_job_update(void *fsmenuv)
Definition: fsmenu.c:1156
int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir)
Definition: fsmenu.c:1111
struct FSMenu FSMenu
char * ED_fsmenu_entry_get_path(struct FSMenuEntry *fsentry)
Definition: fsmenu.c:258
void fsmenu_refresh_bookmarks_status(wmWindowManager *wm, FSMenu *fsmenu)
Definition: fsmenu.c:1215
static FSMenu * g_fsmenu
Definition: fsmenu.c:76
static void fsmenu_free_category(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:1026
void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
Definition: fsmenu.c:213
void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon)
Definition: fsmenu.c:285
struct FSMenuEntry * ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:86
static FSMenu * fsmenu_copy(FSMenu *fsmenu)
Definition: fsmenu.c:1098
void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry)
Definition: fsmenu.c:344
void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
Definition: fsmenu.c:263
static void fsmenu_xdg_user_dirs_free(GHash *xdg_map)
Definition: fsmenu.c:179
static void fsmenu_bookmark_validate_job_stop(wmWindowManager *wm)
Definition: fsmenu.c:1210
void fsmenu_free(void)
Definition: fsmenu.c:1068
void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
Definition: fsmenu.c:641
void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
Definition: fsmenu.c:532
static GHash * fsmenu_xdg_user_dirs_parse(const char *home)
Definition: fsmenu.c:120
int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:234
static void fsmenu_xdg_insert_entry(GHash *xdg_map, struct FSMenu *fsmenu, const char *key, const char *default_path, int icon, const char *home)
Definition: fsmenu.c:194
char * ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry)
Definition: fsmenu.c:307
void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
Definition: fsmenu.c:569
#define FS_UDIR_PATH(dir, icon)
static void fsmenu_bookmark_validate_job_end(void *fsmenuv)
Definition: fsmenu.c:1178
int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry)
Definition: fsmenu.c:280
void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name)
Definition: fsmenu.c:321
FSMenuEntry * ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
Definition: fsmenu.c:246
#define FSMENU_RECENT_MAX
Definition: fsmenu.h:27
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
struct FSMenuEntry * next
char name[256]
Definition: fsmenu.c:68
FSMenuEntry * fsmenu_bookmarks
Definition: fsmenu.c:71
FSMenuEntry * fsmenu_other
Definition: fsmenu.c:73
FSMenuEntry * fsmenu_system_bookmarks
Definition: fsmenu.c:70
FSMenuEntry * fsmenu_recent
Definition: fsmenu.c:72
FSMenuEntry * fsmenu_system
Definition: fsmenu.c:69
const char * relname
Definition: wm_jobs.c:73
struct wmWindow * winactive
#define SEP_STR
Definition: unit.c:47
uint len
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition: wm_jobs.c:450
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:196
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:372
void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type)
Definition: wm_jobs.c:572
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:344
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:360