Blender  V3.3
filelist.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2007 Blender Foundation. All rights reserved. */
3 
8 /* global includes */
9 
10 #include <math.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <time.h>
15 
16 #ifndef WIN32
17 # include <unistd.h>
18 #else
19 # include <direct.h>
20 # include <io.h>
21 #endif
22 #include "MEM_guardedalloc.h"
23 
24 #include "BLF_api.h"
25 
26 #include "BLI_blenlib.h"
27 #include "BLI_fileops.h"
28 #include "BLI_fileops_types.h"
29 #include "BLI_fnmatch.h"
30 #include "BLI_ghash.h"
31 #include "BLI_linklist.h"
32 #include "BLI_math.h"
33 #include "BLI_stack.h"
34 #include "BLI_task.h"
35 #include "BLI_threads.h"
36 #include "BLI_utildefines.h"
37 #include "BLI_uuid.h"
38 
39 #ifdef WIN32
40 # include "BLI_winstuff.h"
41 #endif
42 
43 #include "BKE_asset.h"
44 #include "BKE_asset_library.h"
45 #include "BKE_context.h"
46 #include "BKE_global.h"
47 #include "BKE_icons.h"
48 #include "BKE_idtype.h"
49 #include "BKE_lib_id.h"
50 #include "BKE_main.h"
51 #include "BKE_main_idmap.h"
52 #include "BKE_preferences.h"
53 #include "BLO_readfile.h"
54 
55 #include "DNA_asset_types.h"
56 #include "DNA_space_types.h"
57 
58 #include "ED_datafiles.h"
59 #include "ED_fileselect.h"
60 #include "ED_screen.h"
61 
62 #include "IMB_imbuf.h"
63 #include "IMB_imbuf_types.h"
64 #include "IMB_thumbs.h"
65 
66 #include "PIL_time.h"
67 
68 #include "WM_api.h"
69 #include "WM_types.h"
70 
71 #include "UI_interface_icons.h"
72 #include "UI_resources.h"
73 
74 #include "atomic_ops.h"
75 
76 #include "file_indexer.h"
77 #include "file_intern.h"
78 #include "filelist.h"
79 
80 #define FILEDIR_NBR_ENTRIES_UNSET -1
81 
82 /* ----------------- FOLDERLIST (previous/next) -------------- */
83 
84 typedef struct FolderList {
85  struct FolderList *next, *prev;
86  char *foldername;
88 
89 void folderlist_popdir(struct ListBase *folderlist, char *dir)
90 {
91  const char *prev_dir;
92  struct FolderList *folder;
93  folder = folderlist->last;
94 
95  if (folder) {
96  /* remove the current directory */
97  MEM_freeN(folder->foldername);
98  BLI_freelinkN(folderlist, folder);
99 
100  folder = folderlist->last;
101  if (folder) {
102  prev_dir = folder->foldername;
103  BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
104  }
105  }
106  /* delete the folder next or use setdir directly before PREVIOUS OP */
107 }
108 
109 void folderlist_pushdir(ListBase *folderlist, const char *dir)
110 {
111  if (!dir[0]) {
112  return;
113  }
114 
115  struct FolderList *folder, *previous_folder;
116  previous_folder = folderlist->last;
117 
118  /* check if already exists */
119  if (previous_folder && previous_folder->foldername) {
120  if (BLI_path_cmp(previous_folder->foldername, dir) == 0) {
121  return;
122  }
123  }
124 
125  /* create next folder element */
126  folder = MEM_mallocN(sizeof(*folder), __func__);
127  folder->foldername = BLI_strdup(dir);
128 
129  /* add it to the end of the list */
130  BLI_addtail(folderlist, folder);
131 }
132 
133 const char *folderlist_peeklastdir(ListBase *folderlist)
134 {
135  struct FolderList *folder;
136 
137  if (!folderlist->last) {
138  return NULL;
139  }
140 
141  folder = folderlist->last;
142  return folder->foldername;
143 }
144 
146 {
148  struct FolderList *folder;
149 
150  /* if there is no folder_next there is nothing we can clear */
151  if (BLI_listbase_is_empty(sfile->folders_next)) {
152  return 0;
153  }
154 
155  /* if previous_folder, next_folder or refresh_folder operators are executed
156  * it doesn't clear folder_next */
157  folder = sfile->folders_prev->last;
158  if ((!folder) || (BLI_path_cmp(folder->foldername, params->dir) == 0)) {
159  return 0;
160  }
161 
162  /* eventually clear flist->folders_next */
163  return 1;
164 }
165 
166 void folderlist_free(ListBase *folderlist)
167 {
168  if (folderlist) {
169  FolderList *folder;
170  for (folder = folderlist->first; folder; folder = folder->next) {
171  MEM_freeN(folder->foldername);
172  }
173  BLI_freelistN(folderlist);
174  }
175 }
176 
178 {
179  ListBase folderlistn = {NULL};
180 
181  BLI_duplicatelist(&folderlistn, folderlist);
182 
183  for (FolderList *folder = folderlistn.first; folder; folder = folder->next) {
184  folder->foldername = MEM_dupallocN(folder->foldername);
185  }
186  return folderlistn;
187 }
188 
189 /* ----------------- Folder-History (wraps/owns file list above) -------------- */
190 
192 {
193  LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) {
194  if (history->browse_mode == browse_mode) {
195  return history;
196  }
197  }
198 
199  return NULL;
200 }
201 
203 {
204  FileFolderHistory *history = folder_history_find(sfile, sfile->browse_mode);
205 
206  if (!history) {
207  history = MEM_callocN(sizeof(*history), __func__);
208  history->browse_mode = sfile->browse_mode;
209  BLI_addtail(&sfile->folder_histories, history);
210  }
211 
212  sfile->folders_next = &history->folders_next;
213  sfile->folders_prev = &history->folders_prev;
214 }
215 
217 {
218  if (sfile->folders_prev == &history->folders_prev) {
219  sfile->folders_prev = NULL;
220  }
221  if (sfile->folders_next == &history->folders_next) {
222  sfile->folders_next = NULL;
223  }
224  folderlist_free(&history->folders_prev);
225  folderlist_free(&history->folders_next);
226  BLI_freelinkN(&sfile->folder_histories, history);
227 }
228 
230 {
232  folder_history_entry_free(sfile, history);
233  }
234 }
235 
237 {
238  ListBase histories = {NULL};
239 
240  LISTBASE_FOREACH (FileFolderHistory *, history, listbase) {
241  FileFolderHistory *history_new = MEM_dupallocN(history);
242  history_new->folders_prev = folderlist_duplicate(&history->folders_prev);
243  history_new->folders_next = folderlist_duplicate(&history->folders_next);
244  BLI_addtail(&histories, history_new);
245  }
246 
247  return histories;
248 }
249 
250 /* ------------------FILELIST------------------------ */
251 
252 typedef struct FileListInternEntry {
254 
256 
258  int typeflag;
260  int blentype;
261 
262  char *relpath;
266  char *name;
267  bool free_name;
268 
274  struct {
276  ID *id;
277 
278  /* For the few file types that have the preview already in memory. For others, there's delayed
279  * preview reading from disk. Non-owning pointer. */
282 
286 
291 
292 typedef struct FileListIntern {
296 
297  FileUID curr_uid; /* Used to generate UID during internal listing. */
299 
300 #define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */
301 typedef struct FileListEntryCache {
302  size_t size; /* The size of the cache... */
303 
304  int flags;
305 
306  /* This one gathers all entries from both block and misc caches. Used for easy bulk-freeing. */
308 
309  /* Block cache: all entries between start and end index.
310  * used for part of the list on display. */
313 
314  /* Misc cache: random indices, FIFO behavior.
315  * NOTE: Not 100% sure we actually need that, time will say. */
319 
320  /* Allows to quickly get a cached entry from its UID. */
322 
323  /* Previews handling. */
331 
333 enum {
334  FLC_IS_INIT = 1 << 0,
336 };
337 
338 typedef struct FileListEntryPreview {
341  int index;
342  int attributes; /* from FileDirEntry. */
343  int icon_id;
345 
346 /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing
347  * tasks' data (see T74609). */
351 
352 typedef struct FileListFilter {
356  char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
357  short flags;
358 
361 
363 enum {
364  FLF_DO_FILTER = 1 << 0,
365  FLF_HIDE_DOT = 1 << 1,
366  FLF_HIDE_PARENT = 1 << 2,
368  FLF_ASSETS_ONLY = 1 << 4,
369 };
370 
371 struct FileListReadJob;
372 typedef struct FileList {
374 
376  /* The library this list was created for. Stored here so we know when to re-read. */
378  struct AssetLibrary *asset_library; /* Non-owning pointer. */
379 
380  short flags;
381 
382  short sort;
383 
385 
389  const struct FileIndexerType *indexer;
390 
392 
394 
395  /* We need to keep those info outside of actual filelist items,
396  * because those are no more persistent
397  * (only generated on demand, and freed as soon as possible).
398  * Persistent part (mere list of paths + stat info)
399  * is kept as small as possible, and filebrowser-agnostic.
400  */
402 
405 
407 
408  /* Set given path as root directory,
409  * if last bool is true may change given string in place to a valid value.
410  * Returns True if valid dir. */
411  bool (*check_dir_fn)(struct FileList *, char *, const bool);
412 
413  /* Fill filelist (to be called by read job). */
414  void (*read_job_fn)(struct FileListReadJob *, short *, short *, float *);
415 
416  /* Filter an entry of current filelist. */
417  bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *);
418  /* Executed before filtering individual items, to set up additional filter data. */
420 
421  short tags; /* FileListTags */
423 
425 enum {
426  FL_FORCE_RESET = 1 << 0,
427  /* Don't do a full reset (unless #FL_FORCE_RESET is also set), only reset files representing main
428  * data (assets from the current file/#Main). */
430  FL_IS_READY = 1 << 2,
431  FL_IS_PENDING = 1 << 3,
432  FL_NEED_SORTING = 1 << 4,
434  FL_SORT_INVERT = 1 << 6,
435 };
436 
443 };
444 
445 #define SPECIAL_IMG_SIZE 256
446 #define SPECIAL_IMG_ROWS 1
447 #define SPECIAL_IMG_COLS 7
448 
449 enum {
458 };
459 
461 
462 static void filelist_readjob_main(struct FileListReadJob *job_params,
463  short *stop,
464  short *do_update,
465  float *progress);
466 static void filelist_readjob_lib(struct FileListReadJob *job_params,
467  short *stop,
468  short *do_update,
469  float *progress);
470 static void filelist_readjob_dir(struct FileListReadJob *job_params,
471  short *stop,
472  short *do_update,
473  float *progress);
474 static void filelist_readjob_asset_library(struct FileListReadJob *job_params,
475  short *stop,
476  short *do_update,
477  float *progress);
478 static void filelist_readjob_main_assets(struct FileListReadJob *job_params,
479  short *stop,
480  short *do_update,
481  float *progress);
482 
483 /* helper, could probably go in BKE actually? */
484 static int groupname_to_code(const char *group);
485 static uint64_t groupname_to_filter_id(const char *group);
486 
487 static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
488 static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry);
489 
490 /* ********** Sort helpers ********** */
491 
492 struct FileSortData {
493  bool inverted;
494 };
495 
496 static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
497 {
498  return sort_data->inverted ? -val : val;
499 }
500 
516 static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
517 {
518  /* Case 1. */
519  {
520  const int order = BLI_strcasecmp_natural(entry1->name, entry2->name);
521  if (order) {
522  return order;
523  }
524  }
525 
526  /* Case 2. */
527  if (entry1->local_data.id && entry2->local_data.id) {
528  if (entry1->blentype < entry2->blentype) {
529  return -1;
530  }
531  if (entry1->blentype > entry2->blentype) {
532  return 1;
533  }
534  }
535  /* Case 3. */
536  {
537  if (entry1->local_data.id && !entry2->local_data.id) {
538  return -1;
539  }
540  if (!entry1->local_data.id && entry2->local_data.id) {
541  return 1;
542  }
543  }
544 
545  return 0;
546 }
547 
553  const FileListInternEntry *entry2)
554 {
555  /* type is equal to stat.st_mode */
556 
557  if (entry1->typeflag & FILE_TYPE_DIR) {
558  if (entry2->typeflag & FILE_TYPE_DIR) {
559  /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs,
560  * then libs (.blend files), then categories in libs. */
561  if (entry1->typeflag & FILE_TYPE_BLENDERLIB) {
562  if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
563  return 1;
564  }
565  }
566  else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) {
567  return -1;
568  }
569  else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
570  if (!(entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
571  return 1;
572  }
573  }
574  else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
575  return -1;
576  }
577  }
578  else {
579  return -1;
580  }
581  }
582  else if (entry2->typeflag & FILE_TYPE_DIR) {
583  return 1;
584  }
585 
586  /* make sure "." and ".." are always first */
587  if (FILENAME_IS_CURRENT(entry1->relpath)) {
588  return -1;
589  }
590  if (FILENAME_IS_CURRENT(entry2->relpath)) {
591  return 1;
592  }
593  if (FILENAME_IS_PARENT(entry1->relpath)) {
594  return -1;
595  }
596  if (FILENAME_IS_PARENT(entry2->relpath)) {
597  return 1;
598  }
599 
600  return 0;
601 }
602 
603 static int compare_name(void *user_data, const void *a1, const void *a2)
604 {
605  const FileListInternEntry *entry1 = a1;
606  const FileListInternEntry *entry2 = a2;
607  const struct FileSortData *sort_data = user_data;
608 
609  int ret;
610  if ((ret = compare_direntry_generic(entry1, entry2))) {
611  return ret;
612  }
613 
614  return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
615 }
616 
617 static int compare_date(void *user_data, const void *a1, const void *a2)
618 {
619  const FileListInternEntry *entry1 = a1;
620  const FileListInternEntry *entry2 = a2;
621  const struct FileSortData *sort_data = user_data;
622  int64_t time1, time2;
623 
624  int ret;
625  if ((ret = compare_direntry_generic(entry1, entry2))) {
626  return ret;
627  }
628 
629  time1 = (int64_t)entry1->st.st_mtime;
630  time2 = (int64_t)entry2->st.st_mtime;
631  if (time1 < time2) {
632  return compare_apply_inverted(1, sort_data);
633  }
634  if (time1 > time2) {
635  return compare_apply_inverted(-1, sort_data);
636  }
637 
638  return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
639 }
640 
641 static int compare_size(void *user_data, const void *a1, const void *a2)
642 {
643  const FileListInternEntry *entry1 = a1;
644  const FileListInternEntry *entry2 = a2;
645  const struct FileSortData *sort_data = user_data;
646  uint64_t size1, size2;
647  int ret;
648 
649  if ((ret = compare_direntry_generic(entry1, entry2))) {
650  return ret;
651  }
652 
653  size1 = entry1->st.st_size;
654  size2 = entry2->st.st_size;
655  if (size1 < size2) {
656  return compare_apply_inverted(1, sort_data);
657  }
658  if (size1 > size2) {
659  return compare_apply_inverted(-1, sort_data);
660  }
661 
662  return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
663 }
664 
665 static int compare_extension(void *user_data, const void *a1, const void *a2)
666 {
667  const FileListInternEntry *entry1 = a1;
668  const FileListInternEntry *entry2 = a2;
669  const struct FileSortData *sort_data = user_data;
670  int ret;
671 
672  if ((ret = compare_direntry_generic(entry1, entry2))) {
673  return ret;
674  }
675 
676  if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
677  return -1;
678  }
679  if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
680  return 1;
681  }
682  if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
683  if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) {
684  return 1;
685  }
686  if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) {
687  return -1;
688  }
689  if (entry1->blentype < entry2->blentype) {
690  return compare_apply_inverted(-1, sort_data);
691  }
692  if (entry1->blentype > entry2->blentype) {
693  return compare_apply_inverted(1, sort_data);
694  }
695  }
696  else {
697  const char *sufix1, *sufix2;
698 
699  if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) {
700  sufix1 = strrchr(entry1->relpath, '.');
701  }
702  if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) {
703  sufix2 = strrchr(entry2->relpath, '.');
704  }
705  if (!sufix1) {
706  sufix1 = "";
707  }
708  if (!sufix2) {
709  sufix2 = "";
710  }
711 
712  if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
713  return compare_apply_inverted(ret, sort_data);
714  }
715  }
716 
717  return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
718 }
719 
720 void filelist_sort(struct FileList *filelist)
721 {
722  if (filelist->flags & FL_NEED_SORTING) {
723  void *sort_cb = NULL;
724 
725  switch (filelist->sort) {
726  case FILE_SORT_ALPHA:
727  sort_cb = compare_name;
728  break;
729  case FILE_SORT_TIME:
730  sort_cb = compare_date;
731  break;
732  case FILE_SORT_SIZE:
733  sort_cb = compare_size;
734  break;
735  case FILE_SORT_EXTENSION:
736  sort_cb = compare_extension;
737  break;
738  case FILE_SORT_DEFAULT:
739  default:
740  BLI_assert(0);
741  break;
742  }
744  &filelist->filelist_intern.entries,
745  sort_cb,
746  &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0});
747 
749  filelist->flags &= ~FL_NEED_SORTING;
750  }
751 }
752 
753 void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
754 {
755  const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
756 
757  if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
758  filelist->sort = sort;
759  filelist->flags |= FL_NEED_SORTING;
760  filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
761  (filelist->flags & ~FL_SORT_INVERT);
762  }
763 }
764 
765 /* ********** Filter helpers ********** */
766 
767 /* True if filename is meant to be hidden, eg. starting with period. */
768 static bool is_hidden_dot_filename(const char *filename, const FileListInternEntry *file)
769 {
770  if (filename[0] == '.' && !ELEM(filename[1], '.', '\0')) {
771  return true; /* ignore .file */
772  }
773 
774  int len = strlen(filename);
775  if ((len > 0) && (filename[len - 1] == '~')) {
776  return true; /* ignore file~ */
777  }
778 
779  /* filename might actually be a piece of path, in which case we have to check all its parts. */
780 
781  bool hidden = false;
782  char *sep = (char *)BLI_path_slash_rfind(filename);
783 
784  if (!hidden && sep) {
785  char tmp_filename[FILE_MAX_LIBEXTRA];
786 
787  BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename));
788  sep = tmp_filename + (sep - filename);
789  while (sep) {
790  /* This happens when a path contains 'ALTSEP', '\' on Unix for e.g.
791  * Supporting alternate slashes in paths is a bigger task involving changes
792  * in many parts of the code, for now just prevent an assert, see T74579. */
793 #if 0
794  BLI_assert(sep[1] != '\0');
795 #endif
796  if (is_hidden_dot_filename(sep + 1, file)) {
797  hidden = true;
798  break;
799  }
800  *sep = '\0';
801  sep = (char *)BLI_path_slash_rfind(tmp_filename);
802  }
803  }
804  return hidden;
805 }
806 
807 /* True if should be hidden, based on current filtering. */
808 static bool is_filtered_hidden(const char *filename,
809  const FileListFilter *filter,
810  const FileListInternEntry *file)
811 {
812  if ((filename[0] == '.') && (filename[1] == '\0')) {
813  return true; /* Ignore. */
814  }
815 
816  if (filter->flags & FLF_HIDE_PARENT) {
817  if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
818  return true; /* Ignore. */
819  }
820  }
821 
822  if ((filter->flags & FLF_HIDE_DOT) && (file->attributes & FILE_ATTR_HIDDEN)) {
823  return true; /* Ignore files with Hidden attribute. */
824  }
825 
826 #ifndef WIN32
827  /* Check for unix-style names starting with period. */
828  if ((filter->flags & FLF_HIDE_DOT) && is_hidden_dot_filename(filename, file)) {
829  return true;
830  }
831 #endif
832  /* For data-blocks (but not the group directories), check the asset-only filter. */
833  if (!(file->typeflag & FILE_TYPE_DIR) && (file->typeflag & FILE_TYPE_BLENDERLIB) &&
834  (filter->flags & FLF_ASSETS_ONLY) && !(file->typeflag & FILE_TYPE_ASSET)) {
835  return true;
836  }
837 
838  return false;
839 }
840 
846 {
847  if (filter->filter_search[0] == '\0') {
848  return true;
849  }
850 
851  /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
852  return fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) == 0;
853 }
854 
860 {
861  if (filter->filter_search[0] == '\0') {
862  return true;
863  }
864 
865  /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
866  return fnmatch(filter->filter_search, file->name, FNM_CASEFOLD) == 0;
867 }
868 
871 {
872  if (is_filtered_hidden(file->relpath, filter, file)) {
873  return false;
874  }
875 
876  if (FILENAME_IS_CURRPAR(file->relpath)) {
877  return false;
878  }
879 
880  /* We only check for types if some type are enabled in filtering. */
881  if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
882  if (file->typeflag & FILE_TYPE_DIR) {
884  if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) {
885  return false;
886  }
887  }
888  else {
889  if (!(filter->filter & FILE_TYPE_FOLDER)) {
890  return false;
891  }
892  }
893  }
894  else {
895  if (!(file->typeflag & filter->filter)) {
896  return false;
897  }
898  }
899  }
900  return true;
901 }
902 
905  const char *UNUSED(root),
907 {
908  return is_filtered_file_type(file, filter) &&
910 }
911 
913  const char *id_group,
914  const char *name,
915  const FileListFilter *filter)
916 {
918  return false;
919  }
920 
921  /* We only check for types if some type are enabled in filtering. */
922  if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
923  if (id_group) {
924  if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
925  return false;
926  }
927 
928  uint64_t filter_id = groupname_to_filter_id(id_group);
929  if (!(filter_id & filter->filter_id)) {
930  return false;
931  }
932  }
933  }
934 
935  return true;
936 }
937 
943 {
944  const ID *local_id = file->local_data.id;
945  return local_id ? local_id->asset_data : file->imported_asset_data;
946 }
947 
949 {
950  /* Not used yet for the asset view template. */
951  if (!filter->asset_catalog_filter) {
952  return;
953  }
954  BLI_assert_msg(filelist->asset_library,
955  "prepare_filter_asset_library() should only be called when the file browser is "
956  "in asset browser mode");
957 
958  file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library);
959 }
960 
973 static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data)
974 {
975  LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) {
976  if (BLI_strcasestr(asset_tag->name, filter_search) != NULL) {
977  return true;
978  }
979  }
980  return false;
981 }
982 
984 {
986 
987  /* Not used yet for the asset view template. */
988  if (filter->asset_catalog_filter && !file_is_asset_visible_in_catalog_filter_settings(
989  filter->asset_catalog_filter, asset_data)) {
990  return false;
991  }
992 
993  if (filter->filter_search[0] == '\0') {
994  /* If there is no filter text, everything matches. */
995  return true;
996  }
997 
998  /* filter->filter_search contains "*the search text*". */
999  char filter_search[66]; /* sizeof(FileListFilter::filter_search) */
1000  const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search);
1001 
1002  /* When doing a name comparison, get rid of the leading/trailing asterisks. */
1003  filter_search[string_length - 1] = '\0';
1004  if (BLI_strcasestr(file->name, filter_search + 1) != NULL) {
1005  return true;
1006  }
1007  return asset_tag_matches_filter(filter_search + 1, asset_data);
1008 }
1009 
1011  const char *root,
1013 {
1014  char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name;
1015 
1016  BLI_join_dirfile(path, sizeof(path), root, file->relpath);
1017 
1018  if (BLO_library_path_explode(path, dir, &group, &name)) {
1019  return is_filtered_id_file_type(file, group, name, filter);
1020  }
1022 }
1023 
1025 {
1027 }
1028 
1030  const char *UNUSED(dir),
1032 {
1033  return !is_filtered_hidden(file->relpath, filter, file);
1034 }
1035 
1037  const char *UNUSED(dir),
1039 {
1040  /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
1041  return is_filtered_id_file_type(file, file->relpath, file->name, filter) &&
1043 }
1044 
1046  const char *root,
1048 {
1050  return is_filtered_main_assets(file, root, filter);
1051  }
1052 
1054 }
1055 
1057 {
1058  filelist->flags |= FL_NEED_FILTERING;
1059 }
1060 
1061 void filelist_filter(FileList *filelist)
1062 {
1063  int num_filtered = 0;
1064  const int num_files = filelist->filelist.entries_num;
1065  FileListInternEntry **filtered_tmp, *file;
1066 
1067  if (ELEM(filelist->filelist.entries_num, FILEDIR_NBR_ENTRIES_UNSET, 0)) {
1068  return;
1069  }
1070 
1071  if (!(filelist->flags & FL_NEED_FILTERING)) {
1072  /* Assume it has already been filtered, nothing else to do! */
1073  return;
1074  }
1075 
1076  filelist->filter_data.flags &= ~FLF_HIDE_LIB_DIR;
1077  if (filelist->max_recursion) {
1078  /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
1079  * root path is a blend file. */
1080  char dir[FILE_MAX_LIBEXTRA];
1081  if (!filelist_islibrary(filelist, dir, NULL)) {
1082  filelist->filter_data.flags |= FLF_HIDE_LIB_DIR;
1083  }
1084  }
1085 
1086  if (filelist->prepare_filter_fn) {
1087  filelist->prepare_filter_fn(filelist, &filelist->filter_data);
1088  }
1089 
1090  filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__);
1091 
1092  /* Filter remap & count how many files are left after filter in a single loop. */
1093  for (file = filelist->filelist_intern.entries.first; file; file = file->next) {
1094  if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) {
1095  filtered_tmp[num_filtered++] = file;
1096  }
1097  }
1098 
1099  if (filelist->filelist_intern.filtered) {
1100  MEM_freeN(filelist->filelist_intern.filtered);
1101  }
1102  filelist->filelist_intern.filtered = MEM_mallocN(
1103  sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, __func__);
1104  memcpy(filelist->filelist_intern.filtered,
1105  filtered_tmp,
1106  sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered);
1107  filelist->filelist.entries_filtered_num = num_filtered;
1108  // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.entries_num);
1109 
1110  filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
1111  filelist->flags &= ~FL_NEED_FILTERING;
1112 
1113  MEM_freeN(filtered_tmp);
1114 }
1115 
1117  const bool do_filter,
1118  const bool hide_dot,
1119  const bool hide_parent,
1120  const uint64_t filter,
1121  const uint64_t filter_id,
1122  const bool filter_assets_only,
1123  const char *filter_glob,
1124  const char *filter_search)
1125 {
1126  bool update = false;
1127 
1128  if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) {
1129  filelist->filter_data.flags ^= FLF_DO_FILTER;
1130  update = true;
1131  }
1132  if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) {
1133  filelist->filter_data.flags ^= FLF_HIDE_DOT;
1134  update = true;
1135  }
1136  if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) {
1137  filelist->filter_data.flags ^= FLF_HIDE_PARENT;
1138  update = true;
1139  }
1140  if (((filelist->filter_data.flags & FLF_ASSETS_ONLY) != 0) != (filter_assets_only != 0)) {
1141  filelist->filter_data.flags ^= FLF_ASSETS_ONLY;
1142  update = true;
1143  }
1144  if (filelist->filter_data.filter != filter) {
1145  filelist->filter_data.filter = filter;
1146  update = true;
1147  }
1148  const uint64_t new_filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL;
1149  if (filelist->filter_data.filter_id != new_filter_id) {
1150  filelist->filter_data.filter_id = new_filter_id;
1151  update = true;
1152  }
1153  if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) {
1154  BLI_strncpy(
1155  filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob));
1156  update = true;
1157  }
1158  if ((BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0)) {
1160  filter_search,
1161  '*',
1162  sizeof(filelist->filter_data.filter_search));
1163  update = true;
1164  }
1165 
1166  if (update) {
1167  /* And now, free filtered data so that we know we have to filter again. */
1168  filelist_tag_needs_filtering(filelist);
1169  }
1170 }
1171 
1172 void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
1173 {
1174  BLI_assert(filelist);
1175  BLI_assert(indexer);
1176 
1177  filelist->indexer = indexer;
1178 }
1179 
1181  FileList *filelist,
1182  eFileSel_Params_AssetCatalogVisibility catalog_visibility,
1183  const bUUID *catalog_id)
1184 {
1185  if (!filelist->filter_data.asset_catalog_filter) {
1186  /* There's no filter data yet. */
1188  }
1189 
1190  const bool needs_update = file_set_asset_catalog_filter_settings(
1191  filelist->filter_data.asset_catalog_filter, catalog_visibility, *catalog_id);
1192 
1193  if (needs_update) {
1194  filelist_tag_needs_filtering(filelist);
1195  }
1196 }
1197 
1203  const AssetLibraryReference *library_b)
1204 {
1205  if (library_a->type != library_b->type) {
1206  return false;
1207  }
1208  if (library_a->type == ASSET_LIBRARY_CUSTOM) {
1209  /* Don't only check the index, also check that it's valid. */
1211  &U, library_a->custom_library_index);
1212  return (library_ptr_a != NULL) &&
1213  (library_a->custom_library_index == library_b->custom_library_index);
1214  }
1215 
1216  return true;
1217 }
1218 
1219 void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
1220 {
1221  /* Unset if needed. */
1222  if (!asset_library_ref) {
1223  if (filelist->asset_library_ref) {
1224  MEM_SAFE_FREE(filelist->asset_library_ref);
1225  filelist->flags |= FL_FORCE_RESET;
1226  }
1227  return;
1228  }
1229 
1230  if (!filelist->asset_library_ref) {
1231  filelist->asset_library_ref = MEM_mallocN(sizeof(*filelist->asset_library_ref),
1232  "filelist asset library");
1233  *filelist->asset_library_ref = *asset_library_ref;
1234 
1235  filelist->flags |= FL_FORCE_RESET;
1236  }
1237  else if (!filelist_compare_asset_libraries(filelist->asset_library_ref, asset_library_ref)) {
1238  *filelist->asset_library_ref = *asset_library_ref;
1239  filelist->flags |= FL_FORCE_RESET;
1240  }
1241 }
1242 
1243 /* ********** Icon/image helpers ********** */
1244 
1246 {
1247  short x, y, k;
1248  ImBuf *bbuf;
1249  ImBuf *ibuf;
1250 
1251  BLI_assert(G.background == false);
1252 
1253 #ifdef WITH_HEADLESS
1254  bbuf = NULL;
1255 #else
1256  bbuf = IMB_ibImageFromMemory(
1258 #endif
1259  if (bbuf) {
1260  for (y = 0; y < SPECIAL_IMG_ROWS; y++) {
1261  for (x = 0; x < SPECIAL_IMG_COLS; x++) {
1262  int tile = SPECIAL_IMG_COLS * y + x;
1263  if (tile < SPECIAL_IMG_MAX) {
1265  for (k = 0; k < SPECIAL_IMG_SIZE; k++) {
1266  memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE],
1268  x * SPECIAL_IMG_SIZE],
1269  SPECIAL_IMG_SIZE * sizeof(int));
1270  }
1271  gSpecialFileImages[tile] = ibuf;
1272  }
1273  }
1274  }
1275  IMB_freeImBuf(bbuf);
1276  }
1277 }
1278 
1280 {
1281  BLI_assert(G.background == false);
1282 
1283  for (int i = 0; i < SPECIAL_IMG_MAX; i++) {
1285  gSpecialFileImages[i] = NULL;
1286  }
1287 }
1288 
1289 static FileDirEntry *filelist_geticon_get_file(struct FileList *filelist, const int index)
1290 {
1291  BLI_assert(G.background == false);
1292 
1293  return filelist_file(filelist, index);
1294 }
1295 
1296 ImBuf *filelist_getimage(struct FileList *filelist, const int index)
1297 {
1298  FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1299 
1300  return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
1301 }
1302 
1304 {
1305  return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
1306 }
1307 
1309 {
1310  ImBuf *ibuf = NULL;
1311 
1312  if (file->typeflag & FILE_TYPE_DIR) {
1313  if (FILENAME_IS_PARENT(file->relpath)) {
1315  }
1316  else {
1318  }
1319  }
1320  else {
1322  }
1323 
1324  return ibuf;
1325 }
1326 
1327 ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
1328 {
1329  FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1331 }
1332 
1334  const char *root,
1335  const bool is_main,
1336  const bool ignore_libdir)
1337 {
1338  const eFileSel_File_Types typeflag = file->typeflag;
1339 
1340  if ((typeflag & FILE_TYPE_DIR) &&
1341  !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) {
1342  if (FILENAME_IS_PARENT(file->relpath)) {
1343  return is_main ? ICON_FILE_PARENT : ICON_NONE;
1344  }
1345  if (typeflag & FILE_TYPE_BUNDLE) {
1346  return ICON_UGLYPACKAGE;
1347  }
1348  if (typeflag & FILE_TYPE_BLENDER) {
1349  return ICON_FILE_BLEND;
1350  }
1351  if (is_main) {
1352  /* Do not return icon for folders if icons are not 'main' draw type
1353  * (e.g. when used over previews). */
1354  return (file->attributes & FILE_ATTR_ANY_LINK) ? ICON_FOLDER_REDIRECT : ICON_FILE_FOLDER;
1355  }
1356 
1357  /* If this path is in System list or path cache then use that icon. */
1358  struct FSMenu *fsmenu = ED_fsmenu_get();
1359  FSMenuCategory categories[] = {
1363  };
1364 
1365  for (int i = 0; i < ARRAY_SIZE(categories); i++) {
1366  FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]);
1367  char fullpath[FILE_MAX_LIBEXTRA];
1368  char *target = fullpath;
1369  if (file->redirection_path) {
1370  target = file->redirection_path;
1371  }
1372  else if (root) {
1373  BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
1374  BLI_path_slash_ensure(fullpath);
1375  }
1376  for (; tfsm; tfsm = tfsm->next) {
1377  if (STREQ(tfsm->path, target)) {
1378  /* Never want a little folder inside a large one. */
1379  return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
1380  }
1381  }
1382  }
1383 
1384  if (file->attributes & FILE_ATTR_OFFLINE) {
1385  return ICON_ERROR;
1386  }
1387  if (file->attributes & FILE_ATTR_TEMPORARY) {
1388  return ICON_FILE_CACHE;
1389  }
1390  if (file->attributes & FILE_ATTR_SYSTEM) {
1391  return ICON_SYSTEM;
1392  }
1393  }
1394 
1395  if (typeflag & FILE_TYPE_BLENDER) {
1396  return (is_main || file->preview_icon_id) ? ICON_FILE_BLEND : ICON_BLENDER;
1397  }
1398  if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
1399  return ICON_FILE_BACKUP;
1400  }
1401  if (typeflag & FILE_TYPE_IMAGE) {
1402  return ICON_FILE_IMAGE;
1403  }
1404  if (typeflag & FILE_TYPE_MOVIE) {
1405  return ICON_FILE_MOVIE;
1406  }
1407  if (typeflag & FILE_TYPE_PYSCRIPT) {
1408  return ICON_FILE_SCRIPT;
1409  }
1410  if (typeflag & FILE_TYPE_SOUND) {
1411  return ICON_FILE_SOUND;
1412  }
1413  if (typeflag & FILE_TYPE_FTFONT) {
1414  return ICON_FILE_FONT;
1415  }
1416  if (typeflag & FILE_TYPE_BTX) {
1417  return ICON_FILE_BLANK;
1418  }
1419  if (typeflag & FILE_TYPE_COLLADA) {
1420  return ICON_FILE_3D;
1421  }
1422  if (typeflag & FILE_TYPE_ALEMBIC) {
1423  return ICON_FILE_3D;
1424  }
1425  if (typeflag & FILE_TYPE_USD) {
1426  return ICON_FILE_3D;
1427  }
1428  if (typeflag & FILE_TYPE_VOLUME) {
1429  return ICON_FILE_VOLUME;
1430  }
1431  if (typeflag & FILE_TYPE_OBJECT_IO) {
1432  return ICON_FILE_3D;
1433  }
1434  if (typeflag & FILE_TYPE_TEXT) {
1435  return ICON_FILE_TEXT;
1436  }
1437  if (typeflag & FILE_TYPE_ARCHIVE) {
1438  return ICON_FILE_ARCHIVE;
1439  }
1440  if (typeflag & FILE_TYPE_BLENDERLIB) {
1441  const int ret = UI_icon_from_idcode(file->blentype);
1442  if (ret != ICON_NONE) {
1443  return ret;
1444  }
1445  }
1446  return is_main ? ICON_FILE_BLANK : ICON_NONE;
1447 }
1448 
1449 int filelist_geticon(struct FileList *filelist, const int index, const bool is_main)
1450 {
1451  FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1452 
1453  return filelist_geticon_ex(file, filelist->filelist.root, is_main, false);
1454 }
1455 
1457 {
1458  return file->preview_icon_id ? file->preview_icon_id :
1459  filelist_geticon_ex(file, NULL, false, false);
1460 }
1461 
1463 {
1464  return intern_entry->local_data.id != NULL;
1465 }
1466 
1467 /* ********** Main ********** */
1468 
1470 {
1472 #ifdef WIN32
1474 #else
1475  strcpy(dir, "/");
1476 #endif
1477  }
1478 }
1479 
1480 static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist),
1481  char *r_dir,
1482  const bool do_change)
1483 {
1484  if (do_change) {
1486  return true;
1487  }
1488  return BLI_is_dir(r_dir);
1489 }
1490 
1491 static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist),
1492  char *r_dir,
1493  const bool do_change)
1494 {
1495  char tdir[FILE_MAX_LIBEXTRA];
1496  char *name;
1497 
1498  const bool is_valid = (BLI_is_dir(r_dir) ||
1499  (BLO_library_path_explode(r_dir, tdir, NULL, &name) &&
1500  BLI_is_file(tdir) && !name));
1501 
1502  if (do_change && !is_valid) {
1503  /* if not a valid library, we need it to be a valid directory! */
1505  return true;
1506  }
1507  return is_valid;
1508 }
1509 
1510 static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
1511 {
1512  /* TODO */
1513  return filelist_checkdir_lib(filelist, r_dir, do_change);
1514 }
1515 
1516 static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist),
1517  char *UNUSED(r_dir),
1518  const bool UNUSED(do_change))
1519 {
1520  /* Main is always valid. */
1521  return true;
1522 }
1523 
1525 {
1526  if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) {
1527  MEM_freeN(entry->name);
1528  }
1529  if (entry->relpath) {
1530  MEM_freeN(entry->relpath);
1531  }
1532  if (entry->redirection_path) {
1533  MEM_freeN(entry->redirection_path);
1534  }
1535  if (entry->preview_icon_id) {
1537  entry->preview_icon_id = 0;
1538  }
1539 }
1540 
1542 {
1543  filelist_entry_clear(entry);
1544  MEM_freeN(entry);
1545 }
1546 
1548 {
1549 #if 0
1550  FileDirEntry *entry, *entry_next;
1551 
1552  for (entry = array->entries.first; entry; entry = entry_next) {
1553  entry_next = entry->next;
1554  filelist_entry_free(entry);
1555  }
1556  BLI_listbase_clear(&array->entries);
1557 #else
1559 #endif
1560  array->entries_num = FILEDIR_NBR_ENTRIES_UNSET;
1561  array->entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
1562 }
1563 
1565 {
1566  if (entry->relpath) {
1567  MEM_freeN(entry->relpath);
1568  }
1569  if (entry->redirection_path) {
1570  MEM_freeN(entry->redirection_path);
1571  }
1572  if (entry->name && entry->free_name) {
1573  MEM_freeN(entry->name);
1574  }
1575  /* If we own the asset-data (it was generated from external file data), free it. */
1576  if (entry->imported_asset_data) {
1578  }
1579  MEM_freeN(entry);
1580 }
1581 
1582 static void filelist_intern_free(FileListIntern *filelist_intern)
1583 {
1584  FileListInternEntry *entry, *entry_next;
1585 
1586  for (entry = filelist_intern->entries.first; entry; entry = entry_next) {
1587  entry_next = entry->next;
1589  }
1590  BLI_listbase_clear(&filelist_intern->entries);
1591 
1592  MEM_SAFE_FREE(filelist_intern->filtered);
1593 }
1594 
1599 {
1600  int removed_counter = 0;
1601  LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
1602  if (!filelist_intern_entry_is_main_file(entry)) {
1603  continue;
1604  }
1605 
1606  BLI_remlink(&filelist_intern->entries, entry);
1608  removed_counter++;
1609  }
1610 
1611  MEM_SAFE_FREE(filelist_intern->filtered);
1612  return removed_counter;
1613 }
1614 
1615 static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
1616 {
1618  FileListEntryPreviewTaskData *preview_taskdata = taskdata;
1619  FileListEntryPreview *preview = preview_taskdata->preview;
1620 
1621  ThumbSource source = 0;
1622 
1623  // printf("%s: Start (%d)...\n", __func__, threadid);
1624 
1625  // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
1626  BLI_assert(preview->flags &
1629 
1630  if (preview->flags & FILE_TYPE_IMAGE) {
1631  source = THB_SOURCE_IMAGE;
1632  }
1633  else if (preview->flags &
1635  source = THB_SOURCE_BLEND;
1636  }
1637  else if (preview->flags & FILE_TYPE_MOVIE) {
1638  source = THB_SOURCE_MOVIE;
1639  }
1640  else if (preview->flags & FILE_TYPE_FTFONT) {
1641  source = THB_SOURCE_FONT;
1642  }
1643 
1644  IMB_thumb_path_lock(preview->filepath);
1645  /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
1646  * in case user switch to a bigger preview size. Do not create preview when file is offline. */
1647  ImBuf *imbuf = (preview->attributes & FILE_ATTR_OFFLINE) ?
1648  IMB_thumb_read(preview->filepath, THB_LARGE) :
1649  IMB_thumb_manage(preview->filepath, THB_LARGE, source);
1650  IMB_thumb_path_unlock(preview->filepath);
1651  if (imbuf) {
1652  preview->icon_id = BKE_icon_imbuf_create(imbuf);
1653  }
1654 
1655  /* Move ownership to the done queue. */
1656  preview_taskdata->preview = NULL;
1657 
1659 
1660  // printf("%s: End (%d)...\n", __func__, threadid);
1661 }
1662 
1663 static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
1664 {
1665  FileListEntryPreviewTaskData *preview_taskdata = taskdata;
1666 
1667  /* In case the preview wasn't moved to the "done" queue yet. */
1668  if (preview_taskdata->preview) {
1669  MEM_freeN(preview_taskdata->preview);
1670  }
1671 
1672  MEM_freeN(preview_taskdata);
1673 }
1674 
1676 {
1677  if (!cache->previews_pool) {
1680  cache->previews_todo_count = 0;
1681 
1683  }
1684 }
1685 
1687 {
1688  if (cache->previews_pool) {
1690 
1692  while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
1693  // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
1694  // preview->img);
1695  if (preview->icon_id) {
1696  BKE_icon_delete(preview->icon_id);
1697  }
1698  MEM_freeN(preview);
1699  }
1700  cache->previews_todo_count = 0;
1701  }
1702 }
1703 
1705 {
1706  if (cache->previews_pool) {
1708 
1710 
1713  cache->previews_pool = NULL;
1714  cache->previews_done = NULL;
1715  cache->previews_todo_count = 0;
1716 
1718  }
1719 
1720  cache->flags &= ~FLC_PREVIEWS_ACTIVE;
1721 }
1722 
1723 static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
1724 {
1725  FileListEntryCache *cache = &filelist->filelist_cache;
1726 
1728 
1729  if (entry->preview_icon_id) {
1730  return;
1731  }
1732 
1734  return;
1735  }
1736 
1739  return;
1740  }
1741 
1742  FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
1743  PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
1744  if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
1745  /* Nothing to set yet. Wait for next call. */
1746  return;
1747  }
1748 
1751 
1752  FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
1753  preview->index = index;
1754  preview->flags = entry->typeflag;
1755  preview->attributes = entry->attributes;
1756  preview->icon_id = 0;
1757 
1758  if (preview_in_memory) {
1759  /* TODO(mano-wii): No need to use the thread API here. */
1761  preview->filepath[0] = '\0';
1762  ImBuf *imbuf = BKE_previewimg_to_imbuf(preview_in_memory, ICON_SIZE_PREVIEW);
1763  if (imbuf) {
1764  preview->icon_id = BKE_icon_imbuf_create(imbuf);
1765  }
1767  }
1768  else {
1769  if (entry->redirection_path) {
1770  BLI_strncpy(preview->filepath, entry->redirection_path, FILE_MAXDIR);
1771  }
1772  else {
1774  preview->filepath, sizeof(preview->filepath), filelist->filelist.root, entry->relpath);
1775  }
1776  // printf("%s: %d - %s\n", __func__, preview->index, preview->filepath);
1777 
1778  FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
1779  __func__);
1780  preview_taskdata->preview = preview;
1783  preview_taskdata,
1784  true,
1786  }
1787  cache->previews_todo_count++;
1788 }
1789 
1790 static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
1791 {
1793 
1794  cache->block_cursor = cache->block_start_index = cache->block_center_index =
1795  cache->block_end_index = 0;
1796  cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__);
1797 
1798  cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size);
1799  cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size,
1800  __func__);
1801  copy_vn_i(cache->misc_entries_indices, cache_size, -1);
1802  cache->misc_cursor = 0;
1803 
1804  cache->uids = BLI_ghash_new_ex(
1805  BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__, cache_size * 2);
1806 
1807  cache->size = cache_size;
1808  cache->flags = FLC_IS_INIT;
1809 
1810  cache->previews_todo_count = 0;
1811 
1812  /* We cannot translate from non-main thread, so init translated strings once from here. */
1814 }
1815 
1817 {
1818  FileDirEntry *entry, *entry_next;
1819 
1820  if (!(cache->flags & FLC_IS_INIT)) {
1821  return;
1822  }
1823 
1825 
1826  MEM_freeN(cache->block_entries);
1827 
1830 
1831  BLI_ghash_free(cache->uids, NULL, NULL);
1832 
1833  for (entry = cache->cached_entries.first; entry; entry = entry_next) {
1834  entry_next = entry->next;
1835  filelist_entry_free(entry);
1836  }
1838 }
1839 
1840 static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
1841 {
1842  FileDirEntry *entry, *entry_next;
1843 
1844  if (!(cache->flags & FLC_IS_INIT)) {
1845  return;
1846  }
1847 
1849 
1850  cache->block_cursor = cache->block_start_index = cache->block_center_index =
1851  cache->block_end_index = 0;
1852  if (new_size != cache->size) {
1853  cache->block_entries = MEM_reallocN(cache->block_entries,
1854  sizeof(*cache->block_entries) * new_size);
1855  }
1856 
1857  BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size);
1858  if (new_size != cache->size) {
1860  sizeof(*cache->misc_entries_indices) * new_size);
1861  }
1862  copy_vn_i(cache->misc_entries_indices, new_size, -1);
1863 
1864  BLI_ghash_clear_ex(cache->uids, NULL, NULL, new_size * 2);
1865 
1866  cache->size = new_size;
1867 
1868  for (entry = cache->cached_entries.first; entry; entry = entry_next) {
1869  entry_next = entry->next;
1870  filelist_entry_free(entry);
1871  }
1873 }
1874 
1876 {
1877  FileList *p = MEM_callocN(sizeof(*p), __func__);
1878 
1880 
1883  filelist_settype(p, type);
1884 
1885  return p;
1886 }
1887 
1888 void filelist_settype(FileList *filelist, short type)
1889 {
1890  if (filelist->type == type) {
1891  return;
1892  }
1893 
1894  filelist->type = type;
1895  filelist->tags = 0;
1896  filelist->indexer = &file_indexer_noop;
1897  switch (filelist->type) {
1898  case FILE_MAIN:
1900  filelist->read_job_fn = filelist_readjob_main;
1901  filelist->prepare_filter_fn = NULL;
1902  filelist->filter_fn = is_filtered_main;
1903  break;
1904  case FILE_LOADLIB:
1905  filelist->check_dir_fn = filelist_checkdir_lib;
1906  filelist->read_job_fn = filelist_readjob_lib;
1907  filelist->prepare_filter_fn = NULL;
1908  filelist->filter_fn = is_filtered_lib;
1909  break;
1910  case FILE_ASSET_LIBRARY:
1911  filelist->check_dir_fn = filelist_checkdir_lib;
1915  filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA;
1916  break;
1917  case FILE_MAIN_ASSET:
1921  filelist->filter_fn = is_filtered_main_assets;
1923  break;
1924  default:
1925  filelist->check_dir_fn = filelist_checkdir_dir;
1926  filelist->read_job_fn = filelist_readjob_dir;
1927  filelist->prepare_filter_fn = NULL;
1928  filelist->filter_fn = is_filtered_file;
1929  break;
1930  }
1931 
1932  filelist->flags |= FL_FORCE_RESET;
1933 }
1934 
1936 {
1937  /* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */
1938  filelist->asset_library = NULL;
1940 }
1941 
1942 void filelist_clear_ex(struct FileList *filelist,
1943  const bool do_asset_library,
1944  const bool do_cache,
1945  const bool do_selection)
1946 {
1947  if (!filelist) {
1948  return;
1949  }
1950 
1951  filelist_tag_needs_filtering(filelist);
1952 
1953  if (do_cache) {
1954  filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
1955  }
1956 
1958 
1959  filelist_direntryarr_free(&filelist->filelist);
1960 
1961  if (do_selection && filelist->selection_state) {
1963  }
1964 
1965  if (do_asset_library) {
1966  filelist_clear_asset_library(filelist);
1967  }
1968 }
1969 
1970 static void filelist_clear_main_files(FileList *filelist,
1971  const bool do_asset_library,
1972  const bool do_cache,
1973  const bool do_selection)
1974 {
1975  if (!filelist || !(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) {
1976  return;
1977  }
1978 
1979  filelist_tag_needs_filtering(filelist);
1980 
1981  if (do_cache) {
1982  filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
1983  }
1984 
1985  const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern);
1986 
1987  filelist->filelist.entries_num -= removed_files;
1990 
1991  if (do_selection && filelist->selection_state) {
1993  }
1994 
1995  if (do_asset_library) {
1996  filelist_clear_asset_library(filelist);
1997  }
1998 }
1999 
2000 void filelist_clear(FileList *filelist)
2001 {
2002  filelist_clear_ex(filelist, true, true, true);
2003 }
2004 
2006 {
2007  /* Do a full clear if needed. */
2008  if (filelist->flags & FL_FORCE_RESET) {
2009  filelist_clear(filelist);
2010  return;
2011  }
2012 
2013  if (filelist->flags & FL_FORCE_RESET_MAIN_FILES) {
2014  filelist_clear_main_files(filelist, false, true, false);
2015  return;
2016  }
2017 }
2018 
2019 void filelist_free(struct FileList *filelist)
2020 {
2021  if (!filelist) {
2022  printf("Attempting to delete empty filelist.\n");
2023  return;
2024  }
2025 
2026  /* No need to clear cache & selection_state, we free them anyway. */
2027  filelist_clear_ex(filelist, true, false, false);
2028  filelist_cache_free(&filelist->filelist_cache);
2029 
2030  if (filelist->selection_state) {
2031  BLI_ghash_free(filelist->selection_state, NULL, NULL);
2032  filelist->selection_state = NULL;
2033  }
2034 
2035  MEM_SAFE_FREE(filelist->asset_library_ref);
2036 
2037  memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
2038 
2039  filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
2040 }
2041 
2043 {
2044  return filelist->asset_library;
2045 }
2046 
2047 void filelist_freelib(struct FileList *filelist)
2048 {
2049  if (filelist->libfiledata) {
2051  }
2052  filelist->libfiledata = NULL;
2053 }
2054 
2056 {
2057  return filelist->libfiledata;
2058 }
2059 
2061 {
2062  return filelist->filelist.entries_num;
2063 }
2064 
2065 static char *fileentry_uiname(const char *root,
2066  const char *relpath,
2067  const eFileSel_File_Types typeflag,
2068  char *buff)
2069 {
2070  char *name = NULL;
2071 
2072  if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) {
2073  char abspath[FILE_MAX_LIBEXTRA];
2074  BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
2075  name = BLF_display_name_from_file(abspath);
2076  if (name) {
2077  /* Allocated string, so no need to #BLI_strdup. */
2078  return name;
2079  }
2080  }
2081 
2082  if (typeflag & FILE_TYPE_BLENDERLIB) {
2083  char abspath[FILE_MAX_LIBEXTRA];
2084  char *group;
2085 
2086  BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
2087  BLO_library_path_explode(abspath, buff, &group, &name);
2088  if (!name) {
2089  name = group;
2090  }
2091  }
2092  /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */
2093  if (!name) {
2094  if (typeflag & FILE_TYPE_DIR) {
2095  name = (char *)relpath;
2096  }
2097  else {
2098  name = (char *)BLI_path_basename(relpath);
2099  }
2100  }
2101  BLI_assert(name);
2102 
2103  return BLI_strdup(name);
2104 }
2105 
2106 const char *filelist_dir(struct FileList *filelist)
2107 {
2108  return filelist->filelist.root;
2109 }
2110 
2111 bool filelist_is_dir(struct FileList *filelist, const char *path)
2112 {
2113  return filelist->check_dir_fn(filelist, (char *)path, false);
2114 }
2115 
2116 void filelist_setdir(struct FileList *filelist, char *r_dir)
2117 {
2118  const bool allow_invalid = filelist->asset_library_ref != NULL;
2119  BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
2120 
2122  const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid);
2123  BLI_assert(is_valid_path || allow_invalid);
2124  UNUSED_VARS_NDEBUG(is_valid_path);
2125 
2126  if (!STREQ(filelist->filelist.root, r_dir)) {
2127  BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
2128  filelist->flags |= FL_FORCE_RESET;
2129  }
2130 }
2131 
2132 void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
2133 {
2134  if (filelist->max_recursion != recursion_level) {
2135  filelist->max_recursion = recursion_level;
2136  filelist->flags |= FL_FORCE_RESET;
2137  }
2138 }
2139 
2141 {
2142  return (filelist->flags & (FL_FORCE_RESET | FL_FORCE_RESET_MAIN_FILES)) != 0;
2143 }
2144 
2146 {
2147  filelist->flags |= FL_FORCE_RESET;
2148 }
2149 
2151 {
2152  if (!(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) {
2153  return;
2154  }
2155  filelist->flags |= FL_FORCE_RESET_MAIN_FILES;
2156 }
2157 
2158 bool filelist_is_ready(struct FileList *filelist)
2159 {
2160  return (filelist->flags & FL_IS_READY) != 0;
2161 }
2162 
2163 bool filelist_pending(struct FileList *filelist)
2164 {
2165  return (filelist->flags & FL_IS_PENDING) != 0;
2166 }
2167 
2169 {
2170  return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
2171 }
2172 
2174 {
2175  if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
2176  filelist_sort(filelist);
2177  filelist_filter(filelist);
2178  }
2179 
2180  return filelist->filelist.entries_filtered_num;
2181 }
2182 
2183 static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
2184 {
2185  FileListInternEntry *entry = filelist->filelist_intern.filtered[index];
2186  FileListEntryCache *cache = &filelist->filelist_cache;
2187  FileDirEntry *ret;
2188 
2189  ret = MEM_callocN(sizeof(*ret), __func__);
2190 
2191  ret->size = (uint64_t)entry->st.st_size;
2192  ret->time = (int64_t)entry->st.st_mtime;
2193 
2194  ret->relpath = BLI_strdup(entry->relpath);
2195  if (entry->free_name) {
2196  ret->name = BLI_strdup(entry->name);
2197  ret->flags |= FILE_ENTRY_NAME_FREE;
2198  }
2199  else {
2200  ret->name = entry->name;
2201  }
2202  ret->uid = entry->uid;
2203  ret->blentype = entry->blentype;
2204  ret->typeflag = entry->typeflag;
2205  ret->attributes = entry->attributes;
2206  if (entry->redirection_path) {
2207  ret->redirection_path = BLI_strdup(entry->redirection_path);
2208  }
2209  ret->id = entry->local_data.id;
2210  ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : NULL;
2211  if (ret->id && (ret->asset_data == NULL)) {
2212  ret->asset_data = ret->id->asset_data;
2213  }
2214  /* For some file types the preview is already available. */
2215  if (entry->local_data.preview_image &&
2218  if (ibuf) {
2219  ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
2220  }
2221  }
2222  BLI_addtail(&cache->cached_entries, ret);
2223  return ret;
2224 }
2225 
2226 static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
2227 {
2228  BLI_remlink(&filelist->filelist_cache.cached_entries, entry);
2229  filelist_entry_free(entry);
2230 }
2231 
2232 FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
2233 {
2234  FileDirEntry *ret = NULL, *old;
2235  FileListEntryCache *cache = &filelist->filelist_cache;
2236  const size_t cache_size = cache->size;
2237  int old_index;
2238 
2239  if ((index < 0) || (index >= filelist->filelist.entries_filtered_num)) {
2240  return ret;
2241  }
2242 
2243  if (index >= cache->block_start_index && index < cache->block_end_index) {
2244  const int idx = (index - cache->block_start_index + cache->block_cursor) % cache_size;
2245  return cache->block_entries[idx];
2246  }
2247 
2248  if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) {
2249  return ret;
2250  }
2251 
2252  if (!use_request) {
2253  return NULL;
2254  }
2255 
2256  // printf("requesting file %d (not yet cached)\n", index);
2257 
2258  /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */
2259  ret = filelist_file_create_entry(filelist, index);
2260  old_index = cache->misc_entries_indices[cache->misc_cursor];
2261  if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) {
2262  BLI_ghash_remove(cache->uids, POINTER_FROM_UINT(old->uid), NULL, NULL);
2263  filelist_file_release_entry(filelist, old);
2264  }
2266  BLI_ghash_insert(cache->uids, POINTER_FROM_UINT(ret->uid), ret);
2267 
2268  cache->misc_entries_indices[cache->misc_cursor] = index;
2269  cache->misc_cursor = (cache->misc_cursor + 1) % cache_size;
2270 
2271 #if 0 /* Actually no, only block cached entries should have preview IMHO. */
2272  if (cache->previews_pool) {
2273  filelist_cache_previews_push(filelist, ret, index);
2274  }
2275 #endif
2276 
2277  return ret;
2278 }
2279 
2280 FileDirEntry *filelist_file(struct FileList *filelist, int index)
2281 {
2282  return filelist_file_ex(filelist, index, true);
2283 }
2284 
2285 int filelist_file_find_path(struct FileList *filelist, const char *filename)
2286 {
2288  return -1;
2289  }
2290 
2291  /* XXX TODO: Cache could probably use a ghash on paths too? Not really urgent though.
2292  * This is only used to find again renamed entry,
2293  * annoying but looks hairy to get rid of it currently. */
2294 
2295  for (int fidx = 0; fidx < filelist->filelist.entries_filtered_num; fidx++) {
2296  FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
2297  if (STREQ(entry->relpath, filename)) {
2298  return fidx;
2299  }
2300  }
2301 
2302  return -1;
2303 }
2304 
2305 int filelist_file_find_id(const FileList *filelist, const ID *id)
2306 {
2308  return -1;
2309  }
2310 
2311  for (int fidx = 0; fidx < filelist->filelist.entries_filtered_num; fidx++) {
2312  FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
2313  if (entry->local_data.id == id) {
2314  return fidx;
2315  }
2316  }
2317 
2318  return -1;
2319 }
2320 
2322 {
2323  return file->id;
2324 }
2325 
2326 #define FILE_UID_UNSET 0
2327 
2329 {
2330  /* Using an atomic operation to avoid having to lock thread...
2331  * Note that we do not really need this here currently, since there is a single listing thread,
2332  * but better remain consistent about threading! */
2334 }
2335 
2337 {
2338  FileUID unset_uid;
2339  filelist_uid_unset(&unset_uid);
2340  return unset_uid != uid;
2341 }
2342 
2344 {
2345  *r_uid = FILE_UID_UNSET;
2346 }
2347 
2348 void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
2349 {
2350  /* Always keep it power of 2, in [256, 8192] range for now,
2351  * cache being app. twice bigger than requested window. */
2352  size_t size = 256;
2353  window_size *= 2;
2354 
2355  while (size < window_size && size < 8192) {
2356  size *= 2;
2357  }
2358 
2359  if (size != filelist->filelist_cache.size) {
2361  }
2362 }
2363 
2364 /* Helpers, low-level, they assume cursor + size <= cache_size */
2366  const int start_index,
2367  const int size,
2368  int cursor)
2369 {
2370  FileListEntryCache *cache = &filelist->filelist_cache;
2371 
2372  {
2373  int i, idx;
2374 
2375  for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) {
2376  FileDirEntry *entry;
2377 
2378  /* That entry might have already been requested and stored in misc cache... */
2379  if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) {
2380  entry = filelist_file_create_entry(filelist, idx);
2381  BLI_ghash_insert(cache->uids, POINTER_FROM_UINT(entry->uid), entry);
2382  }
2383  cache->block_entries[cursor] = entry;
2384  }
2385  return true;
2386  }
2387 
2388  return false;
2389 }
2390 
2391 static void filelist_file_cache_block_release(struct FileList *filelist,
2392  const int size,
2393  int cursor)
2394 {
2395  FileListEntryCache *cache = &filelist->filelist_cache;
2396 
2397  {
2398  int i;
2399 
2400  for (i = 0; i < size; i++, cursor++) {
2401  FileDirEntry *entry = cache->block_entries[cursor];
2402 #if 0
2403  printf("%s: release cacheidx %d (%%p %%s)\n",
2404  __func__,
2405  cursor /*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/);
2406 #endif
2407  BLI_ghash_remove(cache->uids, POINTER_FROM_UINT(entry->uid), NULL, NULL);
2408  filelist_file_release_entry(filelist, entry);
2409 #ifndef NDEBUG
2410  cache->block_entries[cursor] = NULL;
2411 #endif
2412  }
2413  }
2414 }
2415 
2416 bool filelist_file_cache_block(struct FileList *filelist, const int index)
2417 {
2418  FileListEntryCache *cache = &filelist->filelist_cache;
2419  const size_t cache_size = cache->size;
2420 
2421  const int entries_num = filelist->filelist.entries_filtered_num;
2422  int start_index = max_ii(0, index - (cache_size / 2));
2423  int end_index = min_ii(entries_num, index + (cache_size / 2));
2424  int i;
2425  const bool full_refresh = (filelist->flags & FL_IS_READY) == 0;
2426 
2427  if ((index < 0) || (index >= entries_num)) {
2428  // printf("Wrong index %d ([%d:%d])", index, 0, entries_num);
2429  return false;
2430  }
2431 
2432  /* Maximize cached range! */
2433  if ((end_index - start_index) < cache_size) {
2434  if (start_index == 0) {
2435  end_index = min_ii(entries_num, start_index + cache_size);
2436  }
2437  else if (end_index == entries_num) {
2438  start_index = max_ii(0, end_index - cache_size);
2439  }
2440  }
2441 
2442  BLI_assert((end_index - start_index) <= cache_size);
2443 
2444  // printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__,
2445  // start_index, end_index, index, cache->block_start_index, cache->block_end_index);
2446 
2447  /* If we have something to (re)cache... */
2448  if (full_refresh || (start_index != cache->block_start_index) ||
2449  (end_index != cache->block_end_index)) {
2450  if (full_refresh || (start_index >= cache->block_end_index) ||
2451  (end_index <= cache->block_start_index)) {
2452  int size1 = cache->block_end_index - cache->block_start_index;
2453  int size2 = 0;
2454  int idx1 = cache->block_cursor, idx2 = 0;
2455 
2456  // printf("Full Recaching!\n");
2457 
2458  if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2460  }
2461 
2462  if (idx1 + size1 > cache_size) {
2463  size2 = idx1 + size1 - cache_size;
2464  size1 -= size2;
2465  filelist_file_cache_block_release(filelist, size2, idx2);
2466  }
2467  filelist_file_cache_block_release(filelist, size1, idx1);
2468 
2469  cache->block_start_index = cache->block_end_index = cache->block_cursor = 0;
2470 
2471  /* New cached block does not overlap existing one, simple. */
2472  if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) {
2473  return false;
2474  }
2475 
2476  cache->block_start_index = start_index;
2477  cache->block_end_index = end_index;
2478  }
2479  else {
2480  // printf("Partial Recaching!\n");
2481 
2482  /* At this point, we know we keep part of currently cached entries, so update previews
2483  * if needed, and remove everything from working queue - we'll add all newly needed
2484  * entries at the end. */
2485  if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2488  }
2489 
2490  // printf("\tpreview cleaned up...\n");
2491 
2492  if (start_index > cache->block_start_index) {
2493  int size1 = start_index - cache->block_start_index;
2494  int size2 = 0;
2495  int idx1 = cache->block_cursor, idx2 = 0;
2496 
2497  // printf("\tcache releasing: [%d:%d] (%d, %d)\n",
2498  // cache->block_start_index, cache->block_start_index + size1,
2499  // cache->block_cursor, size1);
2500 
2501  if (idx1 + size1 > cache_size) {
2502  size2 = idx1 + size1 - cache_size;
2503  size1 -= size2;
2504  filelist_file_cache_block_release(filelist, size2, idx2);
2505  }
2506  filelist_file_cache_block_release(filelist, size1, idx1);
2507 
2508  cache->block_cursor = (idx1 + size1 + size2) % cache_size;
2509  cache->block_start_index = start_index;
2510  }
2511  if (end_index < cache->block_end_index) {
2512  int size1 = cache->block_end_index - end_index;
2513  int size2 = 0;
2514  int idx1, idx2 = 0;
2515 
2516 #if 0
2517  printf("\tcache releasing: [%d:%d] (%d)\n",
2518  cache->block_end_index - size1,
2519  cache->block_end_index,
2520  cache->block_cursor);
2521 #endif
2522 
2523  idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size;
2524  if (idx1 + size1 > cache_size) {
2525  size2 = idx1 + size1 - cache_size;
2526  size1 -= size2;
2527  filelist_file_cache_block_release(filelist, size2, idx2);
2528  }
2529  filelist_file_cache_block_release(filelist, size1, idx1);
2530 
2531  cache->block_end_index = end_index;
2532  }
2533 
2534  // printf("\tcache cleaned up...\n");
2535 
2536  if (start_index < cache->block_start_index) {
2537  /* Add (request) needed entries before already cached ones. */
2538  /* NOTE: We need some index black magic to wrap around (cycle)
2539  * inside our cache_size array... */
2540  int size1 = cache->block_start_index - start_index;
2541  int size2 = 0;
2542  int idx1, idx2;
2543 
2544  if (size1 > cache->block_cursor) {
2545  size2 = size1;
2546  size1 -= cache->block_cursor;
2547  size2 -= size1;
2548  idx2 = 0;
2549  idx1 = cache_size - size1;
2550  }
2551  else {
2552  idx1 = cache->block_cursor - size1;
2553  }
2554 
2555  if (size2) {
2556  if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) {
2557  return false;
2558  }
2559  }
2560  if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) {
2561  return false;
2562  }
2563 
2564  cache->block_cursor = idx1;
2565  cache->block_start_index = start_index;
2566  }
2567  // printf("\tstart-extended...\n");
2568  if (end_index > cache->block_end_index) {
2569  /* Add (request) needed entries after already cached ones. */
2570  /* NOTE: We need some index black magic to wrap around (cycle)
2571  * inside our cache_size array... */
2572  int size1 = end_index - cache->block_end_index;
2573  int size2 = 0;
2574  int idx1, idx2;
2575 
2576  idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size;
2577  if ((idx1 + size1) > cache_size) {
2578  size2 = size1;
2579  size1 = cache_size - idx1;
2580  size2 -= size1;
2581  idx2 = 0;
2582  }
2583 
2584  if (size2) {
2585  if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) {
2586  return false;
2587  }
2588  }
2589  if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) {
2590  return false;
2591  }
2592 
2593  cache->block_end_index = end_index;
2594  }
2595 
2596  // printf("\tend-extended...\n");
2597  }
2598  }
2599  else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) {
2600  /* We try to always preview visible entries first, so 'restart' preview background task. */
2603  }
2604 
2605  // printf("Re-queueing previews...\n");
2606 
2607  if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2608  /* Note we try to preview first images around given index - i.e. assumed visible ones. */
2609  int block_index = cache->block_cursor + (index - start_index);
2610  int offs_max = max_ii(end_index - index, index - start_index);
2611  for (i = 0; i <= offs_max; i++) {
2612  int offs = i;
2613  do {
2614  int offs_idx = index + offs;
2615  if (start_index <= offs_idx && offs_idx < end_index) {
2616  int offs_block_idx = (block_index + offs) % (int)cache_size;
2617  filelist_cache_previews_push(filelist, cache->block_entries[offs_block_idx], offs_idx);
2618  }
2619  } while ((offs = -offs) < 0); /* Switch between negative and positive offset. */
2620  }
2621  }
2622 
2623  cache->block_center_index = index;
2624 
2625  // printf("%s Finished!\n", __func__);
2626 
2627  return true;
2628 }
2629 
2630 void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
2631 {
2632  FileListEntryCache *cache = &filelist->filelist_cache;
2633 
2634  if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) {
2635  return;
2636  }
2637  /* Do not start preview work while listing, gives nasty flickering! */
2638  if (use_previews && (filelist->flags & FL_IS_READY)) {
2639  cache->flags |= FLC_PREVIEWS_ACTIVE;
2640 
2641  BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL) &&
2642  (cache->previews_todo_count == 0));
2643 
2644  // printf("%s: Init Previews...\n", __func__);
2645 
2646  /* No need to populate preview queue here, filelist_file_cache_block() handles this. */
2647  }
2648  else {
2649  // printf("%s: Clear Previews...\n", __func__);
2650 
2652  }
2653 }
2654 
2656 {
2657  FileListEntryCache *cache = &filelist->filelist_cache;
2658  TaskPool *pool = cache->previews_pool;
2659  bool changed = false;
2660 
2661  if (!pool) {
2662  return changed;
2663  }
2664 
2665  // printf("%s: Update Previews...\n", __func__);
2666 
2667  while (!BLI_thread_queue_is_empty(cache->previews_done)) {
2669  FileDirEntry *entry;
2670 
2671  /* Paranoid (should never happen currently
2672  * since we consume this queue from a single thread), but... */
2673  if (!preview) {
2674  continue;
2675  }
2676  /* entry might have been removed from cache in the mean time,
2677  * we do not want to cache it again here. */
2678  entry = filelist_file_ex(filelist, preview->index, false);
2679 
2680  // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->filepath, preview->img);
2681 
2682  if (entry) {
2683  if (preview->icon_id) {
2684  /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous
2685  * process from trying to generate the same preview icon. */
2686  BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet");
2687 
2688  /* Move ownership over icon. */
2689  entry->preview_icon_id = preview->icon_id;
2690  preview->icon_id = 0;
2691  changed = true;
2692  }
2693  else {
2694  /* We want to avoid re-processing this entry continuously!
2695  * Note that, since entries only live in cache,
2696  * preview will be retried quite often anyway. */
2698  }
2699  entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
2700  }
2701  else {
2702  BKE_icon_delete(preview->icon_id);
2703  }
2704 
2705  MEM_freeN(preview);
2706  cache->previews_todo_count--;
2707  }
2708 
2709  return changed;
2710 }
2711 
2713 {
2714  FileListEntryCache *cache = &filelist->filelist_cache;
2715 
2716  return (cache->previews_pool != NULL);
2717 }
2718 
2720 {
2721  FileListEntryCache *cache = &filelist->filelist_cache;
2722  if ((cache->flags & FLC_PREVIEWS_ACTIVE) == 0) {
2723  /* There are no previews. */
2724  return false;
2725  }
2726 
2727  return (cache->previews_pool == NULL) || (cache->previews_done == NULL) ||
2728  (cache->previews_todo_count == 0);
2729 }
2730 
2731 /* would recognize .blend as well */
2732 static bool file_is_blend_backup(const char *str)
2733 {
2734  const size_t a = strlen(str);
2735  size_t b = 7;
2736  bool retval = 0;
2737 
2738  if (a == 0 || b >= a) {
2739  /* pass */
2740  }
2741  else {
2742  const char *loc;
2743 
2744  if (a > b + 1) {
2745  b++;
2746  }
2747 
2748  /* allow .blend1 .blend2 .blend32 */
2749  loc = BLI_strcasestr(str + a - b, ".blend");
2750 
2751  if (loc) {
2752  retval = 1;
2753  }
2754  }
2755 
2756  return retval;
2757 }
2758 
2759 int ED_path_extension_type(const char *path)
2760 {
2761  if (BLO_has_bfile_extension(path)) {
2762  return FILE_TYPE_BLENDER;
2763  }
2764  if (file_is_blend_backup(path)) {
2765  return FILE_TYPE_BLENDER_BACKUP;
2766  }
2767 #ifdef __APPLE__
2768  if (BLI_path_extension_check_n(path,
2769  /* Application bundle */
2770  ".app",
2771  /* Safari in-progress/paused download */
2772  ".download",
2773  NULL)) {
2774  return FILE_TYPE_BUNDLE;
2775  }
2776 #endif
2777  if (BLI_path_extension_check(path, ".py")) {
2778  return FILE_TYPE_PYSCRIPT;
2779  }
2780  if (BLI_path_extension_check_n(path,
2781  ".txt",
2782  ".glsl",
2783  ".osl",
2784  ".data",
2785  ".pov",
2786  ".ini",
2787  ".mcr",
2788  ".inc",
2789  ".fountain",
2790  NULL)) {
2791  return FILE_TYPE_TEXT;
2792  }
2794  path, ".ttf", ".ttc", ".pfb", ".otf", ".otc", ".woff", ".woff2", NULL)) {
2795  return FILE_TYPE_FTFONT;
2796  }
2797  if (BLI_path_extension_check(path, ".btx")) {
2798  return FILE_TYPE_BTX;
2799  }
2800  if (BLI_path_extension_check(path, ".dae")) {
2801  return FILE_TYPE_COLLADA;
2802  }
2803  if (BLI_path_extension_check(path, ".abc")) {
2804  return FILE_TYPE_ALEMBIC;
2805  }
2806  if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", NULL)) {
2807  return FILE_TYPE_USD;
2808  }
2809  if (BLI_path_extension_check(path, ".vdb")) {
2810  return FILE_TYPE_VOLUME;
2811  }
2812  if (BLI_path_extension_check(path, ".zip")) {
2813  return FILE_TYPE_ARCHIVE;
2814  }
2816  path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".stl", NULL)) {
2817  return FILE_TYPE_OBJECT_IO;
2818  }
2820  return FILE_TYPE_IMAGE;
2821  }
2822  if (BLI_path_extension_check(path, ".ogg")) {
2823  if (IMB_isanim(path)) {
2824  return FILE_TYPE_MOVIE;
2825  }
2826  return FILE_TYPE_SOUND;
2827  }
2829  return FILE_TYPE_MOVIE;
2830  }
2832  return FILE_TYPE_SOUND;
2833  }
2834  return 0;
2835 }
2836 
2837 int ED_file_extension_icon(const char *path)
2838 {
2839  const int type = ED_path_extension_type(path);
2840 
2841  switch (type) {
2842  case FILE_TYPE_BLENDER:
2843  return ICON_FILE_BLEND;
2845  return ICON_FILE_BACKUP;
2846  case FILE_TYPE_IMAGE:
2847  return ICON_FILE_IMAGE;
2848  case FILE_TYPE_MOVIE:
2849  return ICON_FILE_MOVIE;
2850  case FILE_TYPE_PYSCRIPT:
2851  return ICON_FILE_SCRIPT;
2852  case FILE_TYPE_SOUND:
2853  return ICON_FILE_SOUND;
2854  case FILE_TYPE_FTFONT:
2855  return ICON_FILE_FONT;
2856  case FILE_TYPE_BTX:
2857  return ICON_FILE_BLANK;
2858  case FILE_TYPE_COLLADA:
2859  case FILE_TYPE_ALEMBIC:
2860  case FILE_TYPE_OBJECT_IO:
2861  return ICON_FILE_3D;
2862  case FILE_TYPE_TEXT:
2863  return ICON_FILE_TEXT;
2864  case FILE_TYPE_ARCHIVE:
2865  return ICON_FILE_ARCHIVE;
2866  case FILE_TYPE_VOLUME:
2867  return ICON_FILE_VOLUME;
2868  default:
2869  return ICON_FILE_BLANK;
2870  }
2871 }
2872 
2874 {
2875  return (filelist->filelist.entries_num == FILEDIR_NBR_ENTRIES_UNSET) ||
2876  filelist_needs_force_reset(filelist);
2877 }
2878 
2880  const FileDirEntry *entry,
2882  uint flag,
2883  FileCheckType check)
2884 {
2885  /* Default NULL pointer if not found is fine here! */
2886  void **es_p = BLI_ghash_lookup_p(filelist->selection_state, POINTER_FROM_UINT(entry->uid));
2887  uint entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0;
2888  const uint org_entry_flag = entry_flag;
2889 
2890  BLI_assert(entry);
2892 
2893  if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
2894  ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) {
2895  switch (select) {
2896  case FILE_SEL_REMOVE:
2897  entry_flag &= ~flag;
2898  break;
2899  case FILE_SEL_ADD:
2900  entry_flag |= flag;
2901  break;
2902  case FILE_SEL_TOGGLE:
2903  entry_flag ^= flag;
2904  break;
2905  }
2906  }
2907 
2908  if (entry_flag != org_entry_flag) {
2909  if (es_p) {
2910  if (entry_flag) {
2911  *es_p = POINTER_FROM_UINT(entry_flag);
2912  }
2913  else {
2915  }
2916  }
2917  else if (entry_flag) {
2919  filelist->selection_state, POINTER_FROM_UINT(entry->uid), POINTER_FROM_UINT(entry_flag));
2920  }
2921  }
2922 
2923  return entry_flag;
2924 }
2925 
2927  FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
2928 {
2929  FileDirEntry *entry = filelist_file(filelist, index);
2930 
2931  if (entry) {
2932  filelist_entry_select_set(filelist, entry, select, flag, check);
2933  }
2934 }
2935 
2937  FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
2938 {
2939  /* select all valid files between first and last indicated */
2940  if ((sel->first >= 0) && (sel->first < filelist->filelist.entries_filtered_num) &&
2941  (sel->last >= 0) && (sel->last < filelist->filelist.entries_filtered_num)) {
2942  int current_file;
2943  for (current_file = sel->first; current_file <= sel->last; current_file++) {
2944  filelist_entry_select_index_set(filelist, current_file, select, flag, check);
2945  }
2946  }
2947 }
2948 
2950 {
2951  BLI_assert(entry);
2953 
2954  if (((check == CHECK_ALL)) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
2955  ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR))) {
2956  /* Default NULL pointer if not found is fine here! */
2957  return POINTER_AS_UINT(
2959  }
2960 
2961  return 0;
2962 }
2963 
2965 {
2966  FileDirEntry *entry = filelist_file(filelist, index);
2967 
2968  if (entry) {
2969  return filelist_entry_select_get(filelist, entry, check);
2970  }
2971 
2972  return 0;
2973 }
2974 
2975 bool filelist_entry_is_selected(FileList *filelist, const int index)
2976 {
2977  BLI_assert(index >= 0 && index < filelist->filelist.entries_filtered_num);
2978  FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
2979 
2980  /* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to
2981  * "not selected". */
2982  const uint selection_state = POINTER_AS_UINT(
2983  BLI_ghash_lookup(filelist->selection_state, POINTER_FROM_UINT(intern_entry->uid)));
2984 
2985  return selection_state != 0;
2986 }
2987 
2990  uint flag,
2991  FileCheckType check)
2992 {
2993  if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
2994  filelist_entry_select_index_set(filelist, 0, select, flag, check);
2995  }
2996 }
2997 
2998 bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
2999 {
3000  return BLO_library_path_explode(filelist->filelist.root, dir, r_group, NULL);
3001 }
3002 
3003 static int groupname_to_code(const char *group)
3004 {
3005  char buf[BLO_GROUP_MAX];
3006  char *lslash;
3007 
3008  BLI_assert(group);
3009 
3010  BLI_strncpy(buf, group, sizeof(buf));
3011  lslash = (char *)BLI_path_slash_rfind(buf);
3012  if (lslash) {
3013  lslash[0] = '\0';
3014  }
3015 
3016  return buf[0] ? BKE_idtype_idcode_from_name(buf) : 0;
3017 }
3018 
3019 static uint64_t groupname_to_filter_id(const char *group)
3020 {
3021  int id_code = groupname_to_code(group);
3022 
3023  return BKE_idtype_idcode_to_idfilter(id_code);
3024 }
3025 
3031 typedef struct TodoDir {
3032  int level;
3033  char *dir;
3035 
3036 static int filelist_readjob_list_dir(const char *root,
3037  ListBase *entries,
3038  const char *filter_glob,
3039  const bool do_lib,
3040  const char *main_name,
3041  const bool skip_currpar)
3042 {
3043  struct direntry *files;
3044  int entries_num = 0;
3045  /* Full path of the item. */
3046  char full_path[FILE_MAX];
3047 
3048  const int files_num = BLI_filelist_dir_contents(root, &files);
3049  if (files) {
3050  int i = files_num;
3051  while (i--) {
3052  FileListInternEntry *entry;
3053 
3054  if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) {
3055  continue;
3056  }
3057 
3058  entry = MEM_callocN(sizeof(*entry), __func__);
3059  entry->relpath = MEM_dupallocN(files[i].relname);
3060  entry->st = files[i].s;
3061 
3062  BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
3063  char *target = full_path;
3064 
3065  /* Set initial file type and attributes. */
3066  entry->attributes = BLI_file_attributes(full_path);
3067  if (S_ISDIR(files[i].s.st_mode)
3068 #ifdef __APPLE__
3069  && !(ED_path_extension_type(full_path) & FILE_TYPE_BUNDLE)
3070 #endif
3071  ) {
3072  entry->typeflag = FILE_TYPE_DIR;
3073  }
3074 
3075  /* Is this a file that points to another file? */
3076  if (entry->attributes & FILE_ATTR_ALIAS) {
3077  entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__);
3078  if (BLI_file_alias_target(full_path, entry->redirection_path)) {
3079  if (BLI_is_dir(entry->redirection_path)) {
3080  entry->typeflag = FILE_TYPE_DIR;
3082  }
3083  else {
3085  }
3086  target = entry->redirection_path;
3087 #ifdef WIN32
3088  /* On Windows don't show `.lnk` extension for valid shortcuts. */
3090 #endif
3091  }
3092  else {
3093  MEM_freeN(entry->redirection_path);
3094  entry->redirection_path = NULL;
3095  entry->attributes |= FILE_ATTR_HIDDEN;
3096  }
3097  }
3098 
3099  if (!(entry->typeflag & FILE_TYPE_DIR)) {
3100  if (do_lib && BLO_has_bfile_extension(target)) {
3101  /* If we are considering .blend files as libs, promote them to directory status. */
3102  entry->typeflag = FILE_TYPE_BLENDER;
3103  /* prevent current file being used as acceptable dir */
3104  if (BLI_path_cmp(main_name, target) != 0) {
3105  entry->typeflag |= FILE_TYPE_DIR;
3106  }
3107  }
3108  else {
3109  entry->typeflag = ED_path_extension_type(target);
3110  if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) {
3111  entry->typeflag |= FILE_TYPE_OPERATOR;
3112  }
3113  }
3114  }
3115 
3116 #ifndef WIN32
3117  /* Set linux-style dot files hidden too. */
3118  if (is_hidden_dot_filename(entry->relpath, entry)) {
3119  entry->attributes |= FILE_ATTR_HIDDEN;
3120  }
3121 #endif
3122 
3123  BLI_addtail(entries, entry);
3124  entries_num++;
3125  }
3126  BLI_filelist_free(files, files_num);
3127  }
3128  return entries_num;
3129 }
3130 
3131 typedef enum ListLibOptions {
3132  /* Will read both the groups + actual ids from the library. Reduces the amount of times that
3133  * a library needs to be opened. */
3135 
3136  /* Will only list assets. */
3138 
3139  /* Add given root as result. */
3142 
3144  const char *group_name)
3145 {
3146  FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
3147  entry->relpath = BLI_strdup(group_name);
3149  entry->blentype = idcode;
3150  return entry;
3151 }
3152 
3154  const BLODataBlockInfo *datablock_info,
3155  const bool prefix_relpath_with_group_name,
3156  const int idcode,
3157  const char *group_name)
3158 {
3159  FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
3160  if (prefix_relpath_with_group_name) {
3161  entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name);
3162  }
3163  else {
3164  entry->relpath = BLI_strdup(datablock_info->name);
3165  }
3166  entry->typeflag |= FILE_TYPE_BLENDERLIB;
3167  if (datablock_info && datablock_info->asset_data) {
3168  entry->typeflag |= FILE_TYPE_ASSET;
3169  /* Moves ownership! */
3170  entry->imported_asset_data = datablock_info->asset_data;
3171  }
3172  entry->blentype = idcode;
3173  BLI_addtail(entries, entry);
3174 }
3175 
3177  LinkNode *datablock_infos,
3178  const bool prefix_relpath_with_group_name,
3179  const int idcode,
3180  const char *group_name)
3181 {
3182  for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
3183  struct BLODataBlockInfo *datablock_info = ln->link;
3185  entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
3186  }
3187 }
3188 
3190  ListBase *entries,
3191  const FileIndexerEntries *indexer_entries,
3192  const bool prefix_relpath_with_group_name)
3193 {
3194  for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
3195  const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link;
3196  const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
3198  &indexer_entry->datablock_info,
3199  prefix_relpath_with_group_name,
3200  indexer_entry->idcode,
3201  group_name);
3202  }
3203 }
3204 
3206 {
3207  FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__);
3210  return entry;
3211 }
3212 
3216 typedef struct FileIndexer {
3218 
3222  void *user_data;
3224 
3226  const ListLibOptions options,
3227  const int read_from_index,
3228  const FileIndexerEntries *indexer_entries)
3229 {
3230  int navigate_to_parent_len = 0;
3231  if (options & LIST_LIB_ADD_PARENT) {
3233  BLI_addtail(entries, entry);
3234  navigate_to_parent_len = 1;
3235  }
3236 
3237  filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true);
3238  return read_from_index + navigate_to_parent_len;
3239 }
3240 
3241 static int filelist_readjob_list_lib(const char *root,
3242  ListBase *entries,
3243  const ListLibOptions options,
3244  FileIndexer *indexer_runtime)
3245 {
3246  BLI_assert(indexer_runtime);
3247 
3248  char dir[FILE_MAX_LIBEXTRA], *group;
3249 
3250  struct BlendHandle *libfiledata = NULL;
3251 
3252  /* Check if the given root is actually a library. All folders are passed to
3253  * `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do`
3254  * will do a dir listing only when this function does not return any entries. */
3255  /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and
3256  * call it directly from `filelist_readjob_do` to increase readability. */
3257  const bool is_lib = BLO_library_path_explode(root, dir, &group, NULL);
3258  if (!is_lib) {
3259  return 0;
3260  }
3261 
3262  const bool group_came_from_path = group != NULL;
3263 
3264  /* Try read from indexer_runtime. */
3265  /* Indexing returns all entries in a blend file. We should ignore the index when listing a group
3266  * inside a blend file, so the `entries` isn't filled with undesired entries.
3267  * This happens when linking or appending data-blocks, where you can navigate into a group (ie
3268  * Materials/Objects) where you only want to work with partial indexes.
3269  *
3270  * Adding support for partial reading/updating indexes would increase the complexity.
3271  */
3272  const bool use_indexer = !group_came_from_path;
3273  FileIndexerEntries indexer_entries = {NULL};
3274  if (use_indexer) {
3275  int read_from_index = 0;
3276  eFileIndexerResult indexer_result = indexer_runtime->callbacks->read_index(
3277  dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
3278  if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
3280  entries, options, read_from_index, &indexer_entries);
3281  ED_file_indexer_entries_clear(&indexer_entries);
3282  return entries_read;
3283  }
3284  }
3285 
3286  /* Open the library file. */
3287  BlendFileReadReport bf_reports = {.reports = NULL};
3288  libfiledata = BLO_blendhandle_from_file(dir, &bf_reports);
3289  if (libfiledata == NULL) {
3290  return 0;
3291  }
3292 
3293  /* Add current parent when requested. */
3294  /* Is the navigate to previous level added to the list of entries. When added the return value
3295  * should be increased to match the actual number of entries added. It is introduced to keep
3296  * the code clean and readable and not counting in a single variable. */
3297  int navigate_to_parent_len = 0;
3298  if (options & LIST_LIB_ADD_PARENT) {
3300  BLI_addtail(entries, entry);
3301  navigate_to_parent_len = 1;
3302  }
3303 
3304  int group_len = 0;
3305  int datablock_len = 0;
3306  if (group_came_from_path) {
3307  const int idcode = groupname_to_code(group);
3308  LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
3309  libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len);
3310  filelist_readjob_list_lib_add_datablocks(entries, datablock_infos, false, idcode, group);
3311  BLI_linklist_freeN(datablock_infos);
3312  }
3313  else {
3314  LinkNode *groups = BLO_blendhandle_get_linkable_groups(libfiledata);
3315  group_len = BLI_linklist_count(groups);
3316 
3317  for (LinkNode *ln = groups; ln; ln = ln->next) {
3318  const char *group_name = ln->link;
3319  const int idcode = groupname_to_code(group_name);
3321  group_name);
3322  BLI_addtail(entries, group_entry);
3323 
3324  if (options & LIST_LIB_RECURSIVE) {
3325  int group_datablock_len;
3326  LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info(
3327  libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
3329  entries, group_datablock_infos, true, idcode, group_name);
3330  if (use_indexer) {
3332  &indexer_entries, group_datablock_infos, idcode);
3333  }
3334  BLI_linklist_freeN(group_datablock_infos);
3335  datablock_len += group_datablock_len;
3336  }
3337  }
3338 
3339  BLI_linklist_freeN(groups);
3340  }
3341 
3342  BLO_blendhandle_close(libfiledata);
3343 
3344  /* Update the index. */
3345  if (use_indexer) {
3346  indexer_runtime->callbacks->update_index(dir, &indexer_entries, indexer_runtime->user_data);
3347  ED_file_indexer_entries_clear(&indexer_entries);
3348  }
3349 
3350  /* Return the number of items added to entries. */
3351  int added_entries_len = group_len + datablock_len + navigate_to_parent_len;
3352  return added_entries_len;
3353 }
3354 
3355 #if 0
3356 /* Kept for reference here, in case we want to add back that feature later.
3357  * We do not need it currently. */
3358 /* Code ***NOT*** updated for job stuff! */
3359 static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
3360 {
3361  ID *id;
3362  FileDirEntry *files, *firstlib = NULL;
3363  ListBase *lb;
3364  int a, fake, idcode, ok, totlib, totbl;
3365 
3366  // filelist->type = FILE_MAIN; /* XXX TODO: add modes to file-browser */
3367 
3368  BLI_assert(filelist->filelist.entries == NULL);
3369 
3370  if (filelist->filelist.root[0] == '/') {
3371  filelist->filelist.root[0] = '\0';
3372  }
3373 
3374  if (filelist->filelist.root[0]) {
3375  idcode = groupname_to_code(filelist->filelist.root);
3376  if (idcode == 0) {
3377  filelist->filelist.root[0] = '\0';
3378  }
3379  }
3380 
3381  if (filelist->dir[0] == 0) {
3382  /* make directories */
3383 # ifdef WITH_FREESTYLE
3384  filelist->filelist.entries_num = 27;
3385 # else
3386  filelist->filelist.entries_num = 26;
3387 # endif
3388  filelist_resize(filelist, filelist->filelist.entries_num);
3389 
3390  for (a = 0; a < filelist->filelist.entries_num; a++) {
3391  filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR;
3392  }
3393 
3394  filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT);
3395  filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene");
3396  filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object");
3397  filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh");
3398  filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve");
3399  filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball");
3400  filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material");
3401  filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture");
3402  filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image");
3403  filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika");
3404  filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave");
3405  filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice");
3406  filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light");
3407  filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera");
3408  filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo");
3409  filelist->filelist.entries[15].entry->relpath = BLI_strdup("World");
3410  filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen");
3411  filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont");
3412  filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text");
3413  filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature");
3414  filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action");
3415  filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree");
3416  filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker");
3417  filelist->filelist.entries[23].entry->relpath = BLI_strdup("Curves");
3418  filelist->filelist.entries[24].entry->relpath = BLI_strdup("Point Cloud");
3419  filelist->filelist.entries[25].entry->relpath = BLI_strdup("Volume");
3420 # ifdef WITH_FREESTYLE
3421  filelist->filelist.entries[26].entry->relpath = BLI_strdup("FreestyleLineStyle");
3422 # endif
3423  }
3424  else {
3425  /* make files */
3426  idcode = groupname_to_code(filelist->filelist.root);
3427 
3428  lb = which_libbase(bmain, idcode);
3429  if (lb == NULL) {
3430  return;
3431  }
3432 
3433  filelist->filelist.entries_num = 0;
3434  for (id = lb->first; id; id = id->next) {
3435  if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
3436  filelist->filelist.entries_num++;
3437  }
3438  }
3439 
3440  /* XXX TODO: if data-browse or append/link #FLF_HIDE_PARENT has to be set. */
3441  if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
3442  filelist->filelist.entries_num++;
3443  }
3444 
3445  if (filelist->filelist.entries_num > 0) {
3446  filelist_resize(filelist, filelist->filelist.entries_num);
3447  }
3448 
3449  files = filelist->filelist.entries;
3450 
3451  if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
3452  files->entry->relpath = BLI_strdup(FILENAME_PARENT);
3453  files->typeflag |= FILE_TYPE_DIR;
3454 
3455  files++;
3456  }
3457 
3458  totlib = totbl = 0;
3459  for (id = lb->first; id; id = id->next) {
3460  ok = 1;
3461  if (ok) {
3462  if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
3463  if (!ID_IS_LINKED(id)) {
3464  files->entry->relpath = BLI_strdup(id->name + 2);
3465  }
3466  else {
3467  char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3];
3468  BLI_snprintf(relname, sizeof(relname), "%s | %s", id->lib->filepath, id->name + 2);
3469  files->entry->relpath = BLI_strdup(relname);
3470  }
3471 // files->type |= S_IFREG;
3472 # if 0 /* XXX TODO: show the selection status of the objects. */
3473  if (!filelist->has_func) { /* F4 DATA BROWSE */
3474  if (idcode == ID_OB) {
3475  if ( ((Object *)id)->flag & SELECT) {
3476  files->entry->selflag |= FILE_SEL_SELECTED;
3477  }
3478  }
3479  else if (idcode == ID_SCE) {
3480  if ( ((Scene *)id)->r.scemode & R_BG_RENDER) {
3481  files->entry->selflag |= FILE_SEL_SELECTED;
3482  }
3483  }
3484  }
3485 # endif
3486  // files->entry->nr = totbl + 1;
3487  files->entry->poin = id;
3488  fake = id->flag & LIB_FAKEUSER;
3489  if (ELEM(idcode, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM)) {
3490  files->typeflag |= FILE_TYPE_IMAGE;
3491  }
3492 # if 0
3493  if (id->lib && fake) {
3494  BLI_snprintf(files->extra, sizeof(files->entry->extra), "LF %d", id->us);
3495  }
3496  else if (id->lib) {
3497  BLI_snprintf(files->extra, sizeof(files->entry->extra), "L %d", id->us);
3498  }
3499  else if (fake) {
3500  BLI_snprintf(files->extra, sizeof(files->entry->extra), "F %d", id->us);
3501  }
3502  else {
3503  BLI_snprintf(files->extra, sizeof(files->entry->extra), " %d", id->us);
3504  }
3505 # endif
3506 
3507  if (id->lib) {
3508  if (totlib == 0) {
3509  firstlib = files;
3510  }
3511  totlib++;
3512  }
3513 
3514  files++;
3515  }
3516  totbl++;
3517  }
3518  }
3519 
3520  /* only qsort of library blocks */
3521  if (totlib > 1) {
3522  qsort(firstlib, totlib, sizeof(*files), compare_name);
3523  }
3524  }
3525 }
3526 #endif
3527 
3528 typedef struct FileListReadJob {
3536 
3549 
3551  ListBase *from_entries,
3552  int from_entries_num,
3553  short *do_update)
3554 {
3555  BLI_assert(BLI_listbase_count(from_entries) == from_entries_num);
3556  if (from_entries_num <= 0) {
3557  *do_update = false;
3558  return;
3559  }
3560 
3561  FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3562  BLI_mutex_lock(&job_params->lock);
3563  BLI_movelisttolist(&filelist->filelist.entries, from_entries);
3564  filelist->filelist.entries_num += from_entries_num;
3565  BLI_mutex_unlock(&job_params->lock);
3566 
3567  *do_update = true;
3568 }
3569 
3571  const bool is_lib,
3572  const int current_recursion_level,
3573  FileListInternEntry *entry)
3574 {
3575  if (max_recursion == 0) {
3576  /* Recursive loading is disabled. */
3577  return false;
3578  }
3579  if (!is_lib && current_recursion_level > max_recursion) {
3580  /* No more levels of recursion left. */
3581  return false;
3582  }
3583  /* Show entries when recursion is set to `Blend file` even when `current_recursion_level`
3584  * exceeds `max_recursion`. */
3585  if (!is_lib && (current_recursion_level >= max_recursion) &&
3586  ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) {
3587  return false;
3588  }
3589  if (entry->typeflag & FILE_TYPE_BLENDERLIB) {
3590  /* Libraries are already loaded recursively when recursive loaded is used. No need to add
3591  * them another time. This loading is done with the `LIST_LIB_RECURSIVE` option. */
3592  return false;
3593  }
3594  if (!(entry->typeflag & FILE_TYPE_DIR)) {
3595  /* Cannot recurse into regular file entries. */
3596  return false;
3597  }
3598  if (FILENAME_IS_CURRPAR(entry->relpath)) {
3599  /* Don't schedule go to parent entry, (`..`) */
3600  return false;
3601  }
3602 
3603  return true;
3604 }
3605 
3606 static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
3607  FileListReadJob *job_params,
3608  const short *stop,
3609  short *do_update,
3610  float *progress)
3611 {
3612  FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3613  ListBase entries = {0};
3614  BLI_Stack *todo_dirs;
3615  TodoDir *td_dir;
3616  char dir[FILE_MAX_LIBEXTRA];
3617  char filter_glob[FILE_MAXFILE];
3618  const char *root = filelist->filelist.root;
3619  const int max_recursion = filelist->max_recursion;
3620  int dirs_done_count = 0, dirs_todo_count = 1;
3621 
3622  todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__);
3623  td_dir = BLI_stack_push_r(todo_dirs);
3624  td_dir->level = 1;
3625 
3626  BLI_strncpy(dir, filelist->filelist.root, sizeof(dir));
3627  BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob));
3628 
3629  BLI_path_normalize_dir(job_params->main_name, dir);
3630  td_dir->dir = BLI_strdup(dir);
3631 
3632  /* Init the file indexer. */
3633  FileIndexer indexer_runtime = {.callbacks = filelist->indexer};
3634  if (indexer_runtime.callbacks->init_user_data) {
3635  indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir));
3636  }
3637 
3638  while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
3639  FileListInternEntry *entry;
3640  int entries_num = 0;
3641 
3642  char *subdir;
3643  char rel_subdir[FILE_MAX_LIBEXTRA];
3644  int recursion_level;
3645  bool skip_currpar;
3646 
3647  td_dir = BLI_stack_peek(todo_dirs);
3648  subdir = td_dir->dir;
3649  recursion_level = td_dir->level;
3650  skip_currpar = (recursion_level > 1);
3651 
3652  BLI_stack_discard(todo_dirs);
3653 
3654  /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over
3655  * entry->relpath itself (nor any path containing it), since it may actually be a datablock
3656  * name inside .blend file, which can have slashes and backslashes! See T46827.
3657  * Note that in the end, this means we 'cache' valid relative subdir once here,
3658  * this is actually better. */
3659  BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir));
3660  BLI_path_normalize_dir(root, rel_subdir);
3661  BLI_path_rel(rel_subdir, root);
3662 
3663  bool is_lib = false;
3664  if (do_lib) {
3665  ListLibOptions list_lib_options = 0;
3666  if (!skip_currpar) {
3667  list_lib_options |= LIST_LIB_ADD_PARENT;
3668  }
3669 
3670  /* Libraries are loaded recursively when max_recursion is set. It doesn't check if there is
3671  * still a recursion level over. */
3672  if (max_recursion > 0) {
3673  list_lib_options |= LIST_LIB_RECURSIVE;
3674  }
3675  /* Only load assets when browsing an asset library. For normal file browsing we return all
3676  * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user. */
3677  if (filelist->asset_library_ref) {
3678  list_lib_options |= LIST_LIB_ASSETS_ONLY;
3679  }
3680  entries_num = filelist_readjob_list_lib(
3681  subdir, &entries, list_lib_options, &indexer_runtime);
3682  if (entries_num > 0) {
3683  is_lib = true;
3684  }
3685  }
3686 
3687  if (!is_lib) {
3688  entries_num = filelist_readjob_list_dir(
3689  subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar);
3690  }
3691 
3692  for (entry = entries.first; entry; entry = entry->next) {
3694 
3695  /* When loading entries recursive, the rel_path should be relative from the root dir.
3696  * we combine the relative path to the subdir with the relative path of the entry. */
3697  BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath);
3698  MEM_freeN(entry->relpath);
3699  entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
3700  * added by BLI_path_rel to rel_subdir. */
3701  entry->name = fileentry_uiname(root, entry->relpath, entry->typeflag, dir);
3702  entry->free_name = true;
3703 
3705  max_recursion, is_lib, recursion_level, entry)) {
3706  /* We have a directory we want to list, add it to todo list! */
3707  BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
3708  BLI_path_normalize_dir(job_params->main_name, dir);
3709  td_dir = BLI_stack_push_r(todo_dirs);
3710  td_dir->level = recursion_level + 1;
3711  td_dir->dir = BLI_strdup(dir);
3712  dirs_todo_count++;
3713  }
3714  }
3715 
3716  filelist_readjob_append_entries(job_params, &entries, entries_num, do_update);
3717 
3718  dirs_done_count++;
3719  *progress = (float)dirs_done_count / (float)dirs_todo_count;
3720  MEM_freeN(subdir);
3721  }
3722 
3723  /* Finalize and free indexer. */
3724  if (indexer_runtime.callbacks->filelist_finished && BLI_stack_is_empty(todo_dirs)) {
3725  indexer_runtime.callbacks->filelist_finished(indexer_runtime.user_data);
3726  }
3727  if (indexer_runtime.callbacks->free_user_data && indexer_runtime.user_data) {
3728  indexer_runtime.callbacks->free_user_data(indexer_runtime.user_data);
3729  indexer_runtime.user_data = NULL;
3730  }
3731 
3732  /* If we were interrupted by stop, stack may not be empty and we need to free
3733  * pending dir paths. */
3734  while (!BLI_stack_is_empty(todo_dirs)) {
3735  td_dir = BLI_stack_peek(todo_dirs);
3736  MEM_freeN(td_dir->dir);
3737  BLI_stack_discard(todo_dirs);
3738  }
3739  BLI_stack_free(todo_dirs);
3740 }
3741 
3742 static void filelist_readjob_do(const bool do_lib,
3743  FileListReadJob *job_params,
3744  const short *stop,
3745  short *do_update,
3746  float *progress)
3747 {
3748  FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3749 
3750  // BLI_assert(filelist->filtered == NULL);
3753 
3754  /* A valid, but empty directory from now. */
3755  filelist->filelist.entries_num = 0;
3756 
3757  filelist_readjob_recursive_dir_add_items(do_lib, job_params, stop, do_update, progress);
3758 }
3759 
3760 static void filelist_readjob_dir(FileListReadJob *job_params,
3761  short *stop,
3762  short *do_update,
3763  float *progress)
3764 {
3765  filelist_readjob_do(false, job_params, stop, do_update, progress);
3766 }
3767 
3768 static void filelist_readjob_lib(FileListReadJob *job_params,
3769  short *stop,
3770  short *do_update,
3771  float *progress)
3772 {
3773  filelist_readjob_do(true, job_params, stop, do_update, progress);
3774 }
3775 
3776 static void filelist_asset_library_path(const FileListReadJob *job_params,
3777  char r_library_root_path[FILE_MAX])
3778 {
3779  if (job_params->filelist->type == FILE_MAIN_ASSET) {
3780  /* For the "Current File" library (#FILE_MAIN_ASSET) we get the asset library root path based
3781  * on main. */
3783  r_library_root_path);
3784  }
3785  else {
3786  BLI_strncpy(r_library_root_path, job_params->tmp_filelist->filelist.root, FILE_MAX);
3787  }
3788 }
3789 
3793 static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params, short *do_update)
3794 {
3795  FileList *tmp_filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3796 
3797  *do_update = false;
3798 
3799  if (job_params->filelist->asset_library_ref == NULL) {
3800  return;
3801  }
3802  if (tmp_filelist->asset_library != NULL) {
3803  /* Asset library already loaded. */
3804  return;
3805  }
3806 
3807  char library_root_path[FILE_MAX];
3808  filelist_asset_library_path(job_params, library_root_path);
3809 
3810  /* Load asset catalogs, into the temp filelist for thread-safety.
3811  * #filelist_readjob_endjob() will move it into the real filelist. */
3812  tmp_filelist->asset_library = BKE_asset_library_load(library_root_path);
3813  *do_update = true;
3814 }
3815 
3817  short *UNUSED(stop),
3818  short *do_update,
3819  float *UNUSED(progress))
3820 {
3821  FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3822 
3823  FileListInternEntry *entry;
3824  ListBase tmp_entries = {0};
3825  ID *id_iter;
3826  int entries_num = 0;
3827 
3828  /* Make sure no IDs are added/removed/reallocated in the main thread while this is running in
3829  * parallel. */
3830  BKE_main_lock(job_params->current_main);
3831 
3832  FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) {
3833  if (!id_iter->asset_data || ID_IS_LINKED(id_iter)) {
3834  continue;
3835  }
3836 
3837  const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
3838 
3839  entry = MEM_callocN(sizeof(*entry), __func__);
3840  entry->relpath = BLI_strdup(id_code_name);
3841  entry->name = id_iter->name + 2;
3842  entry->free_name = false;
3844  entry->blentype = GS(id_iter->name);
3847  id_iter);
3848  entry->local_data.id = id_iter;
3849  entries_num++;
3850  BLI_addtail(&tmp_entries, entry);
3851  }
3853 
3854  BKE_main_unlock(job_params->current_main);
3855 
3856  if (entries_num) {
3857  *do_update = true;
3858 
3859  BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries);
3860  filelist->filelist.entries_num += entries_num;
3861  filelist->filelist.entries_filtered_num = -1;
3862  }
3863 }
3864 
3872 static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
3873 {
3874  const char *blendfile_path = BKE_main_blendfile_path(bmain);
3875  return blendfile_path[0] && BLI_path_contains(filelist->filelist.root, blendfile_path);
3876 }
3877 
3879  short *stop,
3880  short *do_update,
3881  float *progress)
3882 {
3883  FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3884 
3887 
3888  /* A valid, but empty file-list from now. */
3889  filelist->filelist.entries_num = 0;
3890 
3891  /* NOP if already read. */
3892  filelist_readjob_load_asset_library_data(job_params, do_update);
3893 
3894  if (filelist_contains_main(filelist, job_params->current_main)) {
3895  filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress);
3896  }
3897  if (!job_params->only_main_data) {
3898  filelist_readjob_recursive_dir_add_items(true, job_params, stop, do_update, progress);
3899  }
3900 }
3901 
3902 static void filelist_readjob_main(FileListReadJob *job_params,
3903  short *stop,
3904  short *do_update,
3905  float *progress)
3906 {
3907  /* TODO! */
3908  filelist_readjob_dir(job_params, stop, do_update, progress);
3909 }
3910 
3912  short *stop,
3913  short *do_update,
3914  float *progress)
3915 {
3916  FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3919 
3920  filelist_readjob_load_asset_library_data(job_params, do_update);
3921 
3922  /* A valid, but empty file-list from now. */
3923  filelist->filelist.entries_num = 0;
3924 
3925  filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress);
3926 }
3927 
3932 {
3933  return read_job->only_main_data;
3934 }
3935 
3941 static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
3942 {
3943  FileListReadJob *flrj = flrjv;
3944 
3945  // printf("START filelist reading (%d files, main thread: %d)\n",
3946  // flrj->filelist->filelist.entries_num, BLI_thread_is_main());
3947 
3948  BLI_mutex_lock(&flrj->lock);
3949 
3950  BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist);
3951 
3952  flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
3953 
3956 
3960  /* Don't unset the current UID on partial read, would give duplicates otherwise. */
3961  }
3962  else {
3964  }
3965 
3966  flrj->tmp_filelist->libfiledata = NULL;
3967  memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
3971 
3972  BLI_mutex_unlock(&flrj->lock);
3973 
3974  flrj->tmp_filelist->read_job_fn(flrj, stop, do_update, progress);
3975 }
3976 
3982 static void filelist_readjob_update(void *flrjv)
3983 {
3984  FileListReadJob *flrj = flrjv;
3985  FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
3986  ListBase new_entries = {NULL};
3987  int entries_num, new_entries_num = 0;
3988 
3989  BLI_movelisttolist(&new_entries, &fl_intern->entries);
3990  entries_num = flrj->filelist->filelist.entries_num;
3991 
3992  BLI_mutex_lock(&flrj->lock);
3993 
3994  if (flrj->tmp_filelist->filelist.entries_num > 0) {
3995  /* We just move everything out of 'thread context' into final list. */
3996  new_entries_num = flrj->tmp_filelist->filelist.entries_num;
3997  BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
3998  flrj->tmp_filelist->filelist.entries_num = 0;
3999  }
4000 
4001  if (flrj->tmp_filelist->asset_library) {
4003  }
4004 
4005  /* Important for partial reads: Copy increased UID counter back to the real list. */
4006  if (flrj->tmp_filelist->filelist_intern.curr_uid > fl_intern->curr_uid) {
4007  fl_intern->curr_uid = flrj->tmp_filelist->filelist_intern.curr_uid;
4008  }
4009 
4010  BLI_mutex_unlock(&flrj->lock);
4011 
4012  if (new_entries_num) {
4013  /* Do not clear selection cache, we can assume already 'selected' UIDs are still valid! Keep
4014  * the asset library data we just read. */
4015  filelist_clear_ex(flrj->filelist, false, true, false);
4016 
4018  }
4019 
4020  /* if no new_entries_num, this is NOP */
4021  BLI_movelisttolist(&fl_intern->entries, &new_entries);
4022  flrj->filelist->filelist.entries_num = MAX2(entries_num, 0) + new_entries_num;
4023 }
4024 
4025 static void filelist_readjob_endjob(void *flrjv)
4026 {
4027  FileListReadJob *flrj = flrjv;
4028 
4029  /* In case there would be some dangling update... */
4030  filelist_readjob_update(flrjv);
4031 
4032  flrj->filelist->flags &= ~FL_IS_PENDING;
4033  flrj->filelist->flags |= FL_IS_READY;
4034 }
4035 
4036 static void filelist_readjob_free(void *flrjv)
4037 {
4038  FileListReadJob *flrj = flrjv;
4039 
4040  // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.entries_num);
4041 
4042  if (flrj->tmp_filelist) {
4043  /* tmp_filelist shall never ever be filtered! */
4046 
4048  filelist_free(flrj->tmp_filelist);
4049  MEM_freeN(flrj->tmp_filelist);
4050  }
4051 
4052  BLI_mutex_end(&flrj->lock);
4053 
4054  MEM_freeN(flrj);
4055 }
4056 
4057 void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
4058 {
4059  Main *bmain = CTX_data_main(C);
4060  wmJob *wm_job;
4061  FileListReadJob *flrj;
4062 
4063  if (!filelist_is_dir(filelist, filelist->filelist.root)) {
4064  return;
4065  }
4066 
4067  /* prepare job data */
4068  flrj = MEM_callocN(sizeof(*flrj), __func__);
4069  flrj->filelist = filelist;
4070  flrj->current_main = bmain;
4071  BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name));
4072  if ((filelist->flags & FL_FORCE_RESET_MAIN_FILES) && !(filelist->flags & FL_FORCE_RESET)) {
4073  flrj->only_main_data = true;
4074  }
4075 
4077  filelist->flags |= FL_IS_PENDING;
4078 
4079  /* Init even for single threaded execution. Called functions use it. */
4080  BLI_mutex_init(&flrj->lock);
4081 
4082  /* The file list type may not support threading so execute immediately. Same when only rereading
4083  * #Main data (which we do quite often on changes to #Main, since it's the easiest and safest way
4084  * to ensure the displayed data is up to date), because some operations executing right after
4085  * main data changed may need access to the ID files (see T93691). */
4086  const bool no_threads = (filelist->tags & FILELIST_TAGS_NO_THREADS) || flrj->only_main_data;
4087 
4088  if (no_threads) {
4089  short dummy_stop = false;
4090  short dummy_do_update = false;
4091  float dummy_progress = 0.0f;
4092 
4093  /* Single threaded execution. Just directly call the callbacks. */
4094  filelist_readjob_startjob(flrj, &dummy_stop, &dummy_do_update, &dummy_progress);
4096  filelist_readjob_free(flrj);
4097 
4098  WM_event_add_notifier(C, space_notifier | NA_JOB_FINISHED, NULL);
4099  return;
4100  }
4101 
4102  /* setup job */
4103  wm_job = WM_jobs_get(CTX_wm_manager(C),
4104  CTX_wm_window(C),
4105  filelist,
4106  "Listing Dirs...",
4110  WM_jobs_timer(wm_job, 0.01, space_notifier, space_notifier | NA_JOB_FINISHED);
4113 
4114  /* start the job */
4115  WM_jobs_start(CTX_wm_manager(C), wm_job);
4116 }
4117 
4119 {
4121 }
4122 
4124 {
4126 }
typedef float(TangentPoint)[2]
void BKE_asset_metadata_free(struct AssetMetaData **asset_data)
Definition: asset.cc:35
struct PreviewImage * BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data, const struct ID *owner_id)
struct AssetLibrary AssetLibrary
struct AssetLibrary * BKE_asset_library_load(const char *library_path)
bool BKE_asset_library_find_suitable_root_path_from_main(const struct Main *bmain, char r_library_path[768])
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
struct ImBuf * BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT
Definition: icons.cc:817
int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT
Definition: icons.cc:807
bool BKE_icon_delete(int icon_id)
Definition: icons.cc:888
struct ImBuf * BKE_previewimg_to_imbuf(struct PreviewImage *prv, int size)
Definition: icons.cc:567
bool BKE_previewimg_is_finished(const struct PreviewImage *prv, int size)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition: idtype.c:142
uint64_t BKE_idtype_idcode_to_idfilter(short idcode)
Definition: idtype.c:206
short BKE_idtype_idcode_from_name(const char *idtype_name)
Definition: idtype.c:163
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:367
void BKE_main_unlock(struct Main *bmain)
Definition: main.c:219
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
void BKE_main_lock(struct Main *bmain)
Definition: main.c:214
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:361
struct ListBase * which_libbase(struct Main *bmain, short type)
Definition: main.c:567
const char * BKE_main_blendfile_path_from_global(void)
Definition: main.c:562
struct bUserAssetLibrary * BKE_preferences_asset_library_find_from_index(const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
char * BLF_display_name_from_file(const char *filepath)
Definition: blf.c:886
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
File and directory operations.
eFileAttributes BLI_file_attributes(const char *path)
Definition: storage.c:198
#define FILE_ATTR_ANY_LINK
Definition: BLI_fileops.h:105
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:402
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist)
Definition: BLI_filelist.c:218
struct stat BLI_stat_t
Definition: BLI_fileops.h:73
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:397
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
Definition: BLI_filelist.c:420
eFileAttributes
Definition: BLI_fileops.h:86
@ FILE_ATTR_ALIAS
Definition: BLI_fileops.h:97
@ FILE_ATTR_TEMPORARY
Definition: BLI_fileops.h:94
@ FILE_ATTR_HIDDEN
Definition: BLI_fileops.h:88
@ FILE_ATTR_SYSTEM
Definition: BLI_fileops.h:89
@ FILE_ATTR_OFFLINE
Definition: BLI_fileops.h:96
bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT
Some types for dealing with directories.
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:858
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:689
bool BLI_ghashutil_intcmp(const void *a, const void *b)
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_ghashutil_inthash_p(const void *ptr)
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:681
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:790
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:805
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:748
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, unsigned int nentries_reserve)
Definition: BLI_ghash.c:845
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
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:354
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
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:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT 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, int size, int val)
Definition: math_vector.c:1223
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL()
Definition: path_util.c:639
bool BLI_path_extension_check_array(const char *str, const char **ext_array) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1326
const char * BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1653
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2)
Definition: path_util.c:221
#define FILE_MAXFILE
#define FILE_MAX
#define FILENAME_IS_CURRENT(_n)
#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:1341
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL()
Definition: path_util.c:1393
bool BLI_path_extension_check(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1299
bool BLI_path_contains(const char *container_path, const char *containee_path) ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1717
int BLI_path_slash_ensure(char *string) ATTR_NONNULL()
Definition: path_util.c:1780
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL()
Definition: path_util.c:450
#define FILENAME_PARENT
const char * BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1765
bool BLI_path_extension_check_n(const char *str,...) ATTR_NONNULL(1) ATTR_SENTINEL(0)
Definition: path_util.c:1304
#define FILE_MAXDIR
#define BLI_path_cmp
#define FILENAME_IS_PARENT(_n)
void BLI_join_dirfile(char *__restrict dst, size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1531
void * BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:101
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:166
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:247
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:94
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:173
#define BLI_stack_new(esize, descr)
size_t size_t char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define STRNCPY_RLEN(dst, src)
Definition: BLI_string.h:484
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:538
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:623
int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:786
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:719
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, char pad, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:78
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
@ TASK_PRIORITY_LOW
Definition: BLI_task.h:56
void * BLI_task_pool_user_data(TaskPool *pool)
Definition: task_pool.cc:525
void BLI_task_pool_cancel(TaskPool *pool)
Definition: task_pool.cc:495
TaskPool * BLI_task_pool_create_background(void *userdata, eTaskPriority priority)
Definition: task_pool.cc:407
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:440
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:459
void BLI_thread_queue_push(ThreadQueue *queue, void *work)
Definition: threads.cc:641
void BLI_mutex_end(ThreadMutex *mutex)
Definition: threads.cc:388
void * BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
Definition: threads.cc:711
void BLI_mutex_init(ThreadMutex *mutex)
Definition: threads.cc:368
void BLI_thread_queue_free(ThreadQueue *queue)
Definition: threads.cc:629
bool BLI_thread_queue_is_empty(ThreadQueue *queue)
Definition: threads.cc:756
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:373
void BLI_thread_queue_nowait(ThreadQueue *queue)
Definition: threads.cc:767
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:378
void * BLI_thread_queue_pop(ThreadQueue *queue)
Definition: threads.cc:652
ThreadQueue * BLI_thread_queue_init(void)
Definition: threads.cc:615
pthread_mutex_t ThreadMutex
Definition: BLI_threads.h:82
#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[4])
#define S_ISDIR(x)
Definition: BLI_winstuff.h:48
external readfile function prototypes.
BlendHandle * BLO_blendhandle_from_file(const char *filepath, struct BlendFileReadReport *reports)
Definition: readblenentry.c:48
#define BLO_GROUP_MAX
Definition: BLO_readfile.h:296
struct BlendHandle BlendHandle
Definition: BLO_readfile.h:35
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition: readfile.c:1503
struct LinkNode * BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, bool use_assets_only, int *r_tot_info_items)
bool BLO_has_bfile_extension(const char *str)
Definition: readfile.c:1497
struct LinkNode * BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
void BLO_blendhandle_close(BlendHandle *bh)
#define FILTER_ID_ALL
Definition: DNA_ID.h:939
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define MAX_ID_NAME
Definition: DNA_ID.h:337
@ LIB_FAKEUSER
Definition: DNA_ID.h:630
@ ICON_SIZE_PREVIEW
Definition: DNA_ID_enums.h:16
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_OB
Definition: DNA_ID_enums.h:47
@ ASSET_LIBRARY_CUSTOM
#define R_BG_RENDER
@ FILE_SORT_DEFAULT
@ FILE_SORT_ALPHA
@ FILE_SORT_TIME
@ FILE_SORT_EXTENSION
@ FILE_SORT_SIZE
eFileSelectType
@ FILE_LOADLIB
@ FILE_ASSET_LIBRARY
@ FILE_MAIN_ASSET
@ FILE_MAIN
eFileSel_File_Types
@ FILE_TYPE_BTX
@ FILE_TYPE_BLENDER
@ FILE_TYPE_ASSET
@ FILE_TYPE_BUNDLE
@ FILE_TYPE_ALEMBIC
@ FILE_TYPE_ARCHIVE
@ FILE_TYPE_TEXT
@ FILE_TYPE_COLLADA
@ FILE_TYPE_PYSCRIPT
@ FILE_TYPE_BLENDER_BACKUP
@ FILE_TYPE_VOLUME
@ 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_PREVIEW_LOADING
@ FILE_ENTRY_NAME_FREE
@ FILE_ENTRY_INVALID_PREVIEW
eFileSel_Params_AssetCatalogVisibility
eFileBrowse_Mode
@ FILE_SEL_SELECTED
#define FILE_MAX_LIBEXTRA
const char datatoc_prvicons_png[]
int datatoc_prvicons_png_size
eFileIndexerResult
@ FILE_INDEXER_ENTRIES_LOADED
void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries)
Definition: file_indexer.cc:75
void ED_file_indexer_entries_extend_from_datablock_infos(FileIndexerEntries *indexer_entries, const LinkNode *datablock_infos, int idcode)
Definition: file_indexer.cc:56
FSMenuCategory
@ FS_CATEGORY_SYSTEM_BOOKMARKS
@ FS_CATEGORY_OTHER
@ FS_CATEGORY_SYSTEM
struct FSMenu * ED_fsmenu_get(void)
Definition: fsmenu.c:63
struct FSMenuEntry * ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
Definition: fsmenu.c:71
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 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
_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 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 order
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
bool IMB_isanim(const char *filepath)
Definition: util.c:385
struct ImBuf * IMB_ibImageFromMemory(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
Definition: readimage.c:84
Contains defines and structs used throughout the imbuf module.
const char * imb_ext_movie[]
Definition: util.c:81
const char * imb_ext_audio[]
Definition: util.c:88
@ IB_rect
const char * imb_ext_image[]
Definition: util.c:43
@ THB_LARGE
Definition: IMB_thumbs.h:24
void IMB_thumb_locks_release(void)
Definition: thumbs.c:655
ThumbSource
Definition: IMB_thumbs.h:28
@ THB_SOURCE_IMAGE
Definition: IMB_thumbs.h:29
@ THB_SOURCE_FONT
Definition: IMB_thumbs.h:32
@ THB_SOURCE_BLEND
Definition: IMB_thumbs.h:31
@ THB_SOURCE_MOVIE
Definition: IMB_thumbs.h:30
void IMB_thumb_path_unlock(const char *path)
Definition: thumbs.c:686
struct ImBuf * IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
Definition: thumbs.c:516
void IMB_thumb_path_lock(const char *path)
Definition: thumbs.c:670
struct ImBuf * IMB_thumb_read(const char *filepath, ThumbSize size)
Definition: thumbs.c:482
void IMB_thumb_locks_acquire(void)
Definition: thumbs.c:639
void IMB_thumb_ensure_translations(void)
Definition: thumbs_font.c:37
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
int UI_icon_from_idcode(int idcode)
@ WM_JOB_PROGRESS
Definition: WM_api.h:1339
@ WM_JOB_TYPE_FILESEL_READDIR
Definition: WM_api.h:1357
#define NA_JOB_FINISHED
Definition: WM_types.h:531
void file_ensure_updated_catalog_filter_data(FileAssetCatalogFilterSettingsHandle *filter_settings_handle, const ::AssetLibrary *asset_library)
FileAssetCatalogFilterSettingsHandle * file_create_asset_catalog_filter_settings()
bool file_is_asset_visible_in_catalog_filter_settings(const FileAssetCatalogFilterSettingsHandle *filter_settings_handle, const AssetMetaData *asset_data)
void file_delete_asset_catalog_filter_settings(FileAssetCatalogFilterSettingsHandle **filter_settings_handle)
bool file_set_asset_catalog_filter_settings(FileAssetCatalogFilterSettingsHandle *filter_settings_handle, eFileSel_Params_AssetCatalogVisibility catalog_visibility, ::bUUID catalog_id)
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)
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
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
CCL_NAMESPACE_BEGIN struct Options options
FILE * file
bool is_valid
void * user_data
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
#define str(s)
const FileIndexerType file_indexer_noop
Definition: file_indexer.cc:81
struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle
Definition: file_intern.h:209
int ED_file_icon(const FileDirEntry *file)
Definition: filelist.c:1456
#define FILELIST_ENTRYCACHESIZE_DEFAULT
Definition: filelist.c:300
static bool filelist_readjob_should_recurse_into_entry(const int max_recursion, const bool is_lib, const int current_recursion_level, FileListInternEntry *entry)
Definition: filelist.c:3570
void filelist_set_asset_catalog_filter_options(FileList *filelist, eFileSel_Params_AssetCatalogVisibility catalog_visibility, const bUUID *catalog_id)
Definition: filelist.c:1180
void filelist_tag_force_reset(FileList *filelist)
Definition: filelist.c:2145
static void filelist_readjob_list_lib_add_from_indexer_entries(ListBase *entries, const FileIndexerEntries *indexer_entries, const bool prefix_relpath_with_group_name)
Definition: filelist.c:3189
ImBuf * filelist_geticon_image(struct FileList *filelist, const int index)
Definition: filelist.c:1327
int filelist_files_num_entries(FileList *filelist)
Definition: filelist.c:2060
static void filelist_readjob_list_lib_add_datablock(ListBase *entries, const BLODataBlockInfo *datablock_info, const bool prefix_relpath_with_group_name, const int idcode, const char *group_name)
Definition: filelist.c:3153
static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
Definition: filelist.c:516
static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter)
Definition: filelist.c:845
static void filelist_readjob_list_lib_add_datablocks(ListBase *entries, LinkNode *datablock_infos, const bool prefix_relpath_with_group_name, const int idcode, const char *group_name)
Definition: filelist.c:3176
void filelist_free(struct FileList *filelist)
Definition: filelist.c:2019
static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params, short *do_update)
Definition: filelist.c:3793
bool filelist_is_ready(struct FileList *filelist)
Definition: filelist.c:2158
static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
Definition: filelist.c:1491
static void filelist_cache_previews_clear(FileListEntryCache *cache)
Definition: filelist.c:1686
void filelist_tag_needs_filtering(FileList *filelist)
Definition: filelist.c:1056
void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
Definition: filelist.c:2630
@ FLC_PREVIEWS_ACTIVE
Definition: filelist.c:335
@ FLC_IS_INIT
Definition: filelist.c:334
static void filelist_readjob_asset_library(struct FileListReadJob *job_params, short *stop, short *do_update, float *progress)
Definition: filelist.c:3878
static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter)
Definition: filelist.c:948
static FileDirEntry * filelist_geticon_get_file(struct FileList *filelist, const int index)
Definition: filelist.c:1289
void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort)
Definition: filelist.c:753
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
Definition: filelist.c:1790
int filelist_needs_reading(FileList *filelist)
Definition: filelist.c:2873
static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
Definition: filelist.c:1615
#define FILEDIR_NBR_ENTRIES_UNSET
Definition: filelist.c:80
void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile)
Definition: filelist.c:202
void filelist_sort(struct FileList *filelist)
Definition: filelist.c:720
void filelist_clear_ex(struct FileList *filelist, const bool do_asset_library, const bool do_cache, const bool do_selection)
Definition: filelist.c:1942
struct FileListInternEntry FileListInternEntry
int filelist_geticon(struct FileList *filelist, const int index, const bool is_main)
Definition: filelist.c:1449
static void filelist_clear_main_files(FileList *filelist, const bool do_asset_library, const bool do_cache, const bool do_selection)
Definition: filelist.c:1970
static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter)
Definition: filelist.c:1029
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2926
struct FileListEntryPreviewTaskData FileListEntryPreviewTaskData
@ FL_NEED_SORTING
Definition: filelist.c:432
@ FL_IS_PENDING
Definition: filelist.c:431
@ FL_SORT_INVERT
Definition: filelist.c:434
@ FL_IS_READY
Definition: filelist.c:430
@ FL_FORCE_RESET_MAIN_FILES
Definition: filelist.c:429
@ FL_NEED_FILTERING
Definition: filelist.c:433
@ FL_FORCE_RESET
Definition: filelist.c:426
static ImBuf * gSpecialFileImages[SPECIAL_IMG_MAX]
Definition: filelist.c:460
int filelist_file_find_path(struct FileList *filelist, const char *filename)
Definition: filelist.c:2285
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group)
Definition: filelist.c:2998
@ SPECIAL_IMG_DRIVE_FIXED
Definition: filelist.c:454
@ SPECIAL_IMG_DRIVE_ATTACHED
Definition: filelist.c:455
@ SPECIAL_IMG_MAX
Definition: filelist.c:457
@ SPECIAL_IMG_DRIVE_DISC
Definition: filelist.c:451
@ SPECIAL_IMG_FOLDER
Definition: filelist.c:452
@ SPECIAL_IMG_DOCUMENT
Definition: filelist.c:450
@ SPECIAL_IMG_PARENT
Definition: filelist.c:453
@ SPECIAL_IMG_DRIVE_REMOTE
Definition: filelist.c:456
struct TodoDir TodoDir
static void filelist_readjob_main_assets(struct FileListReadJob *job_params, short *stop, short *do_update, float *progress)
Definition: filelist.c:3911
FileListTags
Definition: filelist.c:438
@ FILELIST_TAGS_USES_MAIN_DATA
Definition: filelist.c:440
@ FILELIST_TAGS_NO_THREADS
Definition: filelist.c:442
static void filelist_readjob_dir(struct FileListReadJob *job_params, short *stop, short *do_update, float *progress)
Definition: filelist.c:3760
static AssetMetaData * filelist_file_internal_get_asset_data(const FileListInternEntry *file)
Definition: filelist.c:942
void filelist_clear_from_reset_tag(FileList *filelist)
Definition: filelist.c:2005
#define SPECIAL_IMG_COLS
Definition: filelist.c:447
const char * folderlist_peeklastdir(ListBase *folderlist)
Definition: filelist.c:133
#define SPECIAL_IMG_ROWS
Definition: filelist.c:446
static void filelist_direntryarr_free(FileDirEntryArr *array)
Definition: filelist.c:1547
bool filelist_cache_previews_running(FileList *filelist)
Definition: filelist.c:2712
static bool is_filtered_lib_type(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition: filelist.c:1010
static void filelist_readjob_main(struct FileListReadJob *job_params, short *stop, short *do_update, float *progress)
Definition: filelist.c:3902
void filelist_freelib(struct FileList *filelist)
Definition: filelist.c:2047
static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
Definition: filelist.c:1723
static int compare_apply_inverted(int val, const struct FileSortData *sort_data)
Definition: filelist.c:496
static void parent_dir_until_exists_or_default_root(char *dir)
Definition: filelist.c:1469
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:1116
static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
Definition: filelist.c:1480
struct FileListFilter FileListFilter
void filelist_entry_parent_select_set(FileList *filelist, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2988
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2936
struct FileListEntryCache FileListEntryCache
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
Definition: filelist.c:1219
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:3036
static int filelist_readjob_list_lib(const char *root, ListBase *entries, const ListLibOptions options, FileIndexer *indexer_runtime)
Definition: filelist.c:3241
static void filelist_cache_previews_free(FileListEntryCache *cache)
Definition: filelist.c:1704
static void filelist_asset_library_path(const FileListReadJob *job_params, char r_library_root_path[FILE_MAX])
Definition: filelist.c:3776
void folderlist_popdir(struct ListBase *folderlist, char *dir)
Definition: filelist.c:89
uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
Definition: filelist.c:2964
static uint64_t groupname_to_filter_id(const char *group)
Definition: filelist.c:3019
BlendHandle * filelist_lib(struct FileList *filelist)
Definition: filelist.c:2055
void folder_history_list_free(SpaceFile *sfile)
Definition: filelist.c:229
bool filelist_cache_previews_done(FileList *filelist)
Definition: filelist.c:2719
static int groupname_to_code(const char *group)
Definition: filelist.c:3003
void filelist_setdir(struct FileList *filelist, char *r_dir)
Definition: filelist.c:2116
int folderlist_clear_next(struct SpaceFile *sfile)
Definition: filelist.c:145
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition: filelist.c:1024
void filelist_clear(FileList *filelist)
Definition: filelist.c:2000
static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, short *UNUSED(stop), short *do_update, float *UNUSED(progress))
Definition: filelist.c:3816
FileList * filelist_new(short type)
Definition: filelist.c:1875
void folderlist_pushdir(ListBase *folderlist, const char *dir)
Definition: filelist.c:109
struct FileListReadJob FileListReadJob
static void filelist_readjob_endjob(void *flrjv)
Definition: filelist.c:4025
ListBase folder_history_list_duplicate(ListBase *listbase)
Definition: filelist.c:236
struct FolderList FolderList
static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
Definition: filelist.c:2226
struct FileListIntern FileListIntern
static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
Definition: filelist.c:1598
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
Definition: filelist.c:1840
ID * filelist_file_get_id(const FileDirEntry *file)
Definition: filelist.c:2321
int ED_file_extension_icon(const char *path)
Definition: filelist.c:2837
static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
Definition: filelist.c:1663
AssetLibrary * filelist_asset_library(FileList *filelist)
Definition: filelist.c:2042
static int compare_extension(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:665
static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter)
Definition: filelist.c:904
static int compare_size(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:641
void filelist_setrecursion(struct FileList *filelist, const int recursion_level)
Definition: filelist.c:2132
static void filelist_readjob_lib(struct FileListReadJob *job_params, short *stop, short *do_update, float *progress)
Definition: filelist.c:3768
static FileListInternEntry * filelist_readjob_list_lib_navigate_to_parent_entry_create(void)
Definition: filelist.c:3205
#define FILE_UID_UNSET
Definition: filelist.c:2326
bool filelist_cache_previews_update(FileList *filelist)
Definition: filelist.c:2655
static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress)
Definition: filelist.c:3941
static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter)
Definition: filelist.c:983
void folderlist_free(ListBase *folderlist)
Definition: filelist.c:166
static int compare_name(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:603
static void filelist_entry_free(FileDirEntry *entry)
Definition: filelist.c:1541
void filelist_settype(FileList *filelist, short type)
Definition: filelist.c:1888
static void filelist_readjob_do(const bool do_lib, FileListReadJob *job_params, const short *stop, short *do_update, float *progress)
Definition: filelist.c:3742
static void filelist_intern_entry_free(FileListInternEntry *entry)
Definition: filelist.c:1564
int filelist_file_find_id(const FileList *filelist, const ID *id)
Definition: filelist.c:2305
static void filelist_cache_free(FileListEntryCache *cache)
Definition: filelist.c:1816
static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
Definition: filelist.c:3872
static void filelist_clear_asset_library(FileList *filelist)
Definition: filelist.c:1935
struct FileIndexer FileIndexer
static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
Definition: filelist.c:552
static char * fileentry_uiname(const char *root, const char *relpath, const eFileSel_File_Types typeflag, char *buff)
Definition: filelist.c:2065
bool filelist_uid_is_set(const FileUID uid)
Definition: filelist.c:2336
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition: filelist.c:4118
struct FileListEntryPreview FileListEntryPreview
bool filelist_file_cache_block(struct FileList *filelist, const int index)
Definition: filelist.c:2416
static void filelist_readjob_update(void *flrjv)
Definition: filelist.c:3982
static FileDirEntry * filelist_file_create_entry(FileList *filelist, const int index)
Definition: filelist.c:2183
static bool is_filtered_main_assets(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter)
Definition: filelist.c:1036
static bool filelist_compare_asset_libraries(const AssetLibraryReference *library_a, const AssetLibraryReference *library_b)
Definition: filelist.c:1202
void filelist_init_icons(void)
Definition: filelist.c:1245
static ListBase folderlist_duplicate(ListBase *folderlist)
Definition: filelist.c:177
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
Definition: filelist.c:1675
static int filelist_geticon_ex(const FileDirEntry *file, const char *root, const bool is_main, const bool ignore_libdir)
Definition: filelist.c:1333
static void filelist_file_cache_block_release(struct FileList *filelist, const int size, int cursor)
Definition: filelist.c:2391
void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
Definition: filelist.c:2348
static bool filelist_file_cache_block_create(FileList *filelist, const int start_index, const int size, int cursor)
Definition: filelist.c:2365
static bool is_filtered_file_type(const FileListInternEntry *file, const FileListFilter *filter)
Definition: filelist.c:870
ImBuf * filelist_geticon_image_ex(const FileDirEntry *file)
Definition: filelist.c:1308
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, uint flag, FileCheckType check)
Definition: filelist.c:2879
static bool is_hidden_dot_filename(const char *filename, const FileListInternEntry *file)
Definition: filelist.c:768
FileDirEntry * filelist_file(struct FileList *filelist, int index)
Definition: filelist.c:2280
static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist), char *UNUSED(r_dir), const bool UNUSED(do_change))
Definition: filelist.c:1516
static int compare_date(void *user_data, const void *a1, const void *a2)
Definition: filelist.c:617
int ED_path_extension_type(const char *path)
Definition: filelist.c:2759
@ FLF_DO_FILTER
Definition: filelist.c:364
@ FLF_HIDE_LIB_DIR
Definition: filelist.c:367
@ FLF_HIDE_PARENT
Definition: filelist.c:366
@ FLF_ASSETS_ONLY
Definition: filelist.c:368
@ FLF_HIDE_DOT
Definition: filelist.c:365
bool filelist_pending(struct FileList *filelist)
Definition: filelist.c:2163
int filelist_readjob_running(FileList *filelist, wmWindowManager *wm)
Definition: filelist.c:4123
struct FileList FileList
void filelist_filter(FileList *filelist)
Definition: filelist.c:1061
static bool is_filtered_hidden(const char *filename, const FileListFilter *filter, const FileListInternEntry *file)
Definition: filelist.c:808
#define SPECIAL_IMG_SIZE
Definition: filelist.c:445
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition: filelist.c:2150
static void filelist_entry_clear(FileDirEntry *entry)
Definition: filelist.c:1524
static bool is_filtered_file_name(const FileListInternEntry *file, const FileListFilter *filter)
Definition: filelist.c:859
static FileFolderHistory * folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode)
Definition: filelist.c:191
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition: filelist.c:2168
int filelist_files_ensure(FileList *filelist)
Definition: filelist.c:2173
static bool is_filtered_asset_library(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition: filelist.c:1045
bool filelist_entry_is_selected(FileList *filelist, const int index)
Definition: filelist.c:2975
static void filelist_readjob_recursive_dir_add_items(const bool do_lib, FileListReadJob *job_params, const short *stop, short *do_update, float *progress)
Definition: filelist.c:3606
FileDirEntry * filelist_file_ex(struct FileList *filelist, const int index, const bool use_request)
Definition: filelist.c:2232
static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
Definition: filelist.c:1510
void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
Definition: filelist.c:1172
ImBuf * filelist_getimage(struct FileList *filelist, const int index)
Definition: filelist.c:1296
ImBuf * filelist_file_getimage(const FileDirEntry *file)
Definition: filelist.c:1303
static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history)
Definition: filelist.c:216
ListLibOptions
Definition: filelist.c:3131
@ LIST_LIB_ASSETS_ONLY
Definition: filelist.c:3137
@ LIST_LIB_ADD_PARENT
Definition: filelist.c:3140
@ LIST_LIB_RECURSIVE
Definition: filelist.c:3134
bool filelist_needs_force_reset(FileList *filelist)
Definition: filelist.c:2140
static bool filelist_readjob_is_partial_read(const FileListReadJob *read_job)
Definition: filelist.c:3931
static void filelist_readjob_append_entries(FileListReadJob *job_params, ListBase *from_entries, int from_entries_num, short *do_update)
Definition: filelist.c:3550
bool filelist_is_dir(struct FileList *filelist, const char *path)
Definition: filelist.c:2111
static int filelist_readjob_list_lib_populate_from_index(ListBase *entries, const ListLibOptions options, const int read_from_index, const FileIndexerEntries *indexer_entries)
Definition: filelist.c:3225
void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
Definition: filelist.c:4057
static bool is_filtered_id_file_type(const FileListInternEntry *file, const char *id_group, const char *name, const FileListFilter *filter)
Definition: filelist.c:912
static void filelist_readjob_free(void *flrjv)
Definition: filelist.c:4036
static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry)
Definition: filelist.c:1462
static void filelist_intern_free(FileListIntern *filelist_intern)
Definition: filelist.c:1582
uint filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
Definition: filelist.c:2949
static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data)
Definition: filelist.c:973
void filelist_uid_unset(FileUID *r_uid)
Definition: filelist.c:2343
static bool file_is_blend_backup(const char *str)
Definition: filelist.c:2732
static FileUID filelist_uid_generate(FileList *filelist)
Definition: filelist.c:2328
void filelist_free_icons(void)
Definition: filelist.c:1279
const char * filelist_dir(struct FileList *filelist)
Definition: filelist.c:2106
static FileListInternEntry * filelist_readjob_list_lib_group_create(const int idcode, const char *group_name)
Definition: filelist.c:3143
uint32_t FileUID
Definition: filelist.h:22
FileSelType
Definition: filelist.h:26
@ FILE_SEL_REMOVE
Definition: filelist.h:27
@ FILE_SEL_ADD
Definition: filelist.h:28
@ FILE_SEL_TOGGLE
Definition: filelist.h:29
FileCheckType
Definition: filelist.h:32
@ CHECK_FILES
Definition: filelist.h:34
@ CHECK_DIRS
Definition: filelist.h:33
@ CHECK_ALL
Definition: filelist.h:35
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define GS(x)
Definition: iris.c:225
ccl_global const KernelWorkTile * tile
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken preview("preview", pxr::TfToken::Immortal)
static void update(bNodeTree *ntree)
return ret
__int64 int64_t
Definition: stdint.h:89
unsigned __int64 uint64_t
Definition: stdint.h:90
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
User defined tag. Currently only used by assets, could be used more often at some point....
struct AssetMetaData * asset_data
Definition: BLO_readfile.h:184
struct ReportList * reports
Definition: BLO_readfile.h:80
struct FSMenuEntry * next
Definition: fsmenu.c:53
struct FileDirEntry * next
char * redirection_path
struct LinkNode * entries
struct BLODataBlockInfo datablock_info
FileIndexerUpdateIndexFunc update_index
FileIndexerFinishedFunc filelist_finished
FileIndexerReadIndexFunc read_index
FileIndexerFreeUserDataFunc free_user_data
FileIndexerInitUserDataFunc init_user_data
void * user_data
Definition: filelist.c:3222
const FileIndexerType * callbacks
Definition: filelist.c:3217
TaskPool * previews_pool
Definition: filelist.c:324
ThreadQueue * previews_done
Definition: filelist.c:325
ListBase cached_entries
Definition: filelist.c:307
GHash * misc_entries
Definition: filelist.c:318
int * misc_entries_indices
Definition: filelist.c:317
FileDirEntry ** block_entries
Definition: filelist.c:311
FileListEntryPreview * preview
Definition: filelist.c:349
char filepath[FILE_MAX]
Definition: filelist.c:339
char filter_glob[FILE_MAXFILE]
Definition: filelist.c:355
FileAssetCatalogFilterSettingsHandle * asset_catalog_filter
Definition: filelist.c:359
char filter_search[66]
Definition: filelist.c:356
uint64_t filter_id
Definition: filelist.c:354
uint64_t filter
Definition: filelist.c:353
PreviewImage * preview_image
Definition: filelist.c:280
eFileAttributes attributes
Definition: filelist.c:288
struct FileListInternEntry * next
Definition: filelist.c:253
struct FileListInternEntry::@527 local_data
struct FileListInternEntry * prev
Definition: filelist.c:253
char * redirection_path
Definition: filelist.c:264
BLI_stat_t st
Definition: filelist.c:289
AssetMetaData * imported_asset_data
Definition: filelist.c:285
ListBase entries
Definition: filelist.c:294
FileUID curr_uid
Definition: filelist.c:297
FileListInternEntry ** filtered
Definition: filelist.c:295
struct FileList * filelist
Definition: filelist.c:3532
ThreadMutex lock
Definition: filelist.c:3529
struct FileList * tmp_filelist
Definition: filelist.c:3547
Main * current_main
Definition: filelist.c:3531
bool only_main_data
Definition: filelist.c:3535
char main_name[FILE_MAX]
Definition: filelist.c:3530
struct AssetLibrary * asset_library
Definition: filelist.c:378
FileDirEntryArr filelist
Definition: filelist.c:373
struct BlendHandle * libfiledata
Definition: filelist.c:406
short sort
Definition: filelist.c:382
bool(* check_dir_fn)(struct FileList *, char *, const bool)
Definition: filelist.c:411
short flags
Definition: filelist.c:380
bool(* filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *)
Definition: filelist.c:417
AssetLibraryReference * asset_library_ref
Definition: filelist.c:377
struct FileListIntern filelist_intern
Definition: filelist.c:391
short tags
Definition: filelist.c:421
GHash * selection_state
Definition: filelist.c:401
short max_recursion
Definition: filelist.c:403
struct FileListEntryCache filelist_cache
Definition: filelist.c:393
void(* read_job_fn)(struct FileListReadJob *, short *, short *, float *)
Definition: filelist.c:414
const struct FileIndexerType * indexer
Definition: filelist.c:389
eFileSelectType type
Definition: filelist.c:375
short recursion_level
Definition: filelist.c:404
void(* prepare_filter_fn)(const struct FileList *, FileListFilter *)
Definition: filelist.c:419
FileListFilter filter_data
Definition: filelist.c:384
bool inverted
Definition: filelist.c:493
struct FolderList * next
Definition: filelist.c:85
char * foldername
Definition: filelist.c:86
struct FolderList * prev
Definition: filelist.c:85
Definition: DNA_ID.h:368
struct AssetMetaData * asset_data
Definition: DNA_ID.h:375
struct Library * lib
Definition: DNA_ID.h:372
int us
Definition: DNA_ID.h:388
short flag
Definition: DNA_ID.h:383
void * next
Definition: DNA_ID.h:369
char name[66]
Definition: DNA_ID.h:378
unsigned int * rect
char filepath[1024]
Definition: DNA_ID.h:461
struct LinkNode * next
Definition: BLI_linklist.h:23
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase * folders_prev
ListBase * folders_next
ListBase folder_histories
int level
Definition: filelist.c:3032
char * dir
Definition: filelist.c:3033
Universally Unique Identifier according to RFC4122.
struct stat s
const char * relname
Definition: wm_jobs.c:57
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:437
void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:572
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition: wm_jobs.c:351
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *))
Definition: wm_jobs.c:323
void WM_jobs_timer(wmJob *wm_job, double timestep, unsigned int note, unsigned int endnote)
Definition: wm_jobs.c:339
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, int flag, int job_type)
Definition: wm_jobs.c:184