Blender  V2.93
filelist.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) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 /* global includes */
25 
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <time.h>
31 
32 #ifndef WIN32
33 # include <unistd.h>
34 #else
35 # include <direct.h>
36 # include <io.h>
37 #endif
38 #include "MEM_guardedalloc.h"
39 
40 #include "BLI_blenlib.h"
41 #include "BLI_fileops.h"
42 #include "BLI_fileops_types.h"
43 #include "BLI_fnmatch.h"
44 #include "BLI_ghash.h"
45 #include "BLI_linklist.h"
46 #include "BLI_math.h"
47 #include "BLI_stack.h"
48 #include "BLI_task.h"
49 #include "BLI_threads.h"
50 #include "BLI_utildefines.h"
51 
52 #ifdef WIN32
53 # include "BLI_winstuff.h"
54 #endif
55 
56 #include "BKE_asset.h"
57 #include "BKE_context.h"
58 #include "BKE_global.h"
59 #include "BKE_icons.h"
60 #include "BKE_idtype.h"
61 #include "BKE_lib_id.h"
62 #include "BKE_main.h"
63 #include "BKE_main_idmap.h"
64 #include "BKE_preferences.h"
65 #include "BLO_readfile.h"
66 
67 #include "DNA_asset_types.h"
68 #include "DNA_space_types.h"
69 
70 #include "ED_datafiles.h"
71 #include "ED_fileselect.h"
72 #include "ED_screen.h"
73 
74 #include "IMB_imbuf.h"
75 #include "IMB_imbuf_types.h"
76 #include "IMB_thumbs.h"
77 
78 #include "PIL_time.h"
79 
80 #include "WM_api.h"
81 #include "WM_types.h"
82 
83 #include "UI_interface_icons.h"
84 #include "UI_resources.h"
85 
86 #include "atomic_ops.h"
87 
88 #include "filelist.h"
89 
90 #define FILEDIR_NBR_ENTRIES_UNSET -1
91 
92 /* ----------------- FOLDERLIST (previous/next) -------------- */
93 
94 typedef struct FolderList {
95  struct FolderList *next, *prev;
96  char *foldername;
98 
99 void folderlist_popdir(struct ListBase *folderlist, char *dir)
100 {
101  const char *prev_dir;
102  struct FolderList *folder;
103  folder = folderlist->last;
104 
105  if (folder) {
106  /* remove the current directory */
107  MEM_freeN(folder->foldername);
108  BLI_freelinkN(folderlist, folder);
109 
110  folder = folderlist->last;
111  if (folder) {
112  prev_dir = folder->foldername;
113  BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
114  }
115  }
116  /* delete the folder next or use setdir directly before PREVIOUS OP */
117 }
118 
119 void folderlist_pushdir(ListBase *folderlist, const char *dir)
120 {
121  if (!dir[0]) {
122  return;
123  }
124 
125  struct FolderList *folder, *previous_folder;
126  previous_folder = folderlist->last;
127 
128  /* check if already exists */
129  if (previous_folder && previous_folder->foldername) {
130  if (BLI_path_cmp(previous_folder->foldername, dir) == 0) {
131  return;
132  }
133  }
134 
135  /* create next folder element */
136  folder = MEM_mallocN(sizeof(*folder), __func__);
137  folder->foldername = BLI_strdup(dir);
138 
139  /* add it to the end of the list */
140  BLI_addtail(folderlist, folder);
141 }
142 
143 const char *folderlist_peeklastdir(ListBase *folderlist)
144 {
145  struct FolderList *folder;
146 
147  if (!folderlist->last) {
148  return NULL;
149  }
150 
151  folder = folderlist->last;
152  return folder->foldername;
153 }
154 
156 {
158  struct FolderList *folder;
159 
160  /* if there is no folder_next there is nothing we can clear */
161  if (BLI_listbase_is_empty(sfile->folders_next)) {
162  return 0;
163  }
164 
165  /* if previous_folder, next_folder or refresh_folder operators are executed
166  * it doesn't clear folder_next */
167  folder = sfile->folders_prev->last;
168  if ((!folder) || (BLI_path_cmp(folder->foldername, params->dir) == 0)) {
169  return 0;
170  }
171 
172  /* eventually clear flist->folders_next */
173  return 1;
174 }
175 
176 /* not listbase itself */
177 void folderlist_free(ListBase *folderlist)
178 {
179  if (folderlist) {
180  FolderList *folder;
181  for (folder = folderlist->first; folder; folder = folder->next) {
182  MEM_freeN(folder->foldername);
183  }
184  BLI_freelistN(folderlist);
185  }
186 }
187 
189 {
190  ListBase folderlistn = {NULL};
191 
192  BLI_duplicatelist(&folderlistn, folderlist);
193 
194  for (FolderList *folder = folderlistn.first; folder; folder = folder->next) {
195  folder->foldername = MEM_dupallocN(folder->foldername);
196  }
197  return folderlistn;
198 }
199 
200 /* ----------------- Folder-History (wraps/owns file list above) -------------- */
201 
203 {
204  LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) {
205  if (history->browse_mode == browse_mode) {
206  return history;
207  }
208  }
209 
210  return NULL;
211 }
212 
214 {
215  FileFolderHistory *history = folder_history_find(sfile, sfile->browse_mode);
216 
217  if (!history) {
218  history = MEM_callocN(sizeof(*history), __func__);
219  history->browse_mode = sfile->browse_mode;
220  BLI_addtail(&sfile->folder_histories, history);
221  }
222 
223  sfile->folders_next = &history->folders_next;
224  sfile->folders_prev = &history->folders_prev;
225 }
226 
228 {
229  if (sfile->folders_prev == &history->folders_prev) {
230  sfile->folders_prev = NULL;
231  }
232  if (sfile->folders_next == &history->folders_next) {
233  sfile->folders_next = NULL;
234  }
235  folderlist_free(&history->folders_prev);
236  folderlist_free(&history->folders_next);
237  BLI_freelinkN(&sfile->folder_histories, history);
238 }
239 
241 {
243  folder_history_entry_free(sfile, history);
244  }
245 }
246 
248 {
249  ListBase histories = {NULL};
250 
251  LISTBASE_FOREACH (FileFolderHistory *, history, listbase) {
252  FileFolderHistory *history_new = MEM_dupallocN(history);
253  history_new->folders_prev = folderlist_duplicate(&history->folders_prev);
254  history_new->folders_next = folderlist_duplicate(&history->folders_next);
255  BLI_addtail(&histories, history_new);
256  }
257 
258  return histories;
259 }
260 
261 /* ------------------FILELIST------------------------ */
262 
263 typedef struct FileListInternEntry {
265 
267  char uuid[16];
268 
270  int typeflag;
272  int blentype;
273 
274  char *relpath;
278  char *name;
279  bool free_name;
280 
286  struct {
288  ID *id;
289 
290  /* For the few file types that have the preview already in memory. For others, there's delayed
291  * preview reading from disk. Non-owning pointer. */
294 
298 
303 
304 typedef struct FileListIntern {
308 
309  char curr_uuid[16]; /* Used to generate uuid during internal listing. */
311 
312 #define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */
313 typedef struct FileListEntryCache {
314  size_t size; /* The size of the cache... */
315 
316  int flags;
317 
318  /* This one gathers all entries from both block and misc caches. Used for easy bulk-freing. */
320 
321  /* Block cache: all entries between start and end index.
322  * used for part of the list on display. */
325 
326  /* Misc cache: random indices, FIFO behavior.
327  * Note: Not 100% sure we actually need that, time will say. */
331 
332  /* Allows to quickly get a cached entry from its UUID. */
334 
335  /* Previews handling. */
339 
340 /* FileListCache.flags */
341 enum {
342  FLC_IS_INIT = 1 << 0,
344 };
345 
346 typedef struct FileListEntryPreview {
347  char path[FILE_MAX];
349  int index;
350  /* Some file types load the memory from runtime data, not from disk. We just wait until it's done
351  * generating (BKE_previewimg_is_finished()). */
353 
354  int icon_id;
356 
357 /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing
358  * tasks' data (see T74609). */
362 
363 typedef struct FileListFilter {
367  char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
368  short flags;
370 
371 /* FileListFilter.flags */
372 enum {
373  FLF_DO_FILTER = 1 << 0,
374  FLF_HIDE_DOT = 1 << 1,
375  FLF_HIDE_PARENT = 1 << 2,
377  FLF_ASSETS_ONLY = 1 << 4,
378 };
379 
380 typedef struct FileList {
382 
384  /* The library this list was created for. Stored here so we know when to re-read. */
386 
387  short flags;
388 
389  short sort;
390 
392 
394 
396 
397  /* We need to keep those info outside of actual filelist items,
398  * because those are no more persistent
399  * (only generated on demand, and freed as soon as possible).
400  * Persistent part (mere list of paths + stat info)
401  * is kept as small as possible, and filebrowser-agnostic.
402  */
404 
407 
409 
410  /* Set given path as root directory,
411  * if last bool is true may change given string in place to a valid value.
412  * Returns True if valid dir. */
413  bool (*check_dir_fn)(struct FileList *, char *, const bool);
414 
415  /* Fill filelist (to be called by read job). */
416  void (*read_job_fn)(
417  Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
418 
419  /* Filter an entry of current filelist. */
420  bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *);
421 
422  short tags; /* FileListTags */
424 
425 /* FileList.flags */
426 enum {
427  FL_FORCE_RESET = 1 << 0,
428  FL_IS_READY = 1 << 1,
429  FL_IS_PENDING = 1 << 2,
430  FL_NEED_SORTING = 1 << 3,
432  FL_SORT_INVERT = 1 << 5,
433 };
434 
435 /* FileList.tags */
441 };
442 
443 #define SPECIAL_IMG_SIZE 256
444 #define SPECIAL_IMG_ROWS 1
445 #define SPECIAL_IMG_COLS 7
446 
447 enum {
456 };
457 
459 
460 static void filelist_readjob_main(Main *current_main,
461  FileList *filelist,
462  const char *main_name,
463  short *stop,
464  short *do_update,
465  float *progress,
466  ThreadMutex *lock);
467 static void filelist_readjob_lib(Main *current_main,
468  FileList *filelist,
469  const char *main_name,
470  short *stop,
471  short *do_update,
472  float *progress,
473  ThreadMutex *lock);
474 static void filelist_readjob_dir(Main *current_main,
475  FileList *filelist,
476  const char *main_name,
477  short *stop,
478  short *do_update,
479  float *progress,
480  ThreadMutex *lock);
481 static void filelist_readjob_main_assets(Main *current_main,
482  FileList *filelist,
483  const char *main_name,
484  short *stop,
485  short *do_update,
486  float *progress,
487  ThreadMutex *lock);
488 
489 /* helper, could probably go in BKE actually? */
490 static int groupname_to_code(const char *group);
491 static uint64_t groupname_to_filter_id(const char *group);
492 
493 static void filelist_filter_clear(FileList *filelist);
494 static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
495 
496 /* ********** Sort helpers ********** */
497 
498 struct FileSortData {
499  bool inverted;
500 };
501 
502 static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
503 {
504  return sort_data->inverted ? -val : val;
505 }
506 
512  const FileListInternEntry *entry2)
513 {
514  /* type is equal to stat.st_mode */
515 
516  if (entry1->typeflag & FILE_TYPE_DIR) {
517  if (entry2->typeflag & FILE_TYPE_DIR) {
518  /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs,
519  * then libs (.blend files), then categories in libs. */
520  if (entry1->typeflag & FILE_TYPE_BLENDERLIB) {
521  if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
522  return 1;
523  }
524  }
525  else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) {
526  return -1;
527  }
528  else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
529  if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
530  return 1;
531  }
532  }
533  else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
534  return -1;
535  }
536  }
537  else {
538  return -1;
539  }
540  }
541  else if (entry2->typeflag & FILE_TYPE_DIR) {
542  return 1;
543  }
544 
545  /* make sure "." and ".." are always first */
546  if (FILENAME_IS_CURRENT(entry1->relpath)) {
547  return -1;
548  }
549  if (FILENAME_IS_CURRENT(entry2->relpath)) {
550  return 1;
551  }
552  if (FILENAME_IS_PARENT(entry1->relpath)) {
553  return -1;
554  }
555  if (FILENAME_IS_PARENT(entry2->relpath)) {
556  return 1;
557  }
558 
559  return 0;
560 }
561 
562 static int compare_name(void *user_data, const void *a1, const void *a2)
563 {
564  const FileListInternEntry *entry1 = a1;
565  const FileListInternEntry *entry2 = a2;
566  const struct FileSortData *sort_data = user_data;
567  char *name1, *name2;
568  int ret;
569 
570  if ((ret = compare_direntry_generic(entry1, entry2))) {
571  return ret;
572  }
573 
574  name1 = entry1->name;
575  name2 = entry2->name;
576 
577  return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
578 }
579 
580 static int compare_date(void *user_data, const void *a1, const void *a2)
581 {
582  const FileListInternEntry *entry1 = a1;
583  const FileListInternEntry *entry2 = a2;
584  const struct FileSortData *sort_data = user_data;
585  char *name1, *name2;
586  int64_t time1, time2;
587  int ret;
588 
589  if ((ret = compare_direntry_generic(entry1, entry2))) {
590  return ret;
591  }
592 
593  time1 = (int64_t)entry1->st.st_mtime;
594  time2 = (int64_t)entry2->st.st_mtime;
595  if (time1 < time2) {
596  return compare_apply_inverted(1, sort_data);
597  }
598  if (time1 > time2) {
599  return compare_apply_inverted(-1, sort_data);
600  }
601 
602  name1 = entry1->name;
603  name2 = entry2->name;
604 
605  return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
606 }
607 
608 static int compare_size(void *user_data, const void *a1, const void *a2)
609 {
610  const FileListInternEntry *entry1 = a1;
611  const FileListInternEntry *entry2 = a2;
612  const struct FileSortData *sort_data = user_data;
613  char *name1, *name2;
614  uint64_t size1, size2;
615  int ret;
616 
617  if ((ret = compare_direntry_generic(entry1, entry2))) {
618  return ret;
619  }
620 
621  size1 = entry1->st.st_size;
622  size2 = entry2->st.st_size;
623  if (size1 < size2) {
624  return compare_apply_inverted(1, sort_data);
625  }
626  if (size1 > size2) {
627  return compare_apply_inverted(-1, sort_data);
628  }
629 
630  name1 = entry1->name;
631  name2 = entry2->name;
632 
633  return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
634 }
635 
636 static int compare_extension(void *user_data, const void *a1, const void *a2)
637 {
638  const FileListInternEntry *entry1 = a1;
639  const FileListInternEntry *entry2 = a2;
640  const struct FileSortData *sort_data = user_data;
641  char *name1, *name2;
642  int ret;
643 
644  if ((ret = compare_direntry_generic(entry1, entry2))) {
645  return ret;
646  }
647 
648  if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
649  return -1;
650  }
651  if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
652  return 1;
653  }
654  if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
655  if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) {
656  return 1;
657  }
658  if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) {
659  return -1;
660  }
661  if (entry1->blentype < entry2->blentype) {
662  return compare_apply_inverted(-1, sort_data);
663  }
664  if (entry1->blentype > entry2->blentype) {
665  return compare_apply_inverted(1, sort_data);
666  }
667  }
668  else {
669  const char *sufix1, *sufix2;
670 
671  if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) {
672  sufix1 = strrchr(entry1->relpath, '.');
673  }
674  if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) {
675  sufix2 = strrchr(entry2->relpath, '.');
676  }
677  if (!sufix1) {
678  sufix1 = "";
679  }
680  if (!sufix2) {
681  sufix2 = "";
682  }
683 
684  if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
685  return compare_apply_inverted(ret, sort_data);
686  }
687  }
688 
689  name1 = entry1->name;
690  name2 = entry2->name;
691 
692  return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data);
693 }
694 
695 void filelist_sort(struct FileList *filelist)
696 {
697  if (filelist->flags & FL_NEED_SORTING) {
698  void *sort_cb = NULL;
699 
700  switch (filelist->sort) {
701  case FILE_SORT_ALPHA:
702  sort_cb = compare_name;
703  break;
704  case FILE_SORT_TIME:
705  sort_cb = compare_date;
706  break;
707  case FILE_SORT_SIZE:
708  sort_cb = compare_size;
709  break;
710  case FILE_SORT_EXTENSION:
711  sort_cb = compare_extension;
712  break;
713  case FILE_SORT_DEFAULT:
714  default:
715  BLI_assert(0);
716  break;
717  }
719  &filelist->filelist_intern.entries,
720  sort_cb,
721  &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0});
722 
723  filelist_filter_clear(filelist);
724  filelist->flags &= ~FL_NEED_SORTING;
725  }
726 }
727 
728 void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
729 {
730  const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
731 
732  if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
733  filelist->sort = sort;
734  filelist->flags |= FL_NEED_SORTING;
735  filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
736  (filelist->flags & ~FL_SORT_INVERT);
737  }
738 }
739 
740 /* ********** Filter helpers ********** */
741 
742 /* True if filename is meant to be hidden, eg. starting with period. */
743 static bool is_hidden_dot_filename(const char *filename, const FileListInternEntry *file)
744 {
745  if (filename[0] == '.' && !ELEM(filename[1], '.', '\0')) {
746  return true; /* ignore .file */
747  }
748 
749  int len = strlen(filename);
750  if ((len > 0) && (filename[len - 1] == '~')) {
751  return true; /* ignore file~ */
752  }
753 
754  /* filename might actually be a piece of path, in which case we have to check all its parts. */
755 
756  bool hidden = false;
757  char *sep = (char *)BLI_path_slash_rfind(filename);
758 
759  if (!hidden && sep) {
760  char tmp_filename[FILE_MAX_LIBEXTRA];
761 
762  BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename));
763  sep = tmp_filename + (sep - filename);
764  while (sep) {
765  /* This happens when a path contains 'ALTSEP', '\' on Unix for e.g.
766  * Supporting alternate slashes in paths is a bigger task involving changes
767  * in many parts of the code, for now just prevent an assert, see T74579. */
768 #if 0
769  BLI_assert(sep[1] != '\0');
770 #endif
771  if (is_hidden_dot_filename(sep + 1, file)) {
772  hidden = true;
773  break;
774  }
775  *sep = '\0';
776  sep = (char *)BLI_path_slash_rfind(tmp_filename);
777  }
778  }
779  return hidden;
780 }
781 
782 /* True if should be hidden, based on current filtering. */
783 static bool is_filtered_hidden(const char *filename,
784  const FileListFilter *filter,
785  const FileListInternEntry *file)
786 {
787  if ((filename[0] == '.') && (filename[1] == '\0')) {
788  return true; /* Ignore . */
789  }
790 
791  if (filter->flags & FLF_HIDE_PARENT) {
792  if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
793  return true; /* Ignore .. */
794  }
795  }
796 
797  if ((filter->flags & FLF_HIDE_DOT) && (file->attributes & FILE_ATTR_HIDDEN)) {
798  return true; /* Ignore files with Hidden attribute. */
799  }
800 
801 #ifndef WIN32
802  /* Check for unix-style names starting with period. */
803  if ((filter->flags & FLF_HIDE_DOT) && is_hidden_dot_filename(filename, file)) {
804  return true;
805  }
806 #endif
807  /* For data-blocks (but not the group directories), check the asset-only filter. */
808  if (!(file->typeflag & FILE_TYPE_DIR) && (file->typeflag & FILE_TYPE_BLENDERLIB) &&
809  (filter->flags & FLF_ASSETS_ONLY) && !(file->typeflag & FILE_TYPE_ASSET)) {
810  return true;
811  }
812 
813  return false;
814 }
815 
817  const char *UNUSED(root),
819 {
820  bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
821 
822  if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
823  /* We only check for types if some type are enabled in filtering. */
824  if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
825  if (file->typeflag & FILE_TYPE_DIR) {
826  if (file->typeflag &
828  if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
829  is_filtered = false;
830  }
831  }
832  else {
833  if (!(filter->filter & FILE_TYPE_FOLDER)) {
834  is_filtered = false;
835  }
836  }
837  }
838  else {
839  if (!(file->typeflag & filter->filter)) {
840  is_filtered = false;
841  }
842  }
843  }
844  /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
845  if (is_filtered && (filter->filter_search[0] != '\0')) {
846  if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
847  is_filtered = false;
848  }
849  }
850  }
851 
852  return is_filtered;
853 }
854 
856  const char *id_group,
857  const char *name,
858  const FileListFilter *filter)
859 {
860  bool is_filtered = !is_filtered_hidden(file->relpath, filter, file);
861  if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) {
862  /* We only check for types if some type are enabled in filtering. */
863  if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
864  if (file->typeflag & FILE_TYPE_DIR) {
865  if (file->typeflag &
867  if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
868  is_filtered = false;
869  }
870  }
871  else {
872  if (!(filter->filter & FILE_TYPE_FOLDER)) {
873  is_filtered = false;
874  }
875  }
876  }
877  if (is_filtered && id_group) {
878  if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
879  is_filtered = false;
880  }
881  else {
882  uint64_t filter_id = groupname_to_filter_id(id_group);
883  if (!(filter_id & filter->filter_id)) {
884  is_filtered = false;
885  }
886  }
887  }
888  }
889  /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
890  if (is_filtered && (filter->filter_search[0] != '\0')) {
891  if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) {
892  is_filtered = false;
893  }
894  }
895  }
896 
897  return is_filtered;
898 }
899 
901 {
902  bool is_filtered;
903  char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
904 
905  BLI_join_dirfile(path, sizeof(path), root, file->relpath);
906 
907  if (BLO_library_path_explode(path, dir, &group, &name)) {
908  is_filtered = is_filtered_id_file(file, group, name, filter);
909  }
910  else {
911  is_filtered = is_filtered_file(file, root, filter);
912  }
913 
914  return is_filtered;
915 }
916 
918  const char *UNUSED(dir),
920 {
921  return !is_filtered_hidden(file->relpath, filter, file);
922 }
923 
925  const char *UNUSED(dir),
927 {
928  /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
929  return is_filtered_id_file(file, file->relpath, file->name, filter);
930 }
931 
932 static void filelist_filter_clear(FileList *filelist)
933 {
934  filelist->flags |= FL_NEED_FILTERING;
935 }
936 
937 void filelist_filter(FileList *filelist)
938 {
939  int num_filtered = 0;
940  const int num_files = filelist->filelist.nbr_entries;
941  FileListInternEntry **filtered_tmp, *file;
942 
943  if (ELEM(filelist->filelist.nbr_entries, FILEDIR_NBR_ENTRIES_UNSET, 0)) {
944  return;
945  }
946 
947  if (!(filelist->flags & FL_NEED_FILTERING)) {
948  /* Assume it has already been filtered, nothing else to do! */
949  return;
950  }
951 
952  filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR;
953  if (filelist->max_recursion) {
954  /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
955  * root path is a blend file. */
956  char dir[FILE_MAX_LIBEXTRA];
957  if (!filelist_islibrary(filelist, dir, NULL)) {
958  filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
959  }
960  }
961 
962  filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__);
963 
964  /* Filter remap & count how many files are left after filter in a single loop. */
965  for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
966  if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) {
967  filtered_tmp[num_filtered++] = file;
968  }
969  }
970 
971  if (filelist->filelist_intern.filtered) {
973  }
975  sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, __func__);
976  memcpy(filelist->filelist_intern.filtered,
977  filtered_tmp,
978  sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered);
979  filelist->filelist.nbr_entries_filtered = num_filtered;
980  // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries);
981 
983  filelist->flags &= ~FL_NEED_FILTERING;
984 
985  MEM_freeN(filtered_tmp);
986 }
987 
989  const bool do_filter,
990  const bool hide_dot,
991  const bool hide_parent,
992  const uint64_t filter,
993  const uint64_t filter_id,
994  const bool filter_assets_only,
995  const char *filter_glob,
996  const char *filter_search)
997 {
998  bool update = false;
999 
1000  if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) {
1001  filelist->filter_data.flags ^= FLF_DO_FILTER;
1002  update = true;
1003  }
1004  if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) {
1005  filelist->filter_data.flags ^= FLF_HIDE_DOT;
1006  update = true;
1007  }
1008  if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) {
1009  filelist->filter_data.flags ^= FLF_HIDE_PARENT;
1010  update = true;
1011  }
1012  if (((filelist->filter_data.flags & FLF_ASSETS_ONLY) != 0) != (filter_assets_only != 0)) {
1013  filelist->filter_data.flags ^= FLF_ASSETS_ONLY;
1014  update = true;
1015  }
1016  if (filelist->filter_data.filter != filter) {
1017  filelist->filter_data.filter = filter;
1018  update = true;
1019  }
1020  const uint64_t new_filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL;
1021  if (filelist->filter_data.filter_id != new_filter_id) {
1022  filelist->filter_data.filter_id = new_filter_id;
1023  update = true;
1024  }
1025  if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) {
1026  BLI_strncpy(
1027  filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob));
1028  update = true;
1029  }
1030  if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) {
1032  filter_search,
1033  '*',
1034  sizeof(filelist->filter_data.filter_search));
1035  update = true;
1036  }
1037 
1038  if (update) {
1039  /* And now, free filtered data so that we know we have to filter again. */
1040  filelist_filter_clear(filelist);
1041  }
1042 }
1043 
1049  const FileSelectAssetLibraryUID *library_b)
1050 {
1051  if (library_a->type != library_b->type) {
1052  return false;
1053  }
1054  if (library_a->type == FILE_ASSET_LIBRARY_CUSTOM) {
1055  /* Don't only check the index, also check that it's valid. */
1057  &U, library_a->custom_library_index);
1058  return (library_ptr_a != NULL) &&
1059  (library_a->custom_library_index == library_b->custom_library_index);
1060  }
1061 
1062  return true;
1063 }
1064 
1068 void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library)
1069 {
1070  /* Unset if needed. */
1071  if (!asset_library) {
1072  if (filelist->asset_library) {
1073  MEM_SAFE_FREE(filelist->asset_library);
1074  filelist->flags |= FL_FORCE_RESET;
1075  }
1076  return;
1077  }
1078 
1079  if (!filelist->asset_library) {
1080  filelist->asset_library = MEM_mallocN(sizeof(*filelist->asset_library),
1081  "filelist asset library");
1082  *filelist->asset_library = *asset_library;
1083 
1084  filelist->flags |= FL_FORCE_RESET;
1085  }
1086  else if (!filelist_compare_asset_libraries(filelist->asset_library, asset_library)) {
1087  *filelist->asset_library = *asset_library;
1088  filelist->flags |= FL_FORCE_RESET;
1089  }
1090 }
1091 
1092 /* ********** Icon/image helpers ********** */
1093 
1095 {
1096  short x, y, k;
1097  ImBuf *bbuf;
1098  ImBuf *ibuf;
1099 
1100  BLI_assert(G.background == false);
1101 
1102 #ifdef WITH_HEADLESS
1103  bbuf = NULL;
1104 #else
1105  bbuf = IMB_ibImageFromMemory(
1107 #endif
1108  if (bbuf) {
1109  for (y = 0; y < SPECIAL_IMG_ROWS; y++) {
1110  for (x = 0; x < SPECIAL_IMG_COLS; x++) {
1111  int tile = SPECIAL_IMG_COLS * y + x;
1112  if (tile < SPECIAL_IMG_MAX) {
1114  for (k = 0; k < SPECIAL_IMG_SIZE; k++) {
1115  memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE],
1117  x * SPECIAL_IMG_SIZE],
1118  SPECIAL_IMG_SIZE * sizeof(int));
1119  }
1120  gSpecialFileImages[tile] = ibuf;
1121  }
1122  }
1123  }
1124  IMB_freeImBuf(bbuf);
1125  }
1126 }
1127 
1129 {
1130  BLI_assert(G.background == false);
1131 
1132  for (int i = 0; i < SPECIAL_IMG_MAX; i++) {
1134  gSpecialFileImages[i] = NULL;
1135  }
1136 }
1137 
1138 static FileDirEntry *filelist_geticon_get_file(struct FileList *filelist, const int index)
1139 {
1140  BLI_assert(G.background == false);
1141 
1142  return filelist_file(filelist, index);
1143 }
1144 
1145 ImBuf *filelist_getimage(struct FileList *filelist, const int index)
1146 {
1147  FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1148 
1149  return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
1150 }
1151 
1153 {
1154  return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
1155 }
1156 
1158 {
1159  ImBuf *ibuf = NULL;
1160 
1161  if (file->typeflag & FILE_TYPE_DIR) {
1162  if (FILENAME_IS_PARENT(file->relpath)) {
1164  }
1165  else {
1167  }
1168  }
1169  else {
1171  }
1172 
1173  return ibuf;
1174 }
1175 
1176 ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
1177 {
1178  FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1180 }
1181 
1183  const char *root,
1184  const bool is_main,
1185  const bool ignore_libdir)
1186 {
1187  const eFileSel_File_Types typeflag = file->typeflag;
1188 
1189  if ((typeflag & FILE_TYPE_DIR) &&
1190  !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) {
1191  if (FILENAME_IS_PARENT(file->relpath)) {
1192  return is_main ? ICON_FILE_PARENT : ICON_NONE;
1193  }
1194  if (typeflag & FILE_TYPE_APPLICATIONBUNDLE) {
1195  return ICON_UGLYPACKAGE;
1196  }
1197  if (typeflag & FILE_TYPE_BLENDER) {
1198  return ICON_FILE_BLEND;
1199  }
1200  if (is_main) {
1201  /* Do not return icon for folders if icons are not 'main' draw type
1202  * (e.g. when used over previews). */
1203  return (file->attributes & FILE_ATTR_ANY_LINK) ? ICON_FOLDER_REDIRECT : ICON_FILE_FOLDER;
1204  }
1205 
1206  /* If this path is in System list or path cache then use that icon. */
1207  struct FSMenu *fsmenu = ED_fsmenu_get();
1208  FSMenuCategory categories[] = {
1212  };
1213 
1214  for (int i = 0; i < ARRAY_SIZE(categories); i++) {
1215  FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]);
1216  char fullpath[FILE_MAX_LIBEXTRA];
1217  char *target = fullpath;
1218  if (file->redirection_path) {
1219  target = file->redirection_path;
1220  }
1221  else if (root) {
1222  BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
1223  BLI_path_slash_ensure(fullpath);
1224  }
1225  for (; tfsm; tfsm = tfsm->next) {
1226  if (STREQ(tfsm->path, target)) {
1227  /* Never want a little folder inside a large one. */
1228  return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
1229  }
1230  }
1231  }
1232 
1233  if (file->attributes & FILE_ATTR_OFFLINE) {
1234  return ICON_ERROR;
1235  }
1236  if (file->attributes & FILE_ATTR_TEMPORARY) {
1237  return ICON_FILE_CACHE;
1238  }
1239  if (file->attributes & FILE_ATTR_SYSTEM) {
1240  return ICON_SYSTEM;
1241  }
1242  }
1243 
1244  if (typeflag & FILE_TYPE_BLENDER) {
1245  return ICON_FILE_BLEND;
1246  }
1247  if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
1248  return ICON_FILE_BACKUP;
1249  }
1250  if (typeflag & FILE_TYPE_IMAGE) {
1251  return ICON_FILE_IMAGE;
1252  }
1253  if (typeflag & FILE_TYPE_MOVIE) {
1254  return ICON_FILE_MOVIE;
1255  }
1256  if (typeflag & FILE_TYPE_PYSCRIPT) {
1257  return ICON_FILE_SCRIPT;
1258  }
1259  if (typeflag & FILE_TYPE_SOUND) {
1260  return ICON_FILE_SOUND;
1261  }
1262  if (typeflag & FILE_TYPE_FTFONT) {
1263  return ICON_FILE_FONT;
1264  }
1265  if (typeflag & FILE_TYPE_BTX) {
1266  return ICON_FILE_BLANK;
1267  }
1268  if (typeflag & FILE_TYPE_COLLADA) {
1269  return ICON_FILE_3D;
1270  }
1271  if (typeflag & FILE_TYPE_ALEMBIC) {
1272  return ICON_FILE_3D;
1273  }
1274  if (typeflag & FILE_TYPE_USD) {
1275  return ICON_FILE_3D;
1276  }
1277  if (typeflag & FILE_TYPE_VOLUME) {
1278  return ICON_FILE_VOLUME;
1279  }
1280  if (typeflag & FILE_TYPE_OBJECT_IO) {
1281  return ICON_FILE_3D;
1282  }
1283  if (typeflag & FILE_TYPE_TEXT) {
1284  return ICON_FILE_TEXT;
1285  }
1286  if (typeflag & FILE_TYPE_ARCHIVE) {
1287  return ICON_FILE_ARCHIVE;
1288  }
1289  if (typeflag & FILE_TYPE_BLENDERLIB) {
1290  const int ret = UI_icon_from_idcode(file->blentype);
1291  if (ret != ICON_NONE) {
1292  return ret;
1293  }
1294  }
1295  return is_main ? ICON_FILE_BLANK : ICON_NONE;
1296 }
1297 
1298 int filelist_geticon(struct FileList *filelist, const int index, const bool is_main)
1299 {
1300  FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1301 
1302  return filelist_geticon_ex(file, filelist->filelist.root, is_main, false);
1303 }
1304 
1306 {
1307  return file->preview_icon_id ? file->preview_icon_id :
1308  filelist_geticon_ex(file, NULL, false, false);
1309 }
1310 
1311 /* ********** Main ********** */
1312 
1314 {
1316 #ifdef WIN32
1318 #else
1319  strcpy(dir, "/");
1320 #endif
1321  }
1322 }
1323 
1324 static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist),
1325  char *r_dir,
1326  const bool do_change)
1327 {
1328  if (do_change) {
1330  return true;
1331  }
1332  return BLI_is_dir(r_dir);
1333 }
1334 
1335 static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist),
1336  char *r_dir,
1337  const bool do_change)
1338 {
1339  char tdir[FILE_MAX_LIBEXTRA];
1340  char *name;
1341 
1342  const bool is_valid = (BLI_is_dir(r_dir) ||
1343  (BLO_library_path_explode(r_dir, tdir, NULL, &name) &&
1344  BLI_is_file(tdir) && !name));
1345 
1346  if (do_change && !is_valid) {
1347  /* if not a valid library, we need it to be a valid directory! */
1349  return true;
1350  }
1351  return is_valid;
1352 }
1353 
1354 static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
1355 {
1356  /* TODO */
1357  return filelist_checkdir_lib(filelist, r_dir, do_change);
1358 }
1359 
1360 static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist),
1361  char *UNUSED(r_dir),
1362  const bool UNUSED(do_change))
1363 {
1364  /* Main is always valid. */
1365  return true;
1366 }
1367 
1369 {
1370  if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) {
1371  MEM_freeN(entry->name);
1372  }
1373  if (entry->description) {
1374  MEM_freeN(entry->description);
1375  }
1376  if (entry->relpath) {
1377  MEM_freeN(entry->relpath);
1378  }
1379  if (entry->redirection_path) {
1380  MEM_freeN(entry->redirection_path);
1381  }
1382  if (entry->preview_icon_id) {
1384  entry->preview_icon_id = 0;
1385  }
1386  /* For now, consider FileDirEntryRevision::poin as not owned here,
1387  * so no need to do anything about it */
1388 
1389  if (!BLI_listbase_is_empty(&entry->variants)) {
1390  FileDirEntryVariant *var;
1391 
1392  for (var = entry->variants.first; var; var = var->next) {
1393  if (var->name) {
1394  MEM_freeN(var->name);
1395  }
1396  if (var->description) {
1397  MEM_freeN(var->description);
1398  }
1399 
1400  if (!BLI_listbase_is_empty(&var->revisions)) {
1401  FileDirEntryRevision *rev;
1402 
1403  for (rev = var->revisions.first; rev; rev = rev->next) {
1404  if (rev->comment) {
1405  MEM_freeN(rev->comment);
1406  }
1407  }
1408 
1409  BLI_freelistN(&var->revisions);
1410  }
1411  }
1412 
1413  /* TODO: tags! */
1414 
1415  BLI_freelistN(&entry->variants);
1416  }
1417  else if (entry->entry) {
1418  MEM_freeN(entry->entry);
1419  }
1420 }
1421 
1423 {
1424  filelist_entry_clear(entry);
1425  MEM_freeN(entry);
1426 }
1427 
1429 {
1430 #if 0
1431  FileDirEntry *entry, *entry_next;
1432 
1433  for (entry = array->entries.first; entry; entry = entry_next) {
1434  entry_next = entry->next;
1435  filelist_entry_free(entry);
1436  }
1437  BLI_listbase_clear(&array->entries);
1438 #else
1440 #endif
1441  array->nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
1442  array->nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET;
1443  array->entry_idx_start = -1;
1444  array->entry_idx_end = -1;
1445 }
1446 
1448 {
1449  if (entry->relpath) {
1450  MEM_freeN(entry->relpath);
1451  }
1452  if (entry->redirection_path) {
1453  MEM_freeN(entry->redirection_path);
1454  }
1455  if (entry->name && entry->free_name) {
1456  MEM_freeN(entry->name);
1457  }
1458  /* If we own the asset-data (it was generated from external file data), free it. */
1459  if (entry->imported_asset_data) {
1461  }
1462  MEM_freeN(entry);
1463 }
1464 
1465 static void filelist_intern_free(FileListIntern *filelist_intern)
1466 {
1467  FileListInternEntry *entry, *entry_next;
1468 
1469  for (entry = filelist_intern->entries.first; entry; entry = entry_next) {
1470  entry_next = entry->next;
1472  }
1473  BLI_listbase_clear(&filelist_intern->entries);
1474 
1475  MEM_SAFE_FREE(filelist_intern->filtered);
1476 }
1477 
1478 static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
1479 {
1481  FileListEntryPreviewTaskData *preview_taskdata = taskdata;
1482  FileListEntryPreview *preview = preview_taskdata->preview;
1483 
1484  ThumbSource source = 0;
1485  bool done = false;
1486 
1487  // printf("%s: Start (%d)...\n", __func__, threadid);
1488 
1489  if (preview->in_memory_preview) {
1492  preview->icon_id = BKE_icon_imbuf_create(imbuf);
1493  done = true;
1494  }
1495  }
1496  else {
1497  // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
1498  BLI_assert(preview->flags &
1501 
1502  if (preview->flags & FILE_TYPE_IMAGE) {
1503  source = THB_SOURCE_IMAGE;
1504  }
1505  else if (preview->flags &
1507  source = THB_SOURCE_BLEND;
1508  }
1509  else if (preview->flags & FILE_TYPE_MOVIE) {
1510  source = THB_SOURCE_MOVIE;
1511  }
1512  else if (preview->flags & FILE_TYPE_FTFONT) {
1513  source = THB_SOURCE_FONT;
1514  }
1515 
1516  IMB_thumb_path_lock(preview->path);
1517  /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
1518  * in case user switch to a bigger preview size. */
1519  ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source);
1520  IMB_thumb_path_unlock(preview->path);
1521  if (imbuf) {
1522  preview->icon_id = BKE_icon_imbuf_create(imbuf);
1523  }
1524 
1525  done = true;
1526  }
1527 
1528  if (done) {
1529  /* That way task freeing function won't free th preview, since it does not own it anymore. */
1530  atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL);
1531  BLI_thread_queue_push(cache->previews_done, preview);
1532  }
1533 
1534  // printf("%s: End (%d)...\n", __func__, threadid);
1535 }
1536 
1537 static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
1538 {
1539  FileListEntryPreviewTaskData *preview_taskdata = taskdata;
1540  FileListEntryPreview *preview = preview_taskdata->preview;
1541 
1542  /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent
1543  * to previews_done queue. */
1544  if (preview != NULL) {
1545  if (preview->icon_id) {
1546  BKE_icon_delete(preview->icon_id);
1547  }
1548  MEM_freeN(preview);
1549  }
1550  MEM_freeN(preview_taskdata);
1551 }
1552 
1554 {
1555  if (!cache->previews_pool) {
1558 
1560  }
1561 }
1562 
1564 {
1565  if (cache->previews_pool) {
1567 
1568  FileListEntryPreview *preview;
1569  while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
1570  // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
1571  // preview->img);
1572  if (preview->icon_id) {
1573  BKE_icon_delete(preview->icon_id);
1574  }
1575  MEM_freeN(preview);
1576  }
1577  }
1578 }
1579 
1581 {
1582  if (cache->previews_pool) {
1584 
1586 
1589  cache->previews_pool = NULL;
1590  cache->previews_done = NULL;
1591 
1593  }
1594 
1595  cache->flags &= ~FLC_PREVIEWS_ACTIVE;
1596 }
1597 
1598 static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
1599 {
1600  FileListEntryCache *cache = &filelist->filelist_cache;
1601 
1603 
1604  if (!entry->preview_icon_id && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) &&
1607  FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
1608  FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
1609 
1610  if (entry->redirection_path) {
1611  BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
1612  }
1613  else {
1615  preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
1616  }
1617 
1618  preview->index = index;
1619  preview->flags = entry->typeflag;
1620  preview->in_memory_preview = intern_entry->local_data.preview_image;
1621  preview->icon_id = 0;
1622  // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
1623 
1625 
1626  FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
1627  __func__);
1628  preview_taskdata->preview = preview;
1631  preview_taskdata,
1632  true,
1634  }
1635 }
1636 
1637 static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
1638 {
1640 
1641  cache->block_cursor = cache->block_start_index = cache->block_center_index =
1642  cache->block_end_index = 0;
1643  cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__);
1644 
1645  cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size);
1646  cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size,
1647  __func__);
1648  copy_vn_i(cache->misc_entries_indices, cache_size, -1);
1649  cache->misc_cursor = 0;
1650 
1651  /* XXX This assumes uint is 32 bits and uuid is 128 bits (char[16]), be careful! */
1652  cache->uuids = BLI_ghash_new_ex(
1653  BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__, cache_size * 2);
1654 
1655  cache->size = cache_size;
1656  cache->flags = FLC_IS_INIT;
1657 
1658  /* We cannot translate from non-main thread, so init translated strings once from here. */
1660 }
1661 
1663 {
1664  FileDirEntry *entry, *entry_next;
1665 
1666  if (!(cache->flags & FLC_IS_INIT)) {
1667  return;
1668  }
1669 
1671 
1672  MEM_freeN(cache->block_entries);
1673 
1676 
1677  BLI_ghash_free(cache->uuids, NULL, NULL);
1678 
1679  for (entry = cache->cached_entries.first; entry; entry = entry_next) {
1680  entry_next = entry->next;
1681  filelist_entry_free(entry);
1682  }
1684 }
1685 
1686 static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
1687 {
1688  FileDirEntry *entry, *entry_next;
1689 
1690  if (!(cache->flags & FLC_IS_INIT)) {
1691  return;
1692  }
1693 
1695 
1696  cache->block_cursor = cache->block_start_index = cache->block_center_index =
1697  cache->block_end_index = 0;
1698  if (new_size != cache->size) {
1699  cache->block_entries = MEM_reallocN(cache->block_entries,
1700  sizeof(*cache->block_entries) * new_size);
1701  }
1702 
1703  BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size);
1704  if (new_size != cache->size) {
1706  sizeof(*cache->misc_entries_indices) * new_size);
1707  }
1708  copy_vn_i(cache->misc_entries_indices, new_size, -1);
1709 
1710  BLI_ghash_clear_ex(cache->uuids, NULL, NULL, new_size * 2);
1711 
1712  cache->size = new_size;
1713 
1714  for (entry = cache->cached_entries.first; entry; entry = entry_next) {
1715  entry_next = entry->next;
1716  filelist_entry_free(entry);
1717  }
1719 }
1720 
1722 {
1723  FileList *p = MEM_callocN(sizeof(*p), __func__);
1724 
1726 
1730  filelist_settype(p, type);
1731 
1732  return p;
1733 }
1734 
1735 void filelist_settype(FileList *filelist, short type)
1736 {
1737  if (filelist->type == type) {
1738  return;
1739  }
1740 
1741  filelist->type = type;
1742  filelist->tags = 0;
1743  switch (filelist->type) {
1744  case FILE_MAIN:
1746  filelist->read_job_fn = filelist_readjob_main;
1747  filelist->filter_fn = is_filtered_main;
1748  break;
1749  case FILE_LOADLIB:
1750  filelist->check_dir_fn = filelist_checkdir_lib;
1751  filelist->read_job_fn = filelist_readjob_lib;
1752  filelist->filter_fn = is_filtered_lib;
1753  break;
1754  case FILE_MAIN_ASSET:
1757  filelist->filter_fn = is_filtered_main_assets;
1759  break;
1760  default:
1761  filelist->check_dir_fn = filelist_checkdir_dir;
1762  filelist->read_job_fn = filelist_readjob_dir;
1763  filelist->filter_fn = is_filtered_file;
1764  break;
1765  }
1766 
1767  filelist->flags |= FL_FORCE_RESET;
1768 }
1769 
1770 void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection)
1771 {
1772  if (!filelist) {
1773  return;
1774  }
1775 
1776  filelist_filter_clear(filelist);
1777 
1778  if (do_cache) {
1779  filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
1780  }
1781 
1783 
1784  filelist_direntryarr_free(&filelist->filelist);
1785 
1786  if (do_selection && filelist->selection_state) {
1788  }
1789 }
1790 
1791 void filelist_clear(struct FileList *filelist)
1792 {
1793  filelist_clear_ex(filelist, true, true);
1794 }
1795 
1796 void filelist_free(struct FileList *filelist)
1797 {
1798  if (!filelist) {
1799  printf("Attempting to delete empty filelist.\n");
1800  return;
1801  }
1802 
1803  /* No need to clear cache & selection_state, we free them anyway. */
1804  filelist_clear_ex(filelist, false, false);
1805  filelist_cache_free(&filelist->filelist_cache);
1806 
1807  if (filelist->selection_state) {
1809  filelist->selection_state = NULL;
1810  }
1811 
1812  MEM_SAFE_FREE(filelist->asset_library);
1813 
1814  memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
1815 
1816  filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
1817 }
1818 
1819 void filelist_freelib(struct FileList *filelist)
1820 {
1821  if (filelist->libfiledata) {
1823  }
1824  filelist->libfiledata = NULL;
1825 }
1826 
1828 {
1829  return filelist->libfiledata;
1830 }
1831 
1832 static const char *fileentry_uiname(const char *root,
1833  const char *relpath,
1834  const eFileSel_File_Types typeflag,
1835  char *buff)
1836 {
1837  char *name = NULL;
1838 
1839  if (typeflag & FILE_TYPE_BLENDERLIB) {
1840  char abspath[FILE_MAX_LIBEXTRA];
1841  char *group;
1842 
1843  BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
1844  BLO_library_path_explode(abspath, buff, &group, &name);
1845  if (!name) {
1846  name = group;
1847  }
1848  }
1849  /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */
1850  if (!name) {
1851  if (typeflag & FILE_TYPE_DIR) {
1852  name = (char *)relpath;
1853  }
1854  else {
1855  name = (char *)BLI_path_basename(relpath);
1856  }
1857  }
1858  BLI_assert(name);
1859 
1860  return name;
1861 }
1862 
1863 const char *filelist_dir(struct FileList *filelist)
1864 {
1865  return filelist->filelist.root;
1866 }
1867 
1868 bool filelist_is_dir(struct FileList *filelist, const char *path)
1869 {
1870  return filelist->check_dir_fn(filelist, (char *)path, false);
1871 }
1872 
1876 void filelist_setdir(struct FileList *filelist, char *r_dir)
1877 {
1878  const bool allow_invalid = filelist->asset_library != NULL;
1879  BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
1880 
1882  const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid);
1883  BLI_assert(is_valid_path || allow_invalid);
1884  UNUSED_VARS_NDEBUG(is_valid_path);
1885 
1886  if (!STREQ(filelist->filelist.root, r_dir)) {
1887  BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
1888  filelist->flags |= FL_FORCE_RESET;
1889  }
1890 }
1891 
1892 void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
1893 {
1894  if (filelist->max_recursion != recursion_level) {
1895  filelist->max_recursion = recursion_level;
1896  filelist->flags |= FL_FORCE_RESET;
1897  }
1898 }
1899 
1901 {
1902  return (filelist->flags & FL_FORCE_RESET) != 0;
1903 }
1904 
1906 {
1907  filelist->flags |= FL_FORCE_RESET;
1908 }
1909 
1910 bool filelist_is_ready(struct FileList *filelist)
1911 {
1912  return (filelist->flags & FL_IS_READY) != 0;
1913 }
1914 
1915 bool filelist_pending(struct FileList *filelist)
1916 {
1917  return (filelist->flags & FL_IS_PENDING) != 0;
1918 }
1919 
1921 {
1922  return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
1923 }
1924 
1932 {
1933  if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
1934  filelist_sort(filelist);
1935  filelist_filter(filelist);
1936  }
1937 
1938  return filelist->filelist.nbr_entries_filtered;
1939 }
1940 
1941 static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
1942 {
1943  FileListInternEntry *entry = filelist->filelist_intern.filtered[index];
1944  FileListEntryCache *cache = &filelist->filelist_cache;
1945  FileDirEntry *ret;
1946  FileDirEntryRevision *rev;
1947 
1948  ret = MEM_callocN(sizeof(*ret), __func__);
1949  rev = MEM_callocN(sizeof(*rev), __func__);
1950 
1951  rev->size = (uint64_t)entry->st.st_size;
1952 
1953  rev->time = (int64_t)entry->st.st_mtime;
1954 
1955  ret->entry = rev;
1956  ret->relpath = BLI_strdup(entry->relpath);
1957  if (entry->free_name) {
1958  ret->name = BLI_strdup(entry->name);
1959  ret->flags |= FILE_ENTRY_NAME_FREE;
1960  }
1961  else {
1962  ret->name = entry->name;
1963  }
1964  ret->description = BLI_strdupcat(filelist->filelist.root, entry->relpath);
1965  memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid));
1966  ret->blentype = entry->blentype;
1967  ret->typeflag = entry->typeflag;
1968  ret->attributes = entry->attributes;
1969  if (entry->redirection_path) {
1970  ret->redirection_path = BLI_strdup(entry->redirection_path);
1971  }
1972  ret->id = entry->local_data.id;
1973  ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : NULL;
1974  if (ret->id && (ret->asset_data == NULL)) {
1975  ret->asset_data = ret->id->asset_data;
1976  }
1977  /* For some file types the preview is already available. */
1978  if (entry->local_data.preview_image &&
1981  ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
1982  }
1983  BLI_addtail(&cache->cached_entries, ret);
1984  return ret;
1985 }
1986 
1987 static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
1988 {
1989  BLI_remlink(&filelist->filelist_cache.cached_entries, entry);
1990  filelist_entry_free(entry);
1991 }
1992 
1993 FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
1994 {
1995  FileDirEntry *ret = NULL, *old;
1996  FileListEntryCache *cache = &filelist->filelist_cache;
1997  const size_t cache_size = cache->size;
1998  int old_index;
1999 
2000  if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) {
2001  return ret;
2002  }
2003 
2004  if (index >= cache->block_start_index && index < cache->block_end_index) {
2005  const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size;
2006  return cache->block_entries[idx];
2007  }
2008 
2009  if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) {
2010  return ret;
2011  }
2012 
2013  if (!use_request) {
2014  return NULL;
2015  }
2016 
2017  // printf("requesting file %d (not yet cached)\n", index);
2018 
2019  /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */
2020  ret = filelist_file_create_entry(filelist, index);
2021  old_index = cache->misc_entries_indices[cache->misc_cursor];
2022  if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) {
2023  BLI_ghash_remove(cache->uuids, old->uuid, NULL, NULL);
2024  filelist_file_release_entry(filelist, old);
2025  }
2027  BLI_ghash_insert(cache->uuids, ret->uuid, ret);
2028 
2029  cache->misc_entries_indices[cache->misc_cursor] = index;
2030  cache->misc_cursor = (cache->misc_cursor + 1) % cache_size;
2031 
2032 #if 0 /* Actually no, only block cached entries should have preview imho. */
2033  if (cache->previews_pool) {
2034  filelist_cache_previews_push(filelist, ret, index);
2035  }
2036 #endif
2037 
2038  return ret;
2039 }
2040 
2041 FileDirEntry *filelist_file(struct FileList *filelist, int index)
2042 {
2043  return filelist_file_ex(filelist, index, true);
2044 }
2045 
2046 int filelist_file_findpath(struct FileList *filelist, const char *filename)
2047 {
2048  int fidx = -1;
2049 
2051  return fidx;
2052  }
2053 
2054  /* XXX TODO Cache could probably use a ghash on paths too? Not really urgent though.
2055  * This is only used to find again renamed entry,
2056  * annoying but looks hairy to get rid of it currently. */
2057 
2058  for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
2059  FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
2060  if (STREQ(entry->relpath, filename)) {
2061  return fidx;
2062  }
2063  }
2064 
2065  return -1;
2066 }
2067 
2072 {
2073  return file->id;
2074 }
2075 
2076 FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4])
2077 {
2079  return NULL;
2080  }
2081 
2082  if (filelist->filelist_cache.uuids) {
2083  FileDirEntry *entry = BLI_ghash_lookup(filelist->filelist_cache.uuids, uuid);
2084  if (entry) {
2085  return entry;
2086  }
2087  }
2088 
2089  {
2090  int fidx;
2091 
2092  for (fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
2093  FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
2094  if (memcmp(entry->uuid, uuid, sizeof(entry->uuid)) == 0) {
2095  return filelist_file(filelist, fidx);
2096  }
2097  }
2098  }
2099 
2100  return NULL;
2101 }
2102 
2103 void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
2104 {
2105  /* Always keep it power of 2, in [256, 8192] range for now,
2106  * cache being app. twice bigger than requested window. */
2107  size_t size = 256;
2108  window_size *= 2;
2109 
2110  while (size < window_size && size < 8192) {
2111  size *= 2;
2112  }
2113 
2114  if (size != filelist->filelist_cache.size) {
2116  }
2117 }
2118 
2119 /* Helpers, low-level, they assume cursor + size <= cache_size */
2121  const int start_index,
2122  const int size,
2123  int cursor)
2124 {
2125  FileListEntryCache *cache = &filelist->filelist_cache;
2126 
2127  {
2128  int i, idx;
2129 
2130  for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) {
2131  FileDirEntry *entry;
2132 
2133  /* That entry might have already been requested and stored in misc cache... */
2134  if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) {
2135  entry = filelist_file_create_entry(filelist, idx);
2136  BLI_ghash_insert(cache->uuids, entry->uuid, entry);
2137  }
2138  cache->block_entries[cursor] = entry;
2139  }
2140  return true;
2141  }
2142 
2143  return false;
2144 }
2145 
2146 static void filelist_file_cache_block_release(struct FileList *filelist,
2147  const int size,
2148  int cursor)
2149 {
2150  FileListEntryCache *cache = &filelist->filelist_cache;
2151 
2152  {
2153  int i;
2154 
2155  for (i = 0; i < size; i++, cursor++) {
2156  FileDirEntry *entry = cache->block_entries[cursor];
2157 #if 0
2158  printf("%s: release cacheidx %d (%%p %%s)\n",
2159  __func__,
2160  cursor /*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/);
2161 #endif
2162  BLI_ghash_remove(cache->uuids, entry->uuid, NULL, NULL);
2163  filelist_file_release_entry(filelist, entry);
2164 #ifndef NDEBUG
2165  cache->block_entries[cursor] = NULL;
2166 #endif
2167  }
2168  }
2169 }
2170 
2171 /* Load in cache all entries "around" given index (as much as block cache may hold). */
2172 bool filelist_file_cache_block(struct FileList *filelist, const int index)
2173 {
2174  FileListEntryCache *cache = &filelist->filelist_cache;
2175  const size_t cache_size = cache->size;
2176 
2177  const int nbr_entries = filelist->filelist.nbr_entries_filtered;
2178  int start_index = max_ii(0, index - (cache_size / 2));
2179  int end_index = min_ii(nbr_entries, index + (cache_size / 2));
2180  int i;
2181  const bool full_refresh = (filelist->flags & FL_IS_READY) == 0;
2182 
2183  if ((index < 0) || (index >= nbr_entries)) {
2184  // printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries);
2185  return false;
2186  }
2187 
2188  /* Maximize cached range! */
2189  if ((end_index - start_index) < cache_size) {
2190  if (start_index == 0) {
2191  end_index = min_ii(nbr_entries, start_index + cache_size);
2192  }
2193  else if (end_index == nbr_entries) {
2194  start_index = max_ii(0, end_index - cache_size);
2195  }
2196  }
2197 
2198  BLI_assert((end_index - start_index) <= cache_size);
2199 
2200  // printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__,
2201  // start_index, end_index, index, cache->block_start_index, cache->block_end_index);
2202 
2203  /* If we have something to (re)cache... */
2204  if (full_refresh || (start_index != cache->block_start_index) ||
2205  (end_index != cache->block_end_index)) {
2206  if (full_refresh || (start_index >= cache->block_end_index) ||
2207  (end_index <= cache->block_start_index)) {
2208  int size1 = cache->block_end_index - cache->block_start_index;
2209  int size2 = 0;
2210  int idx1 = cache->block_cursor, idx2 = 0;
2211 
2212  // printf("Full Recaching!\n");
2213 
2214  if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2216  }
2217 
2218  if (idx1 + size1 > cache_size) {
2219  size2 = idx1 + size1 - cache_size;
2220  size1 -= size2;
2221  filelist_file_cache_block_release(filelist, size2, idx2);
2222  }
2223  filelist_file_cache_block_release(filelist, size1, idx1);
2224 
2225  cache->block_start_index = cache->block_end_index = cache->block_cursor = 0;
2226 
2227  /* New cached block does not overlap existing one, simple. */
2228  if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) {
2229  return false;
2230  }
2231 
2232  cache->block_start_index = start_index;
2233  cache->block_end_index = end_index;
2234  }
2235  else {
2236  // printf("Partial Recaching!\n");
2237 
2238  /* At this point, we know we keep part of currently cached entries, so update previews
2239  * if needed, and remove everything from working queue - we'll add all newly needed
2240  * entries at the end. */
2241  if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2244  }
2245 
2246  // printf("\tpreview cleaned up...\n");
2247 
2248  if (start_index > cache->block_start_index) {
2249  int size1 = start_index - cache->block_start_index;
2250  int size2 = 0;
2251  int idx1 = cache->block_cursor, idx2 = 0;
2252 
2253  // printf("\tcache releasing: [%d:%d] (%d, %d)\n",
2254  // cache->block_start_index, cache->block_start_index + size1,
2255  // cache->block_cursor, size1);
2256 
2257  if (idx1 + size1 > cache_size) {
2258  size2 = idx1 + size1 - cache_size;
2259  size1 -= size2;
2260  filelist_file_cache_block_release(filelist, size2, idx2);
2261  }
2262  filelist_file_cache_block_release(filelist, size1, idx1);
2263 
2264  cache->block_cursor = (idx1 + size1 + size2) % cache_size;
2265  cache->block_start_index = start_index;
2266  }
2267  if (end_index < cache->block_end_index) {
2268  int size1 = cache->block_end_index - end_index;
2269  int size2 = 0;
2270  int idx1, idx2 = 0;
2271 
2272 #if 0
2273  printf("\tcache releasing: [%d:%d] (%d)\n",
2274  cache->block_end_index - size1,
2275  cache->block_end_index,
2276  cache->block_cursor);
2277 #endif
2278 
2279  idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size;
2280  if (idx1 + size1 > cache_size) {
2281  size2 = idx1 + size1 - cache_size;
2282  size1 -= size2;
2283  filelist_file_cache_block_release(filelist, size2, idx2);
2284  }
2285  filelist_file_cache_block_release(filelist, size1, idx1);
2286 
2287  cache->block_end_index = end_index;
2288  }
2289 
2290  // printf("\tcache cleaned up...\n");
2291 
2292  if (start_index < cache->block_start_index) {
2293  /* Add (request) needed entries before already cached ones. */
2294  /* Note: We need some index black magic to wrap around (cycle)
2295  * inside our cache_size array... */
2296  int size1 = cache->block_start_index - start_index;
2297  int size2 = 0;
2298  int idx1, idx2;
2299 
2300  if (size1 > cache->block_cursor) {
2301  size2 = size1;
2302  size1 -= cache->block_cursor;
2303  size2 -= size1;
2304  idx2 = 0;
2305  idx1 = cache_size - size1;
2306  }
2307  else {
2308  idx1 = cache->block_cursor - size1;
2309  }
2310 
2311  if (size2) {
2312  if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) {
2313  return false;
2314  }
2315  }
2316  if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) {
2317  return false;
2318  }
2319 
2320  cache->block_cursor = idx1;
2321  cache->block_start_index = start_index;
2322  }
2323  // printf("\tstart-extended...\n");
2324  if (end_index > cache->block_end_index) {
2325  /* Add (request) needed entries after already cached ones. */
2326  /* Note: We need some index black magic to wrap around (cycle)
2327  * inside our cache_size array... */
2328  int size1 = end_index - cache->block_end_index;
2329  int size2 = 0;
2330  int idx1, idx2;
2331 
2332  idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size;
2333  if ((idx1 + size1) > cache_size) {
2334  size2 = size1;
2335  size1 = cache_size - idx1;
2336  size2 -= size1;
2337  idx2 = 0;
2338  }
2339 
2340  if (size2) {
2341  if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) {
2342  return false;
2343  }
2344  }
2345  if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) {
2346  return false;
2347  }
2348 
2349  cache->block_end_index = end_index;
2350  }
2351 
2352  // printf("\tend-extended...\n");
2353  }
2354  }
2355  else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) {
2356  /* We try to always preview visible entries first, so 'restart' preview background task. */
2359  }
2360 
2361  // printf("Re-queueing previews...\n");
2362 
2363  /* Note we try to preview first images around given index - i.e. assumed visible ones. */
2364  if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2365  for (i = 0; ((index + i) < end_index) || ((index - i) >= start_index); i++) {
2366  if ((index - i) >= start_index) {
2367  const int idx = (cache->block_cursor + (index - start_index) - i) % cache_size;
2368  filelist_cache_previews_push(filelist, cache->block_entries[idx], index - i);
2369  }
2370  if ((index + i) < end_index) {
2371  const int idx = (cache->block_cursor + (index - start_index) + i) % cache_size;
2372  filelist_cache_previews_push(filelist, cache->block_entries[idx], index + i);
2373  }
2374  }
2375  }
2376 
2377  cache->block_center_index = index;
2378 
2379  // printf("%s Finished!\n", __func__);
2380 
2381  return true;
2382 }
2383 
2384 void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
2385 {
2386  FileListEntryCache *cache = &filelist->filelist_cache;
2387 
2388  if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) {
2389  return;
2390  }
2391  /* Do not start preview work while listing, gives nasty flickering! */
2392  if (use_previews && (filelist->flags & FL_IS_READY)) {
2393  cache->flags |= FLC_PREVIEWS_ACTIVE;
2394 
2395  BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL));
2396 
2397  // printf("%s: Init Previews...\n", __func__);
2398 
2399  /* No need to populate preview queue here, filelist_file_cache_block() handles this. */
2400  }
2401  else {
2402  // printf("%s: Clear Previews...\n", __func__);
2403 
2405  }
2406 }
2407 
2409 {
2410  FileListEntryCache *cache = &filelist->filelist_cache;
2411  TaskPool *pool = cache->previews_pool;
2412  bool changed = false;
2413 
2414  if (!pool) {
2415  return changed;
2416  }
2417 
2418  // printf("%s: Update Previews...\n", __func__);
2419 
2420  while (!BLI_thread_queue_is_empty(cache->previews_done)) {
2422  FileDirEntry *entry;
2423 
2424  /* Paranoid (should never happen currently
2425  * since we consume this queue from a single thread), but... */
2426  if (!preview) {
2427  continue;
2428  }
2429  /* entry might have been removed from cache in the mean time,
2430  * we do not want to cache it again here. */
2431  entry = filelist_file_ex(filelist, preview->index, false);
2432 
2433  // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
2434 
2435  if (preview->icon_id) {
2436  /* Due to asynchronous process, a preview for a given image may be generated several times,
2437  * i.e. entry->image may already be set at this point. */
2438  if (entry && !entry->preview_icon_id) {
2439  /* Move ownership over icon. */
2440  entry->preview_icon_id = preview->icon_id;
2441  preview->icon_id = 0;
2442  changed = true;
2443  }
2444  else {
2445  BKE_icon_delete(preview->icon_id);
2446  }
2447  }
2448  else if (entry) {
2449  /* We want to avoid re-processing this entry continuously!
2450  * Note that, since entries only live in cache,
2451  * preview will be retried quite often anyway. */
2453  }
2454 
2455  MEM_freeN(preview);
2456  }
2457 
2458  return changed;
2459 }
2460 
2462 {
2463  FileListEntryCache *cache = &filelist->filelist_cache;
2464 
2465  return (cache->previews_pool != NULL);
2466 }
2467 
2468 /* would recognize .blend as well */
2469 static bool file_is_blend_backup(const char *str)
2470 {
2471  const size_t a = strlen(str);
2472  size_t b = 7;
2473  bool retval = 0;
2474 
2475  if (a == 0 || b >= a) {
2476  /* pass */
2477  }
2478  else {
2479  const char *loc;
2480 
2481  if (a > b + 1) {
2482  b++;
2483  }
2484 
2485  /* allow .blend1 .blend2 .blend32 */
2486  loc = BLI_strcasestr(str + a - b, ".blend");
2487 
2488  if (loc) {
2489  retval = 1;
2490  }
2491  }
2492 
2493  return retval;
2494 }
2495 
2496 /* TODO: Maybe we should move this to BLI?
2497  * On the other hand, it's using defines from space-file area, so not sure... */
2498 int ED_path_extension_type(const char *path)
2499 {
2500  if (BLO_has_bfile_extension(path)) {
2501  return FILE_TYPE_BLENDER;
2502  }
2503  if (file_is_blend_backup(path)) {
2504  return FILE_TYPE_BLENDER_BACKUP;
2505  }
2506  if (BLI_path_extension_check(path, ".app")) {
2508  }
2509  if (BLI_path_extension_check(path, ".py")) {
2510  return FILE_TYPE_PYSCRIPT;
2511  }
2512  if (BLI_path_extension_check_n(path,
2513  ".txt",
2514  ".glsl",
2515  ".osl",
2516  ".data",
2517  ".pov",
2518  ".ini",
2519  ".mcr",
2520  ".inc",
2521  ".fountain",
2522  NULL)) {
2523  return FILE_TYPE_TEXT;
2524  }
2525  if (BLI_path_extension_check_n(path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", NULL)) {
2526  return FILE_TYPE_FTFONT;
2527  }
2528  if (BLI_path_extension_check(path, ".btx")) {
2529  return FILE_TYPE_BTX;
2530  }
2531  if (BLI_path_extension_check(path, ".dae")) {
2532  return FILE_TYPE_COLLADA;
2533  }
2534  if (BLI_path_extension_check(path, ".abc")) {
2535  return FILE_TYPE_ALEMBIC;
2536  }
2537  if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", NULL)) {
2538  return FILE_TYPE_USD;
2539  }
2540  if (BLI_path_extension_check(path, ".vdb")) {
2541  return FILE_TYPE_VOLUME;
2542  }
2543  if (BLI_path_extension_check(path, ".zip")) {
2544  return FILE_TYPE_ARCHIVE;
2545  }
2546  if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) {
2547  return FILE_TYPE_OBJECT_IO;
2548  }
2550  return FILE_TYPE_IMAGE;
2551  }
2552  if (BLI_path_extension_check(path, ".ogg")) {
2553  if (IMB_isanim(path)) {
2554  return FILE_TYPE_MOVIE;
2555  }
2556  return FILE_TYPE_SOUND;
2557  }
2559  return FILE_TYPE_MOVIE;
2560  }
2562  return FILE_TYPE_SOUND;
2563  }
2564  return 0;
2565 }
2566 
2567 int ED_file_extension_icon(const char *path)
2568 {
2569  const int type = ED_path_extension_type(path);
2570 
2571  switch (type) {
2572  case FILE_TYPE_BLENDER:
2573  return ICON_FILE_BLEND;
2575  return ICON_FILE_BACKUP;
2576  case FILE_TYPE_IMAGE:
2577  return ICON_FILE_IMAGE;
2578  case FILE_TYPE_MOVIE:
2579  return ICON_FILE_MOVIE;
2580  case FILE_TYPE_PYSCRIPT:
2581  return ICON_FILE_SCRIPT;
2582  case FILE_TYPE_SOUND:
2583  return ICON_FILE_SOUND;
2584  case FILE_TYPE_FTFONT:
2585  return ICON_FILE_FONT;
2586  case FILE_TYPE_BTX:
2587  return ICON_FILE_BLANK;
2588  case FILE_TYPE_COLLADA:
2589  case FILE_TYPE_ALEMBIC:
2590  case FILE_TYPE_OBJECT_IO:
2591  return ICON_FILE_3D;
2592  case FILE_TYPE_TEXT:
2593  return ICON_FILE_TEXT;
2594  case FILE_TYPE_ARCHIVE:
2595  return ICON_FILE_ARCHIVE;
2596  case FILE_TYPE_VOLUME:
2597  return ICON_FILE_VOLUME;
2598  default:
2599  return ICON_FILE_BLANK;
2600  }
2601 }
2602 
2603 int filelist_needs_reading(struct FileList *filelist)
2604 {
2605  return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET);
2606 }
2607 
2609  const FileDirEntry *entry,
2611  uint flag,
2612  FileCheckType check)
2613 {
2614  /* Default NULL pointer if not found is fine here! */
2615  void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid);
2616  uint entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0;
2617  const uint org_entry_flag = entry_flag;
2618 
2619  BLI_assert(entry);
2621 
2622  if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
2623  ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) {
2624  switch (select) {
2625  case FILE_SEL_REMOVE:
2626  entry_flag &= ~flag;
2627  break;
2628  case FILE_SEL_ADD:
2629  entry_flag |= flag;
2630  break;
2631  case FILE_SEL_TOGGLE:
2632  entry_flag ^= flag;
2633  break;
2634  }
2635  }
2636 
2637  if (entry_flag != org_entry_flag) {
2638  if (es_p) {
2639  if (entry_flag) {
2640  *es_p = POINTER_FROM_UINT(entry_flag);
2641  }
2642  else {
2643  BLI_ghash_remove(filelist->selection_state, entry->uuid, MEM_freeN, NULL);
2644  }
2645  }
2646  else if (entry_flag) {
2647  void *key = MEM_mallocN(sizeof(entry->uuid), __func__);
2648  memcpy(key, entry->uuid, sizeof(entry->uuid));
2649  BLI_ghash_insert(filelist->selection_state, key, POINTER_FROM_UINT(entry_flag));
2650  }
2651  }
2652 
2653  return entry_flag;
2654 }
2655 
2657  FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
2658 {
2659  FileDirEntry *entry = filelist_file(filelist, index);
2660 
2661  if (entry) {
2662  filelist_entry_select_set(filelist, entry, select, flag, check);
2663  }
2664 }
2665 
2667  FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
2668 {
2669  /* select all valid files between first and last indicated */
2670  if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) &&
2671  (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered)) {
2672  int current_file;
2673  for (current_file = sel->first; current_file <= sel->last; current_file++) {
2674  filelist_entry_select_index_set(filelist, current_file, select, flag, check);
2675  }
2676  }
2677 }
2678 
2680 {
2681  BLI_assert(entry);
2683 
2684  if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
2685  ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) {
2686  /* Default NULL pointer if not found is fine here! */
2687  return POINTER_AS_UINT(BLI_ghash_lookup(filelist->selection_state, entry->uuid));
2688  }
2689 
2690  return 0;
2691 }
2692 
2694 {
2695  FileDirEntry *entry = filelist_file(filelist, index);
2696 
2697  if (entry) {
2698  return filelist_entry_select_get(filelist, entry, check);
2699  }
2700 
2701  return 0;
2702 }
2703 
2704 bool filelist_entry_is_selected(FileList *filelist, const int index)
2705 {
2706  BLI_assert(index >= 0 && index < filelist->filelist.nbr_entries_filtered);
2707  FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
2708 
2709  /* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to
2710  * "not selected". */
2711  const uint selection_state = POINTER_AS_UINT(
2712  BLI_ghash_lookup(filelist->selection_state, intern_entry->uuid));
2713 
2714  return selection_state != 0;
2715 }
2716 
2722  uint flag,
2723  FileCheckType check)
2724 {
2725  if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
2726  filelist_entry_select_index_set(filelist, 0, select, flag, check);
2727  }
2728 }
2729 
2730 /* WARNING! dir must be FILE_MAX_LIBEXTRA long! */
2731 bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
2732 {
2733  return BLO_library_path_explode(filelist->filelist.root, dir, r_group, NULL);
2734 }
2735 
2736 static int groupname_to_code(const char *group)
2737 {
2738  char buf[BLO_GROUP_MAX];
2739  char *lslash;
2740 
2741  BLI_assert(group);
2742 
2743  BLI_strncpy(buf, group, sizeof(buf));
2744  lslash = (char *)BLI_path_slash_rfind(buf);
2745  if (lslash) {
2746  lslash[0] = '\0';
2747  }
2748 
2749  return buf[0] ? BKE_idtype_idcode_from_name(buf) : 0;
2750 }
2751 
2752 static uint64_t groupname_to_filter_id(const char *group)
2753 {
2754  int id_code = groupname_to_code(group);
2755 
2756  return BKE_idtype_idcode_to_idfilter(id_code);
2757 }
2758 
2764 typedef struct TodoDir {
2765  int level;
2766  char *dir;
2768 
2769 static int filelist_readjob_list_dir(const char *root,
2770  ListBase *entries,
2771  const char *filter_glob,
2772  const bool do_lib,
2773  const char *main_name,
2774  const bool skip_currpar)
2775 {
2776  struct direntry *files;
2777  int nbr_files, nbr_entries = 0;
2778  /* Full path of the item. */
2779  char full_path[FILE_MAX];
2780 
2781  nbr_files = BLI_filelist_dir_contents(root, &files);
2782  if (files) {
2783  int i = nbr_files;
2784  while (i--) {
2785  FileListInternEntry *entry;
2786 
2787  if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) {
2788  continue;
2789  }
2790 
2791  entry = MEM_callocN(sizeof(*entry), __func__);
2792  entry->relpath = MEM_dupallocN(files[i].relname);
2793  entry->st = files[i].s;
2794 
2795  BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
2796  char *target = full_path;
2797 
2798  /* Set initial file type and attributes. */
2799  entry->attributes = BLI_file_attributes(full_path);
2800  if (S_ISDIR(files[i].s.st_mode)
2801 #ifdef __APPLE__
2803 #endif
2804  ) {
2805  entry->typeflag = FILE_TYPE_DIR;
2806  }
2807 
2808  /* Is this a file that points to another file? */
2809  if (entry->attributes & FILE_ATTR_ALIAS) {
2810  entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__);
2811  if (BLI_file_alias_target(full_path, entry->redirection_path)) {
2812  if (BLI_is_dir(entry->redirection_path)) {
2813  entry->typeflag = FILE_TYPE_DIR;
2815  }
2816  else {
2818  }
2819  target = entry->redirection_path;
2820 #ifdef WIN32
2821  /* On Windows don't show ".lnk" extension for valid shortcuts. */
2823 #endif
2824  }
2825  else {
2826  MEM_freeN(entry->redirection_path);
2827  entry->redirection_path = NULL;
2828  entry->attributes |= FILE_ATTR_HIDDEN;
2829  }
2830  }
2831 
2832  if (!(entry->typeflag & FILE_TYPE_DIR)) {
2833  if (do_lib && BLO_has_bfile_extension(target)) {
2834  /* If we are considering .blend files as libs, promote them to directory status. */
2835  entry->typeflag = FILE_TYPE_BLENDER;
2836  /* prevent current file being used as acceptable dir */
2837  if (BLI_path_cmp(main_name, target) != 0) {
2838  entry->typeflag |= FILE_TYPE_DIR;
2839  }
2840  }
2841  else {
2842  entry->typeflag = ED_path_extension_type(target);
2843  if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) {
2844  entry->typeflag |= FILE_TYPE_OPERATOR;
2845  }
2846  }
2847  }
2848 
2849 #ifndef WIN32
2850  /* Set linux-style dot files hidden too. */
2851  if (is_hidden_dot_filename(entry->relpath, entry)) {
2852  entry->attributes |= FILE_ATTR_HIDDEN;
2853  }
2854 #endif
2855 
2856  BLI_addtail(entries, entry);
2857  nbr_entries++;
2858  }
2859  BLI_filelist_free(files, nbr_files);
2860  }
2861  return nbr_entries;
2862 }
2863 
2864 static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar)
2865 {
2866  FileListInternEntry *entry;
2867  LinkNode *ln, *names = NULL, *datablock_infos = NULL;
2868  int i, nitems, idcode = 0, nbr_entries = 0;
2869  char dir[FILE_MAX_LIBEXTRA], *group;
2870  bool ok;
2871 
2872  struct BlendHandle *libfiledata = NULL;
2873 
2874  /* name test */
2875  ok = BLO_library_path_explode(root, dir, &group, NULL);
2876  if (!ok) {
2877  return nbr_entries;
2878  }
2879 
2880  /* there we go */
2881  libfiledata = BLO_blendhandle_from_file(dir, NULL);
2882  if (libfiledata == NULL) {
2883  return nbr_entries;
2884  }
2885 
2886  /* memory for strings is passed into filelist[i].entry->relpath
2887  * and freed in filelist_entry_free. */
2888  if (group) {
2889  idcode = groupname_to_code(group);
2890  datablock_infos = BLO_blendhandle_get_datablock_info(libfiledata, idcode, &nitems);
2891  }
2892  else {
2894  nitems = BLI_linklist_count(names);
2895  }
2896 
2897  BLO_blendhandle_close(libfiledata);
2898 
2899  if (!skip_currpar) {
2900  entry = MEM_callocN(sizeof(*entry), __func__);
2903  BLI_addtail(entries, entry);
2904  nbr_entries++;
2905  }
2906 
2907  for (i = 0, ln = (datablock_infos ? datablock_infos : names); i < nitems; i++, ln = ln->next) {
2908  struct BLODataBlockInfo *info = datablock_infos ? ln->link : NULL;
2909  const char *blockname = info ? info->name : ln->link;
2910 
2911  entry = MEM_callocN(sizeof(*entry), __func__);
2912  entry->relpath = BLI_strdup(blockname);
2913  entry->typeflag |= FILE_TYPE_BLENDERLIB;
2914  if (info && info->asset_data) {
2915  entry->typeflag |= FILE_TYPE_ASSET;
2916  /* Moves ownership! */
2917  entry->imported_asset_data = info->asset_data;
2918  }
2919  if (!(group && idcode)) {
2920  entry->typeflag |= FILE_TYPE_DIR;
2921  entry->blentype = groupname_to_code(blockname);
2922  }
2923  else {
2924  entry->blentype = idcode;
2925  }
2926  BLI_addtail(entries, entry);
2927  nbr_entries++;
2928  }
2929 
2930  BLI_linklist_freeN(datablock_infos ? datablock_infos : names);
2931 
2932  return nbr_entries;
2933 }
2934 
2935 #if 0
2936 /* Kept for reference here, in case we want to add back that feature later.
2937  * We do not need it currently. */
2938 /* Code ***NOT*** updated for job stuff! */
2939 static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
2940 {
2941  ID *id;
2942  FileDirEntry *files, *firstlib = NULL;
2943  ListBase *lb;
2944  int a, fake, idcode, ok, totlib, totbl;
2945 
2946  // filelist->type = FILE_MAIN; /* XXX TODO: add modes to filebrowser */
2947 
2948  BLI_assert(filelist->filelist.entries == NULL);
2949 
2950  if (filelist->filelist.root[0] == '/') {
2951  filelist->filelist.root[0] = '\0';
2952  }
2953 
2954  if (filelist->filelist.root[0]) {
2955  idcode = groupname_to_code(filelist->filelist.root);
2956  if (idcode == 0) {
2957  filelist->filelist.root[0] = '\0';
2958  }
2959  }
2960 
2961  if (filelist->dir[0] == 0) {
2962  /* make directories */
2963 # ifdef WITH_FREESTYLE
2964  filelist->filelist.nbr_entries = 27;
2965 # else
2966  filelist->filelist.nbr_entries = 26;
2967 # endif
2968  filelist_resize(filelist, filelist->filelist.nbr_entries);
2969 
2970  for (a = 0; a < filelist->filelist.nbr_entries; a++) {
2971  filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR;
2972  }
2973 
2974  filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT);
2975  filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene");
2976  filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object");
2977  filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh");
2978  filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve");
2979  filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball");
2980  filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material");
2981  filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture");
2982  filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image");
2983  filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika");
2984  filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave");
2985  filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice");
2986  filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light");
2987  filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera");
2988  filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo");
2989  filelist->filelist.entries[15].entry->relpath = BLI_strdup("World");
2990  filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen");
2991  filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont");
2992  filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text");
2993  filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature");
2994  filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action");
2995  filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree");
2996  filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker");
2997  filelist->filelist.entries[23].entry->relpath = BLI_strdup("Hair");
2998  filelist->filelist.entries[24].entry->relpath = BLI_strdup("Point Cloud");
2999  filelist->filelist.entries[25].entry->relpath = BLI_strdup("Volume");
3000 # ifdef WITH_FREESTYLE
3001  filelist->filelist.entries[26].entry->relpath = BLI_strdup("FreestyleLineStyle");
3002 # endif
3003  }
3004  else {
3005  /* make files */
3006  idcode = groupname_to_code(filelist->filelist.root);
3007 
3008  lb = which_libbase(bmain, idcode);
3009  if (lb == NULL) {
3010  return;
3011  }
3012 
3013  filelist->filelist.nbr_entries = 0;
3014  for (id = lb->first; id; id = id->next) {
3015  if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
3016  filelist->filelist.nbr_entries++;
3017  }
3018  }
3019 
3020  /* XXX TODO: if data-browse or append/link #FLF_HIDE_PARENT has to be set. */
3021  if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
3022  filelist->filelist.nbr_entries++;
3023  }
3024 
3025  if (filelist->filelist.nbr_entries > 0) {
3026  filelist_resize(filelist, filelist->filelist.nbr_entries);
3027  }
3028 
3029  files = filelist->filelist.entries;
3030 
3031  if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
3032  files->entry->relpath = BLI_strdup(FILENAME_PARENT);
3033  files->typeflag |= FILE_TYPE_DIR;
3034 
3035  files++;
3036  }
3037 
3038  totlib = totbl = 0;
3039  for (id = lb->first; id; id = id->next) {
3040  ok = 1;
3041  if (ok) {
3042  if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
3043  if (id->lib == NULL) {
3044  files->entry->relpath = BLI_strdup(id->name + 2);
3045  }
3046  else {
3047  char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3];
3048  BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->filepath, id->name + 2);
3049  files->entry->relpath = BLI_strdup(relname);
3050  }
3051 // files->type |= S_IFREG;
3052 # if 0 /* XXX TODO show the selection status of the objects */
3053  if (!filelist->has_func) { /* F4 DATA BROWSE */
3054  if (idcode == ID_OB) {
3055  if ( ((Object *)id)->flag & SELECT) {
3056  files->entry->selflag |= FILE_SEL_SELECTED;
3057  }
3058  }
3059  else if (idcode == ID_SCE) {
3060  if ( ((Scene *)id)->r.scemode & R_BG_RENDER) {
3061  files->entry->selflag |= FILE_SEL_SELECTED;
3062  }
3063  }
3064  }
3065 # endif
3066  // files->entry->nr = totbl + 1;
3067  files->entry->poin = id;
3068  fake = id->flag & LIB_FAKEUSER;
3069  if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO ||
3070  idcode == ID_IM) {
3071  files->typeflag |= FILE_TYPE_IMAGE;
3072  }
3073 # if 0
3074  if (id->lib && fake) {
3075  BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us);
3076  }
3077  else if (id->lib) {
3078  BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us);
3079  }
3080  else if (fake) {
3081  BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us);
3082  }
3083  else {
3084  BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us);
3085  }
3086 # endif
3087 
3088  if (id->lib) {
3089  if (totlib == 0) {
3090  firstlib = files;
3091  }
3092  totlib++;
3093  }
3094 
3095  files++;
3096  }
3097  totbl++;
3098  }
3099  }
3100 
3101  /* only qsort of library blocks */
3102  if (totlib > 1) {
3103  qsort(firstlib, totlib, sizeof(*files), compare_name);
3104  }
3105  }
3106 }
3107 #endif
3108 
3109 static void filelist_readjob_do(const bool do_lib,
3110  FileList *filelist,
3111  const char *main_name,
3112  const short *stop,
3113  short *do_update,
3114  float *progress,
3115  ThreadMutex *lock)
3116 {
3117  ListBase entries = {0};
3118  BLI_Stack *todo_dirs;
3119  TodoDir *td_dir;
3120  char dir[FILE_MAX_LIBEXTRA];
3121  char filter_glob[FILE_MAXFILE];
3122  const char *root = filelist->filelist.root;
3123  const int max_recursion = filelist->max_recursion;
3124  int nbr_done_dirs = 0, nbr_todo_dirs = 1;
3125 
3126  // BLI_assert(filelist->filtered == NULL);
3129 
3130  /* A valid, but empty directory from now. */
3131  filelist->filelist.nbr_entries = 0;
3132 
3133  todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__);
3134  td_dir = BLI_stack_push_r(todo_dirs);
3135  td_dir->level = 1;
3136 
3137  BLI_strncpy(dir, filelist->filelist.root, sizeof(dir));
3138  BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob));
3139 
3140  BLI_path_normalize_dir(main_name, dir);
3141  td_dir->dir = BLI_strdup(dir);
3142 
3143  while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
3144  FileListInternEntry *entry;
3145  int nbr_entries = 0;
3146  bool is_lib = do_lib;
3147 
3148  char *subdir;
3149  char rel_subdir[FILE_MAX_LIBEXTRA];
3150  int recursion_level;
3151  bool skip_currpar;
3152 
3153  td_dir = BLI_stack_peek(todo_dirs);
3154  subdir = td_dir->dir;
3155  recursion_level = td_dir->level;
3156  skip_currpar = (recursion_level > 1);
3157 
3158  BLI_stack_discard(todo_dirs);
3159 
3160  /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over
3161  * entry->relpath itself (nor any path containing it), since it may actually be a datablock
3162  * name inside .blend file, which can have slashes and backslashes! See T46827.
3163  * Note that in the end, this means we 'cache' valid relative subdir once here,
3164  * this is actually better. */
3165  BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir));
3166  BLI_path_normalize_dir(root, rel_subdir);
3167  BLI_path_rel(rel_subdir, root);
3168 
3169  if (do_lib) {
3170  nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar);
3171  }
3172  if (!nbr_entries) {
3173  is_lib = false;
3174  nbr_entries = filelist_readjob_list_dir(
3175  subdir, &entries, filter_glob, do_lib, main_name, skip_currpar);
3176  }
3177 
3178  for (entry = entries.first; entry; entry = entry->next) {
3179  BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath);
3180 
3181  /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here,
3182  * things would crash way before we overflow that counter!
3183  * Using an atomic operation to avoid having to lock thread...
3184  * Note that we do not really need this here currently,
3185  * since there is a single listing thread, but better
3186  * remain consistent about threading! */
3187  *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32(
3188  (uint32_t *)filelist->filelist_intern.curr_uuid, 1);
3189 
3190  /* Only thing we change in direntry here, so we need to free it first. */
3191  MEM_freeN(entry->relpath);
3192  entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
3193  * added by BLI_path_rel to rel_subdir. */
3194  entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir));
3195  entry->free_name = true;
3196 
3197  /* Here we decide whether current filedirentry is to be listed too, or not. */
3198  if (max_recursion && (is_lib || (recursion_level <= max_recursion))) {
3199  if (((entry->typeflag & FILE_TYPE_DIR) == 0) || FILENAME_IS_CURRPAR(entry->relpath)) {
3200  /* Skip... */
3201  }
3202  else if (!is_lib && (recursion_level >= max_recursion) &&
3203  ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) {
3204  /* Do not recurse in real directories in this case, only in .blend libs. */
3205  }
3206  else {
3207  /* We have a directory we want to list, add it to todo list! */
3208  BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
3209  BLI_path_normalize_dir(main_name, dir);
3210  td_dir = BLI_stack_push_r(todo_dirs);
3211  td_dir->level = recursion_level + 1;
3212  td_dir->dir = BLI_strdup(dir);
3213  nbr_todo_dirs++;
3214  }
3215  }
3216  }
3217 
3218  if (nbr_entries) {
3219  BLI_mutex_lock(lock);
3220 
3221  *do_update = true;
3222 
3223  BLI_movelisttolist(&filelist->filelist.entries, &entries);
3224  filelist->filelist.nbr_entries += nbr_entries;
3225 
3226  BLI_mutex_unlock(lock);
3227  }
3228 
3229  nbr_done_dirs++;
3230  *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs;
3231  MEM_freeN(subdir);
3232  }
3233 
3234  /* If we were interrupted by stop, stack may not be empty and we need to free
3235  * pending dir paths. */
3236  while (!BLI_stack_is_empty(todo_dirs)) {
3237  td_dir = BLI_stack_peek(todo_dirs);
3238  MEM_freeN(td_dir->dir);
3239  BLI_stack_discard(todo_dirs);
3240  }
3241  BLI_stack_free(todo_dirs);
3242 }
3243 
3244 static void filelist_readjob_dir(Main *UNUSED(current_main),
3245  FileList *filelist,
3246  const char *main_name,
3247  short *stop,
3248  short *do_update,
3249  float *progress,
3250  ThreadMutex *lock)
3251 {
3252  filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock);
3253 }
3254 
3255 static void filelist_readjob_lib(Main *UNUSED(current_main),
3256  FileList *filelist,
3257  const char *main_name,
3258  short *stop,
3259  short *do_update,
3260  float *progress,
3261  ThreadMutex *lock)
3262 {
3263  filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock);
3264 }
3265 
3266 static void filelist_readjob_main(Main *current_main,
3267  FileList *filelist,
3268  const char *main_name,
3269  short *stop,
3270  short *do_update,
3271  float *progress,
3272  ThreadMutex *lock)
3273 {
3274  /* TODO! */
3275  filelist_readjob_dir(current_main, filelist, main_name, stop, do_update, progress, lock);
3276 }
3277 
3281 static void filelist_readjob_main_assets(Main *current_main,
3282  FileList *filelist,
3283  const char *UNUSED(main_name),
3284  short *UNUSED(stop),
3285  short *do_update,
3286  float *UNUSED(progress),
3287  ThreadMutex *UNUSED(lock))
3288 {
3291 
3292  /* A valid, but empty directory from now. */
3293  filelist->filelist.nbr_entries = 0;
3294 
3295  FileListInternEntry *entry;
3296  ListBase tmp_entries = {0};
3297  ID *id_iter;
3298  int nbr_entries = 0;
3299 
3300  FOREACH_MAIN_ID_BEGIN (current_main, id_iter) {
3301  if (!id_iter->asset_data) {
3302  continue;
3303  }
3304 
3305  const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
3306 
3307  entry = MEM_callocN(sizeof(*entry), __func__);
3308  entry->relpath = BLI_strdup(id_code_name);
3309  entry->name = id_iter->name + 2;
3310  entry->free_name = false;
3312  entry->blentype = GS(id_iter->name);
3313  *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32(
3314  (uint32_t *)filelist->filelist_intern.curr_uuid, 1);
3316  id_iter);
3317  entry->local_data.id = id_iter;
3318  nbr_entries++;
3319  BLI_addtail(&tmp_entries, entry);
3320  }
3322 
3323  if (nbr_entries) {
3324  *do_update = true;
3325 
3326  BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries);
3327  filelist->filelist.nbr_entries += nbr_entries;
3328  filelist->filelist.nbr_entries_filtered = filelist->filelist.entry_idx_start =
3329  filelist->filelist.entry_idx_end = -1;
3330  }
3331 }
3332 
3333 typedef struct FileListReadJob {
3341 
3342 static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
3343 {
3344  FileListReadJob *flrj = flrjv;
3345 
3346  // printf("START filelist reading (%d files, main thread: %d)\n",
3347  // flrj->filelist->filelist.nbr_entries, BLI_thread_is_main());
3348 
3349  BLI_mutex_lock(&flrj->lock);
3350 
3351  BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist);
3352 
3353  flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
3354 
3357 
3360  memset(flrj->tmp_filelist->filelist_intern.curr_uuid,
3361  0,
3362  sizeof(flrj->tmp_filelist->filelist_intern.curr_uuid));
3363 
3364  flrj->tmp_filelist->libfiledata = NULL;
3365  memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
3367  flrj->tmp_filelist->asset_library = NULL;
3368 
3369  BLI_mutex_unlock(&flrj->lock);
3370 
3371  flrj->tmp_filelist->read_job_fn(flrj->current_main,
3372  flrj->tmp_filelist,
3373  flrj->main_name,
3374  stop,
3375  do_update,
3376  progress,
3377  &flrj->lock);
3378 }
3379 
3380 static void filelist_readjob_update(void *flrjv)
3381 {
3382  FileListReadJob *flrj = flrjv;
3383  FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
3384  ListBase new_entries = {NULL};
3385  int nbr_entries, new_nbr_entries = 0;
3386 
3387  BLI_movelisttolist(&new_entries, &fl_intern->entries);
3388  nbr_entries = flrj->filelist->filelist.nbr_entries;
3389 
3390  BLI_mutex_lock(&flrj->lock);
3391 
3392  if (flrj->tmp_filelist->filelist.nbr_entries > 0) {
3393  /* We just move everything out of 'thread context' into final list. */
3394  new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries;
3395  BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
3396  flrj->tmp_filelist->filelist.nbr_entries = 0;
3397  }
3398 
3399  BLI_mutex_unlock(&flrj->lock);
3400 
3401  if (new_nbr_entries) {
3402  /* Do not clear selection cache, we can assume already 'selected' uuids are still valid! */
3403  filelist_clear_ex(flrj->filelist, true, false);
3404 
3406  }
3407 
3408  /* if no new_nbr_entries, this is NOP */
3409  BLI_movelisttolist(&fl_intern->entries, &new_entries);
3410  flrj->filelist->filelist.nbr_entries = MAX2(nbr_entries, 0) + new_nbr_entries;
3411 }
3412 
3413 static void filelist_readjob_endjob(void *flrjv)
3414 {
3415  FileListReadJob *flrj = flrjv;
3416 
3417  /* In case there would be some dangling update... */
3418  filelist_readjob_update(flrjv);
3419 
3420  flrj->filelist->flags &= ~FL_IS_PENDING;
3421  flrj->filelist->flags |= FL_IS_READY;
3422 }
3423 
3424 static void filelist_readjob_free(void *flrjv)
3425 {
3426  FileListReadJob *flrj = flrjv;
3427 
3428  // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries);
3429 
3430  if (flrj->tmp_filelist) {
3431  /* tmp_filelist shall never ever be filtered! */
3434 
3436  filelist_free(flrj->tmp_filelist);
3437  MEM_freeN(flrj->tmp_filelist);
3438  }
3439 
3440  BLI_mutex_end(&flrj->lock);
3441 
3442  MEM_freeN(flrj);
3443 }
3444 
3446 {
3447  Main *bmain = CTX_data_main(C);
3448  wmJob *wm_job;
3449  FileListReadJob *flrj;
3450 
3451  if (!filelist_is_dir(filelist, filelist->filelist.root)) {
3452  return;
3453  }
3454 
3455  /* prepare job data */
3456  flrj = MEM_callocN(sizeof(*flrj), __func__);
3457  flrj->filelist = filelist;
3458  flrj->current_main = bmain;
3459  BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name));
3460 
3461  filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY);
3462  filelist->flags |= FL_IS_PENDING;
3463 
3464  /* Init even for single threaded execution. Called functions use it. */
3465  BLI_mutex_init(&flrj->lock);
3466 
3467  if (filelist->tags & FILELIST_TAGS_NO_THREADS) {
3468  short dummy_stop = false;
3469  short dummy_do_update = false;
3470  float dummy_progress = 0.0f;
3471 
3472  /* Single threaded execution. Just directly call the callbacks. */
3473  filelist_readjob_startjob(flrj, &dummy_stop, &dummy_do_update, &dummy_progress);
3475  filelist_readjob_free(flrj);
3476 
3478  return;
3479  }
3480 
3481  /* setup job */
3482  wm_job = WM_jobs_get(CTX_wm_manager(C),
3483  CTX_wm_window(C),
3484  CTX_data_scene(C),
3485  "Listing Dirs...",
3489  WM_jobs_timer(wm_job,
3490  0.01,
3495 
3496  /* start the job */
3497  WM_jobs_start(CTX_wm_manager(C), wm_job);
3498 }
3499 
3501 {
3503 }
3504 
3506 {
3507  return WM_jobs_test(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR);
3508 }
typedef float(TangentPoint)[2]
void BKE_asset_metadata_free(struct AssetMetaData **asset_data)
Definition: asset.cc:47
struct PreviewImage * BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data, const struct ID *owner_id)
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
struct ImBuf * BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT
Definition: icons.cc:866
int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT
Definition: icons.cc:856
struct ImBuf * BKE_previewimg_to_imbuf(struct PreviewImage *prv, const int size)
Definition: icons.cc:597
bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size)
bool BKE_icon_delete(const int icon_id)
Definition: icons.cc:940
const char * BKE_idtype_idcode_to_name(const short idcode)
Definition: idtype.c:168
short BKE_idtype_idcode_from_name(const char *idtype_name)
Definition: idtype.c:208
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
Definition: idtype.c:242
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:250
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:244
struct ListBase * which_libbase(struct Main *bmain, short type)
Definition: main.c:447
const char * BKE_main_blendfile_path_from_global(void)
Definition: main.c:439
struct bUserAssetLibrary * BKE_preferences_asset_library_find_from_index(const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define BLI_assert(a)
Definition: BLI_assert.h:58
File and directory operations.
eFileAttributes BLI_file_attributes(const char *path)
Definition: storage.c:230
#define FILE_ATTR_ANY_LINK
Definition: BLI_fileops.h:99
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
Definition: BLI_filelist.c:467
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:444
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist)
Definition: BLI_filelist.c:238
struct stat BLI_stat_t
Definition: BLI_fileops.h:67
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:436
eFileAttributes
Definition: BLI_fileops.h:80
@ FILE_ATTR_ALIAS
Definition: BLI_fileops.h:91
@ FILE_ATTR_TEMPORARY
Definition: BLI_fileops.h:88
@ FILE_ATTR_HIDDEN
Definition: BLI_fileops.h:82
@ FILE_ATTR_SYSTEM
Definition: BLI_fileops.h:83
@ FILE_ATTR_OFFLINE
Definition: BLI_fileops.h:90
bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT
Some types for dealing with directories.
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:707
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:996
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:718
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, const unsigned int nentries_reserve)
Definition: BLI_ghash.c:980
#define BLI_ghashutil_uinthash_v4_p
Definition: BLI_ghash.h:370
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:900
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:924
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:830
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
GHash * BLI_ghash_ptr_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b)
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void copy_vn_i(int *array_tar, const int size, const int val)
Definition: math_vector.c:1374
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL()
Definition: path_util.c:728
bool BLI_path_extension_check_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1487
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1868
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2)
Definition: path_util.c:266
#define FILE_MAXFILE
#define FILE_MAX
#define FILENAME_IS_CURRENT(_n)
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
#define FILENAME_IS_CURRPAR(_n)
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1506
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1571
bool BLI_path_extension_check(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1459
int BLI_path_slash_ensure(char *string) ATTR_NONNULL()
Definition: path_util.c:1981
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL()
Definition: path_util.c:519
#define FILENAME_PARENT
const char * BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1962
bool BLI_path_extension_check_n(const char *str,...) ATTR_NONNULL(1) ATTR_SENTINEL(0)
Definition: path_util.c:1464
#define FILE_MAXDIR
#define BLI_path_cmp
#define FILENAME_IS_PARENT(_n)
void * BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:127
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:220
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:310
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:114
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:230
#define BLI_stack_new(esize, descr)
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:578
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:666
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:766
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:837
char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, const char pad, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:132
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
char * BLI_strdupcat(const char *__restrict str1, const char *__restrict str2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:81
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
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
TaskPool * BLI_task_pool_create_background(void *userdata, TaskPriority priority)
Definition: task_pool.cc:423
void * BLI_task_pool_user_data(TaskPool *pool)
Definition: task_pool.cc:541
void BLI_task_pool_cancel(TaskPool *pool)
Definition: task_pool.cc:511
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:456
@ TASK_PRIORITY_LOW
Definition: BLI_task.h:66
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:475
void BLI_thread_queue_push(ThreadQueue *queue, void *work)
Definition: threads.cc:669
void BLI_mutex_end(ThreadMutex *mutex)
Definition: threads.cc:416
void * BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
Definition: threads.cc:739
void BLI_mutex_init(ThreadMutex *mutex)
Definition: threads.cc:396
void BLI_thread_queue_free(ThreadQueue *queue)
Definition: threads.cc:657
bool BLI_thread_queue_is_empty(ThreadQueue *queue)
Definition: threads.cc:784
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:401
void BLI_thread_queue_nowait(ThreadQueue *queue)
Definition: threads.cc:795
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:406
void * BLI_thread_queue_pop(ThreadQueue *queue)
Definition: threads.cc:680
ThreadQueue * BLI_thread_queue_init(void)
Definition: threads.cc:643
pthread_mutex_t ThreadMutex
Definition: BLI_threads.h:83
#define ARRAY_SIZE(arr)
#define POINTER_FROM_INT(i)
#define POINTER_AS_UINT(i)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define MAX2(a, b)
#define ELEM(...)
#define POINTER_FROM_UINT(i)
#define STREQ(a, b)
Compatibility-like things for windows.
void BLI_windows_get_default_root_dir(char *root_dir)
#define S_ISDIR(x)
Definition: BLI_winstuff.h:64
external readfile function prototypes.
#define BLO_GROUP_MAX
Definition: BLO_readfile.h:146
struct BlendHandle BlendHandle
Definition: BLO_readfile.h:49
BlendHandle * BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports)
Definition: readblenentry.c:71
struct LinkNode * BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, int *r_tot_info_items)
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition: readfile.c:1701
bool BLO_has_bfile_extension(const char *str)
Definition: readfile.c:1684
struct LinkNode * BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
void BLO_blendhandle_close(BlendHandle *bh)
#define FILTER_ID_ALL
Definition: DNA_ID.h:741
#define MAX_ID_NAME
Definition: DNA_ID.h:269
@ LIB_FAKEUSER
Definition: DNA_ID.h:477
@ ICON_SIZE_PREVIEW
Definition: DNA_ID_enums.h:30
@ ID_TE
Definition: DNA_ID_enums.h:64
@ ID_IM
Definition: DNA_ID_enums.h:65
@ ID_LA
Definition: DNA_ID_enums.h:67
@ ID_SCE
Definition: DNA_ID_enums.h:57
@ ID_WO
Definition: DNA_ID_enums.h:71
@ ID_MA
Definition: DNA_ID_enums.h:63
@ ID_OB
Definition: DNA_ID_enums.h:59
#define R_BG_RENDER
@ FILE_SORT_DEFAULT
@ FILE_SORT_ALPHA
@ FILE_SORT_TIME
@ FILE_SORT_EXTENSION
@ FILE_SORT_SIZE
eFileSelectType
@ FILE_LOADLIB
@ FILE_MAIN_ASSET
@ FILE_MAIN
eFileSel_File_Types
@ FILE_TYPE_BTX
@ FILE_TYPE_BLENDER
@ FILE_TYPE_ASSET
@ FILE_TYPE_ALEMBIC
@ FILE_TYPE_ARCHIVE
@ FILE_TYPE_TEXT
@ FILE_TYPE_COLLADA
@ FILE_TYPE_PYSCRIPT
@ FILE_TYPE_BLENDER_BACKUP
@ FILE_TYPE_VOLUME
@ FILE_TYPE_APPLICATIONBUNDLE
@ FILE_TYPE_MOVIE
@ FILE_TYPE_SOUND
@ FILE_TYPE_OBJECT_IO
@ FILE_TYPE_FOLDER
@ FILE_TYPE_FTFONT
@ FILE_TYPE_BLENDERLIB
@ FILE_TYPE_OPERATOR
@ FILE_TYPE_USD
@ FILE_TYPE_IMAGE
@ FILE_TYPE_DIR
@ FILE_ENTRY_NAME_FREE
@ FILE_ENTRY_INVALID_PREVIEW
eFileBrowse_Mode
@ FILE_SEL_SELECTED
@ FILE_ASSET_LIBRARY_CUSTOM
#define FILE_MAX_LIBEXTRA
int datatoc_prvicons_png_size
char datatoc_prvicons_png[]
FSMenuCategory
@ FS_CATEGORY_SYSTEM_BOOKMARKS
@ FS_CATEGORY_OTHER
@ FS_CATEGORY_SYSTEM
struct FSMenu * ED_fsmenu_get(void)
Definition: fsmenu.c:78
struct FSMenuEntry * ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:86
struct FileSelectParams * ED_fileselect_get_active_params(const struct SpaceFile *sfile)
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_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
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:478
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
bool IMB_isanim(const char *filepath)
Definition: util.c:399
struct ImBuf * IMB_ibImageFromMemory(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
Definition: readimage.c:99
Contains defines and structs used throughout the imbuf module.
const char * imb_ext_movie[]
Definition: util.c:95
const char * imb_ext_audio[]
Definition: util.c:102
@ IB_rect
const char * imb_ext_image[]
Definition: util.c:60
struct ImBuf * IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
Definition: thumbs.c:563
@ THB_LARGE
Definition: IMB_thumbs.h:40
void IMB_thumb_locks_release(void)
Definition: thumbs.c:702
ThumbSource
Definition: IMB_thumbs.h:44
@ THB_SOURCE_IMAGE
Definition: IMB_thumbs.h:45
@ THB_SOURCE_FONT
Definition: IMB_thumbs.h:48
@ THB_SOURCE_BLEND
Definition: IMB_thumbs.h:47
@ THB_SOURCE_MOVIE
Definition: IMB_thumbs.h:46
void IMB_thumb_path_unlock(const char *path)
Definition: thumbs.c:733
void IMB_thumb_path_lock(const char *path)
Definition: thumbs.c:717
void IMB_thumb_locks_acquire(void)
Definition: thumbs.c:686
void IMB_thumb_ensure_translations(void)
Definition: thumbs_font.c:51
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
Platform independent time functions.
#define C
Definition: RandGen.cpp:39
int UI_icon_from_idcode(const int idcode)
@ WM_JOB_TYPE_FILESEL_READDIR
Definition: WM_api.h:742
@ WM_JOB_PROGRESS
Definition: WM_api.h:726
#define NA_JOB_FINISHED
Definition: WM_types.h:470
#define NC_SPACE
Definition: WM_types.h:293
#define ND_SPACE_FILE_LIST
Definition: WM_types.h:419
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
ATOMIC_INLINE void * atomic_cas_ptr(void **v, void *old, void *_new)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
#define SELECT
FILE * file
bool is_valid
void * user_data
#define str(s)
int ED_file_icon(const FileDirEntry *file)
Definition: filelist.c:1305
#define FILELIST_ENTRYCACHESIZE_DEFAULT
Definition: filelist.c:312
static void filelist_readjob_do(const bool do_lib, FileList *filelist, const char *main_name, const short *stop, short *do_update, float *progress, ThreadMutex *lock)
Definition: filelist.c:3109
void filelist_tag_force_reset(FileList *filelist)
Definition: filelist.c:1905
ImBuf * filelist_geticon_image(struct FileList *filelist, const int index)
Definition: filelist.c:1176
static bool is_filtered_id_file(const FileListInternEntry *file, const char *id_group, const char *name, const FileListFilter *filter)
Definition: filelist.c:855
void filelist_free(struct FileList *filelist)
Definition: filelist.c:1796
bool filelist_is_ready(struct FileList *filelist)
Definition: filelist.c:1910
static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
Definition: filelist.c:1335
void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene)
Definition: filelist.c:3500
static void filelist_cache_previews_clear(FileListEntryCache *cache)
Definition: filelist.c:1563
void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
Definition: filelist.c:2384
@ FL_NEED_SORTING
Definition: filelist.c:430
@ FL_IS_PENDING
Definition: filelist.c:429
@ FL_SORT_INVERT
Definition: filelist.c:432
@ FL_IS_READY
Definition: filelist.c:428
@ FL_NEED_FILTERING
Definition: filelist.c:431
@ FL_FORCE_RESET
Definition: filelist.c:427
static FileDirEntry * filelist_geticon_get_file(struct FileList *filelist, const int index)
Definition: filelist.c:1138
void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
Definition: filelist.c:728
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
Definition: filelist.c:1637
static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
Definition: filelist.c:1478
#define FILEDIR_NBR_ENTRIES_UNSET
Definition: filelist.c:90
void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile)
Definition: filelist.c:213
void filelist_sort(struct FileList *filelist)
Definition: filelist.c:695
struct FileListInternEntry FileListInternEntry
int filelist_geticon(struct FileList *filelist, const int index, const bool is_main)
Definition: filelist.c:1298
static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter)
Definition: filelist.c:917
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2656
static void filelist_readjob_main(Main *current_main, FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
Definition: filelist.c:3266
struct FileListEntryPreviewTaskData FileListEntryPreviewTaskData
static ImBuf * gSpecialFileImages[SPECIAL_IMG_MAX]
Definition: filelist.c:458
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
Definition: filelist.c:2731
@ FLF_DO_FILTER
Definition: filelist.c:373
@ FLF_HIDE_LIB_DIR
Definition: filelist.c:376
@ FLF_HIDE_PARENT
Definition: filelist.c:375
@ FLF_ASSETS_ONLY
Definition: filelist.c:377
@ FLF_HIDE_DOT
Definition: filelist.c:374
struct TodoDir TodoDir
FileListTags
Definition: filelist.c:436
@ FILELIST_TAGS_USES_MAIN_DATA
Definition: filelist.c:438
@ FILELIST_TAGS_NO_THREADS
Definition: filelist.c:440
int filelist_file_findpath(struct FileList *filelist, const char *filename)
Definition: filelist.c:2046
#define SPECIAL_IMG_COLS
Definition: filelist.c:445
const char * folderlist_peeklastdir(ListBase *folderlist)
Definition: filelist.c:143
#define SPECIAL_IMG_ROWS
Definition: filelist.c:444
static void filelist_direntryarr_free(FileDirEntryArr *array)
Definition: filelist.c:1428
bool filelist_cache_previews_running(FileList *filelist)
Definition: filelist.c:2461
static void filelist_readjob_dir(Main *current_main, FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
void filelist_freelib(struct FileList *filelist)
Definition: filelist.c:1819
static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
Definition: filelist.c:1598
static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
Definition: filelist.c:502
static void parent_dir_until_exists_or_default_root(char *dir)
Definition: filelist.c:1313
void filelist_setfilter_options(FileList *filelist, const bool do_filter, const bool hide_dot, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, const bool filter_assets_only, const char *filter_glob, const char *filter_search)
Definition: filelist.c:988
static ImBuf * filelist_geticon_image_ex(FileDirEntry *file)
Definition: filelist.c:1157
static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
Definition: filelist.c:1324
struct FileListFilter FileListFilter
void filelist_entry_parent_select_set(FileList *filelist, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2720
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2666
struct FileListEntryCache FileListEntryCache
static int filelist_readjob_list_dir(const char *root, ListBase *entries, const char *filter_glob, const bool do_lib, const char *main_name, const bool skip_currpar)
Definition: filelist.c:2769
static void filelist_cache_previews_free(FileListEntryCache *cache)
Definition: filelist.c:1580
void folderlist_popdir(struct ListBase *folderlist, char *dir)
Definition: filelist.c:99
uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
Definition: filelist.c:2693
static uint64_t groupname_to_filter_id(const char *group)
Definition: filelist.c:2752
BlendHandle * filelist_lib(struct FileList *filelist)
Definition: filelist.c:1827
void folder_history_list_free(SpaceFile *sfile)
Definition: filelist.c:240
static int groupname_to_code(const char *group)
Definition: filelist.c:2736
void filelist_setdir(struct FileList *filelist, char *r_dir)
Definition: filelist.c:1876
int folderlist_clear_next(struct SpaceFile *sfile)
Definition: filelist.c:155
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition: filelist.c:900
FileList * filelist_new(short type)
Definition: filelist.c:1721
void folderlist_pushdir(ListBase *folderlist, const char *dir)
Definition: filelist.c:119
struct FileListReadJob FileListReadJob
static void filelist_readjob_endjob(void *flrjv)
Definition: filelist.c:3413
ListBase folder_history_list_duplicate(ListBase *listbase)
Definition: filelist.c:247
struct FolderList FolderList
static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
Definition: filelist.c:1987
struct FileListIntern FileListIntern
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
Definition: filelist.c:1686
ID * filelist_file_get_id(const FileDirEntry *file)
Definition: filelist.c:2071
int ED_file_extension_icon(const char *path)
Definition: filelist.c:2567
@ FLC_PREVIEWS_ACTIVE
Definition: filelist.c:343
@ FLC_IS_INIT
Definition: filelist.c:342
static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
Definition: filelist.c:1537
void filelist_readjob_start(FileList *filelist, const bContext *C)
Definition: filelist.c:3445
static int compare_extension(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:636
static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter)
Definition: filelist.c:816
static int compare_size(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:608
void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
Definition: filelist.c:1892
static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar)
Definition: filelist.c:2864
bool filelist_cache_previews_update(FileList *filelist)
Definition: filelist.c:2408
static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
Definition: filelist.c:3342
void folderlist_free(ListBase *folderlist)
Definition: filelist.c:177
static int compare_name(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:562
static void filelist_entry_free(FileDirEntry *entry)
Definition: filelist.c:1422
void filelist_settype(FileList *filelist, short type)
Definition: filelist.c:1735
static void filelist_intern_entry_free(FileListInternEntry *entry)
Definition: filelist.c:1447
static void filelist_cache_free(FileListEntryCache *cache)
Definition: filelist.c:1662
static void filelist_readjob_main_assets(Main *current_main, FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
Definition: filelist.c:511
FileDirEntry * filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4])
Definition: filelist.c:2076
@ SPECIAL_IMG_DRIVE_FIXED
Definition: filelist.c:452
@ SPECIAL_IMG_DRIVE_ATTACHED
Definition: filelist.c:453
@ SPECIAL_IMG_MAX
Definition: filelist.c:455
@ SPECIAL_IMG_DRIVE_DISC
Definition: filelist.c:449
@ SPECIAL_IMG_FOLDER
Definition: filelist.c:450
@ SPECIAL_IMG_DOCUMENT
Definition: filelist.c:448
@ SPECIAL_IMG_PARENT
Definition: filelist.c:451
@ SPECIAL_IMG_DRIVE_REMOTE
Definition: filelist.c:454
struct FileListEntryPreview FileListEntryPreview
bool filelist_file_cache_block(struct FileList *filelist, const int index)
Definition: filelist.c:2172
static void filelist_readjob_update(void *flrjv)
Definition: filelist.c:3380
static FileDirEntry * filelist_file_create_entry(FileList *filelist, const int index)
Definition: filelist.c:1941
static bool is_filtered_main_assets(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter)
Definition: filelist.c:924
static const char * fileentry_uiname(const char *root, const char *relpath, const eFileSel_File_Types typeflag, char *buff)
Definition: filelist.c:1832
void filelist_clear(struct FileList *filelist)
Definition: filelist.c:1791
void filelist_init_icons(void)
Definition: filelist.c:1094
static ListBase folderlist_duplicate(ListBase *folderlist)
Definition: filelist.c:188
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
Definition: filelist.c:1553
static int filelist_geticon_ex(const FileDirEntry *file, const char *root, const bool is_main, const bool ignore_libdir)
Definition: filelist.c:1182
static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor)
Definition: filelist.c:2146
void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
Definition: filelist.c:2103
static bool filelist_file_cache_block_create(FileList *filelist, const int start_index, const int size, int cursor)
Definition: filelist.c:2120
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2608
static bool is_hidden_dot_filename(const char *filename, const FileListInternEntry *file)
Definition: filelist.c:743
FileDirEntry * filelist_file(struct FileList *filelist, int index)
Definition: filelist.c:2041
static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist), char *UNUSED(r_dir), const bool UNUSED(do_change))
Definition: filelist.c:1360
static void filelist_filter_clear(FileList *filelist)
Definition: filelist.c:932
static int compare_date(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:580
int ED_path_extension_type(const char *path)
Definition: filelist.c:2498
bool filelist_pending(struct FileList *filelist)
Definition: filelist.c:1915
struct FileList FileList
void filelist_filter(FileList *filelist)
Definition: filelist.c:937
static bool is_filtered_hidden(const char *filename, const FileListFilter *filter, const FileListInternEntry *file)
Definition: filelist.c:783
#define SPECIAL_IMG_SIZE
Definition: filelist.c:443
static void filelist_entry_clear(FileDirEntry *entry)
Definition: filelist.c:1368
static void filelist_readjob_lib(Main *current_main, FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock)
void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library)
Definition: filelist.c:1068
static FileFolderHistory * folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode)
Definition: filelist.c:202
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition: filelist.c:1920
int filelist_files_ensure(FileList *filelist)
Definition: filelist.c:1931
bool filelist_entry_is_selected(FileList *filelist, const int index)
Definition: filelist.c:2704
FileDirEntry * filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
Definition: filelist.c:1993
static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
Definition: filelist.c:1354
ImBuf * filelist_getimage(struct FileList *filelist, const int index)
Definition: filelist.c:1145
static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *library_a, const FileSelectAssetLibraryUID *library_b)
Definition: filelist.c:1048
ImBuf * filelist_file_getimage(const FileDirEntry *file)
Definition: filelist.c:1152
static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history)
Definition: filelist.c:227
bool filelist_needs_force_reset(FileList *filelist)
Definition: filelist.c:1900
bool filelist_is_dir(struct FileList *filelist, const char *path)
Definition: filelist.c:1868
void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection)
Definition: filelist.c:1770
static void filelist_readjob_free(void *flrjv)
Definition: filelist.c:3424
static void filelist_intern_free(FileListIntern *filelist_intern)
Definition: filelist.c:1465
uint filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
Definition: filelist.c:2679
static bool file_is_blend_backup(const char *str)
Definition: filelist.c:2469
int filelist_needs_reading(struct FileList *filelist)
Definition: filelist.c:2603
void filelist_free_icons(void)
Definition: filelist.c:1128
const char * filelist_dir(struct FileList *filelist)
Definition: filelist.c:1863
int filelist_readjob_running(wmWindowManager *wm, Scene *owner_scene)
Definition: filelist.c:3505
FileSelType
Definition: filelist.h:38
@ FILE_SEL_REMOVE
Definition: filelist.h:39
@ FILE_SEL_ADD
Definition: filelist.h:40
@ FILE_SEL_TOGGLE
Definition: filelist.h:41
FileCheckType
Definition: filelist.h:44
@ CHECK_FILES
Definition: filelist.h:46
@ CHECK_DIRS
Definition: filelist.h:45
@ CHECK_ALL
Definition: filelist.h:47
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define GS(x)
Definition: iris.c:241
static char ** names
Definition: makesdna.c:162
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
static unsigned a[3]
Definition: RandGen.cpp:92
static void update(bNodeTree *ntree)
return ret
unsigned int uint32_t
Definition: stdint.h:83
__int64 int64_t
Definition: stdint.h:92
unsigned __int64 uint64_t
Definition: stdint.h:93
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
struct AssetMetaData * asset_data
Definition: BLO_readfile.h:125
struct FSMenuEntry * next
Definition: fsmenu.c:68
struct FileDirEntryRevision * next
struct FileDirEntryVariant * next
struct FileDirEntry * next
char * redirection_path
FileDirEntryRevision * entry
TaskPool * previews_pool
Definition: filelist.c:336
ThreadQueue * previews_done
Definition: filelist.c:337
ListBase cached_entries
Definition: filelist.c:319
GHash * misc_entries
Definition: filelist.c:330
int * misc_entries_indices
Definition: filelist.c:329
FileDirEntry ** block_entries
Definition: filelist.c:323
FileListEntryPreview * preview
Definition: filelist.c:360
char path[FILE_MAX]
Definition: filelist.c:347
PreviewImage * in_memory_preview
Definition: filelist.c:352
char filter_glob[FILE_MAXFILE]
Definition: filelist.c:366
char filter_search[66]
Definition: filelist.c:367
uint64_t filter_id
Definition: filelist.c:365
uint64_t filter
Definition: filelist.c:364
PreviewImage * preview_image
Definition: filelist.c:292
struct FileListInternEntry::@503 local_data
eFileAttributes attributes
Definition: filelist.c:300
struct FileListInternEntry * next
Definition: filelist.c:264
struct FileListInternEntry * prev
Definition: filelist.c:264
char * redirection_path
Definition: filelist.c:276
BLI_stat_t st
Definition: filelist.c:301
AssetMetaData * imported_asset_data
Definition: filelist.c:297
char curr_uuid[16]
Definition: filelist.c:309
ListBase entries
Definition: filelist.c:306
FileListInternEntry ** filtered
Definition: filelist.c:307
struct FileList * filelist
Definition: filelist.c:3337
ThreadMutex lock
Definition: filelist.c:3334
struct FileList * tmp_filelist
Definition: filelist.c:3339
Main * current_main
Definition: filelist.c:3336
char main_name[FILE_MAX]
Definition: filelist.c:3335
FileDirEntryArr filelist
Definition: filelist.c:381
struct BlendHandle * libfiledata
Definition: filelist.c:408
short sort
Definition: filelist.c:389
bool(* check_dir_fn)(struct FileList *, char *, const bool)
Definition: filelist.c:413
short flags
Definition: filelist.c:387
bool(* filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *)
Definition: filelist.c:420
void(* read_job_fn)(Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *)
Definition: filelist.c:416
struct FileListIntern filelist_intern
Definition: filelist.c:393
short tags
Definition: filelist.c:422
GHash * selection_state
Definition: filelist.c:403
short max_recursion
Definition: filelist.c:405
struct FileListEntryCache filelist_cache
Definition: filelist.c:395
eFileSelectType type
Definition: filelist.c:383
short recursion_level
Definition: filelist.c:406
FileListFilter filter_data
Definition: filelist.c:391
FileSelectAssetLibraryUID * asset_library
Definition: filelist.c:385
bool inverted
Definition: filelist.c:499
struct FolderList * next
Definition: filelist.c:95
char * foldername
Definition: filelist.c:96
struct FolderList * prev
Definition: filelist.c:95
Definition: DNA_ID.h:273
struct AssetMetaData * asset_data
Definition: DNA_ID.h:280
struct Library * lib
Definition: DNA_ID.h:277
int us
Definition: DNA_ID.h:293
short flag
Definition: DNA_ID.h:288
void * next
Definition: DNA_ID.h:274
char name[66]
Definition: DNA_ID.h:283
unsigned int * rect
char filepath[1024]
Definition: DNA_ID.h:352
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase * folders_prev
ListBase * folders_next
ListBase folder_histories
int level
Definition: filelist.c:2765
char * dir
Definition: filelist.c:2766
struct stat s
const char * relname
Definition: wm_jobs.c:73
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
#define G(x, y, z)
uint len
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
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
bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type)
Definition: wm_jobs.c:223
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