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