Blender V4.5
filelist.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* global includes */
10
11#include <algorithm>
12#include <cstdlib>
13#include <cstring>
14#include <ctime>
15#include <memory>
16#include <optional>
17#include <sys/stat.h>
18
19#ifndef WIN32
20# include <unistd.h>
21#else
22# include <direct.h>
23# include <io.h>
24#endif
25
26#include "AS_asset_library.hh"
28
29#include "MEM_guardedalloc.h"
30
31#include "BLF_api.hh"
32
33#include "BLI_fileops.h"
34#include "BLI_fileops_types.h"
35#include "BLI_fnmatch.h"
36#include "BLI_ghash.h"
37#include "BLI_linklist.h"
38#include "BLI_listbase.h"
39#include "BLI_math_vector.h"
40#include "BLI_path_utils.hh"
41#include "BLI_stack.h"
42#include "BLI_string.h"
43#include "BLI_string_utils.hh"
44#include "BLI_task.h"
45#include "BLI_threads.h"
46#include "BLI_utildefines.h"
47
48#ifdef WIN32
49# include "BLI_winstuff.h"
50#endif
51
52#include "BKE_asset.hh"
53#include "BKE_blendfile.hh"
54#include "BKE_context.hh"
55#include "BKE_global.hh"
56#include "BKE_icons.h"
57#include "BKE_idtype.hh"
58#include "BKE_main.hh"
59#include "BKE_preferences.h"
60#include "BKE_preview_image.hh"
61
62#include "DNA_asset_types.h"
63#include "DNA_space_types.h"
64#include "DNA_userdef_types.h"
65
66#include "ED_fileselect.hh"
67
68#include "IMB_imbuf.hh"
69#include "IMB_imbuf_types.hh"
70#include "IMB_thumbs.hh"
71
72#include "MOV_util.hh"
73
74#include "WM_api.hh"
75#include "WM_types.hh"
76
77#include "UI_interface_icons.hh"
78#include "UI_resources.hh"
79
80#include "atomic_ops.h"
81
82#include "file_indexer.hh"
83#include "file_intern.hh"
84#include "filelist.hh"
85
86using namespace blender;
87
88#define FILEDIR_NBR_ENTRIES_UNSET -1
89
90/* ------------------FILELIST------------------------ */
91
93 FileListInternEntry *next = nullptr, *prev = nullptr;
94
96
99 int blentype = 0;
100
101 char *relpath = nullptr;
103 char *redirection_path = nullptr;
105 const char *name = nullptr;
106 bool free_name = false;
107
113 struct {
115 ID *id = nullptr;
116
117 /* For the few file types that have the preview already in memory. For others, there's delayed
118 * preview reading from disk. Non-owning pointer. */
121
129 std::weak_ptr<asset_system::AssetRepresentation> asset;
130
131 /* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */
133
137
143 {
144 if (std::shared_ptr<asset_system::AssetRepresentation> asset_ptr = asset.lock()) {
145 /* Returning a raw pointer from a shared pointer and destructing the shared pointer
146 * immediately afterwards isn't entirely clean. But it's just a way to get the raw pointer
147 * from the weak pointer. Nothing should free the asset in the asset library meanwhile, so
148 * this should be fine really. */
149 BLI_assert(asset_ptr.use_count() > 1);
150 return asset_ptr.get();
151 }
152 return nullptr;
153 }
154};
155
160
161 FileUID curr_uid; /* Used to generate UID during internal listing. */
162};
163
164#define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */
166 size_t size; /* The size of the cache... */
167
168 int flags;
169
170 /* This one gathers all entries from both block and misc caches. Used for easy bulk-freeing. */
172
173 /* Block cache: all entries between start and end index.
174 * used for part of the list on display. */
177
178 /* Misc cache: random indices, FIFO behavior.
179 * NOTE: Not 100% sure we actually need that, time will say. */
183
184 /* Allows to quickly get a cached entry from its UID. */
186
187 /* Previews handling. */
194};
195
197enum {
198 FLC_IS_INIT = 1 << 0,
200};
201
209
210/* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing
211 * tasks' data (see #74609). */
215
225
227enum {
229 FLF_HIDE_DOT = 1 << 1,
233};
234
235struct FileListReadJob;
236struct FileList {
238
240 /* The library this list was created for. Stored here so we know when to re-read. */
243
244 short flags;
245
246 short sort;
247
249
254
256
258
270
273
274 BlendHandle *libfiledata;
275
283 char dirpath[FILE_MAX_LIBEXTRA],
284 const bool do_change);
285
287 void (*read_job_fn)(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress);
288
290 bool (*filter_fn)(FileListInternEntry *file, const char *root, FileListFilter *filter);
293
295 short tags;
296};
297
299enum {
301 /* Don't do a full reset (unless #FL_FORCE_RESET is also set), only reset files representing main
302 * data (assets from the current file/#Main). */
304 FL_IS_READY = 1 << 2,
312};
313
321
326 /* Keep this last. */
328};
329
331
332static void filelist_readjob_main(FileListReadJob *job_params,
333 bool *stop,
334 bool *do_update,
335 float *progress);
336static void filelist_readjob_lib(FileListReadJob *job_params,
337 bool *stop,
338 bool *do_update,
339 float *progress);
340static void filelist_readjob_dir(FileListReadJob *job_params,
341 bool *stop,
342 bool *do_update,
343 float *progress);
344static void filelist_readjob_asset_library(FileListReadJob *job_params,
345 bool *stop,
346 bool *do_update,
347 float *progress);
348static void filelist_readjob_main_assets(FileListReadJob *job_params,
349 bool *stop,
350 bool *do_update,
351 float *progress);
353 bool *stop,
354 bool *do_update,
355 float *progress);
356
357/* helper, could probably go in BKE actually? */
358static int groupname_to_code(const char *group);
359
360static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
361static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry);
362
363/* ********** Sort helpers ********** */
364
367};
368
369static int compare_apply_inverted(int val, const FileSortData *sort_data)
370{
371 return sort_data->inverted ? -val : val;
372}
373
389static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
390{
391 /* Case 1. */
392 {
393 const int order = BLI_strcasecmp_natural(entry1->name, entry2->name);
394 if (order) {
395 return order;
396 }
397 }
398
399 /* Case 2. */
400 if (entry1->local_data.id && entry2->local_data.id) {
401 if (entry1->blentype < entry2->blentype) {
402 return -1;
403 }
404 if (entry1->blentype > entry2->blentype) {
405 return 1;
406 }
407 }
408 /* Case 3. */
409 {
410 if (entry1->local_data.id && !entry2->local_data.id) {
411 return -1;
412 }
413 if (!entry1->local_data.id && entry2->local_data.id) {
414 return 1;
415 }
416 }
417
418 return 0;
419}
420
426 const FileListInternEntry *entry2)
427{
428 /* type is equal to stat.st_mode */
429
430 if (entry1->typeflag & FILE_TYPE_DIR) {
431 if (entry2->typeflag & FILE_TYPE_DIR) {
432 /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs,
433 * then libraries (.blend files), then categories in libraries. */
434 if (entry1->typeflag & FILE_TYPE_BLENDERLIB) {
435 if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
436 return 1;
437 }
438 }
439 else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) {
440 return -1;
441 }
442 else if (entry1->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
444 return 1;
445 }
446 }
447 else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
448 return -1;
449 }
450 }
451 else {
452 return -1;
453 }
454 }
455 else if (entry2->typeflag & FILE_TYPE_DIR) {
456 return 1;
457 }
458
459 /* make sure "." and ".." are always first */
460 if (FILENAME_IS_CURRENT(entry1->relpath)) {
461 return -1;
462 }
463 if (FILENAME_IS_CURRENT(entry2->relpath)) {
464 return 1;
465 }
466 if (FILENAME_IS_PARENT(entry1->relpath)) {
467 return -1;
468 }
469 if (FILENAME_IS_PARENT(entry2->relpath)) {
470 return 1;
471 }
472
473 return 0;
474}
475
476static int compare_name(void *user_data, const void *a1, const void *a2)
477{
478 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
479 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
480 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
481
482 int ret;
483 if ((ret = compare_direntry_generic(entry1, entry2))) {
484 return ret;
485 }
486
487 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
488}
489
490static int compare_date(void *user_data, const void *a1, const void *a2)
491{
492 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
493 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
494 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
495 int64_t time1, time2;
496
497 int ret;
498 if ((ret = compare_direntry_generic(entry1, entry2))) {
499 return ret;
500 }
501
502 time1 = int64_t(entry1->st.st_mtime);
503 time2 = int64_t(entry2->st.st_mtime);
504 if (time1 < time2) {
505 return compare_apply_inverted(1, sort_data);
506 }
507 if (time1 > time2) {
508 return compare_apply_inverted(-1, sort_data);
509 }
510
511 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
512}
513
514static int compare_size(void *user_data, const void *a1, const void *a2)
515{
516 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
517 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
518 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
519 uint64_t size1, size2;
520 int ret;
521
522 if ((ret = compare_direntry_generic(entry1, entry2))) {
523 return ret;
524 }
525
526 size1 = entry1->st.st_size;
527 size2 = entry2->st.st_size;
528 if (size1 < size2) {
529 return compare_apply_inverted(1, sort_data);
530 }
531 if (size1 > size2) {
532 return compare_apply_inverted(-1, sort_data);
533 }
534
535 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
536}
537
538static int compare_extension(void *user_data, const void *a1, const void *a2)
539{
540 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
541 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
542 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
543 int ret;
544
545 if ((ret = compare_direntry_generic(entry1, entry2))) {
546 return ret;
547 }
548
549 if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
550 return -1;
551 }
552 if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
553 return 1;
554 }
555 if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
556 if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) {
557 return 1;
558 }
559 if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) {
560 return -1;
561 }
562 if (entry1->blentype < entry2->blentype) {
563 return compare_apply_inverted(-1, sort_data);
564 }
565 if (entry1->blentype > entry2->blentype) {
566 return compare_apply_inverted(1, sort_data);
567 }
568 }
569 else {
570 const char *sufix1, *sufix2;
571
572 if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) {
573 sufix1 = strrchr(entry1->relpath, '.');
574 }
575 if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) {
576 sufix2 = strrchr(entry2->relpath, '.');
577 }
578 if (!sufix1) {
579 sufix1 = "";
580 }
581 if (!sufix2) {
582 sufix2 = "";
583 }
584
585 if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
586 return compare_apply_inverted(ret, sort_data);
587 }
588 }
589
590 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
591}
592
593static int compare_asset_catalog(void *user_data, const void *a1, const void *a2)
594{
595 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
596 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
597 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
598 const asset_system::AssetRepresentation *asset1 = entry1->get_asset();
599 const asset_system::AssetRepresentation *asset2 = entry2->get_asset();
600
601 /* Order non-assets. */
602 if (asset1 && !asset2) {
603 return 1;
604 }
605 if (!asset1 && asset2) {
606 return -1;
607 }
608 if (!asset1 && !asset2) {
609 if (int order = compare_direntry_generic(entry1, entry2); order) {
610 return compare_apply_inverted(order, sort_data);
611 }
612
613 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
614 }
615
616 const asset_system::AssetLibrary &asset_library1 = asset1->owner_asset_library();
617 const asset_system::AssetLibrary &asset_library2 = asset2->owner_asset_library();
618
619 const asset_system::AssetCatalog *catalog1 = asset_library1.catalog_service().find_catalog(
620 asset1->get_metadata().catalog_id);
621 const asset_system::AssetCatalog *catalog2 = asset_library2.catalog_service().find_catalog(
622 asset2->get_metadata().catalog_id);
623
624 /* Order by catalog. Always keep assets without catalog last. */
625 int order = 0;
626
627 if (catalog1 && !catalog2) {
628 order = 1;
629 }
630 else if (!catalog1 && catalog2) {
631 order = -1;
632 }
633 else if (catalog1 && catalog2) {
634 order = BLI_strcasecmp_natural(catalog1->path.c_str(), catalog2->path.c_str());
635 }
636
637 if (!order) {
638 /* Order by name. */
639 order = compare_tiebreaker(entry1, entry2);
640 if (!order) {
641 /* Order by library name. */
642 order = BLI_strcasecmp_natural(asset_library1.name().c_str(), asset_library2.name().c_str());
643 }
644 }
645
646 return compare_apply_inverted(order, sort_data);
647}
648
649void filelist_sort(FileList *filelist)
650{
651 if (filelist->flags & FL_NEED_SORTING) {
652 int (*sort_cb)(void *, const void *, const void *) = nullptr;
653
654 switch (filelist->sort) {
655 case FILE_SORT_ALPHA:
656 sort_cb = compare_name;
657 break;
658 case FILE_SORT_TIME:
659 sort_cb = compare_date;
660 break;
661 case FILE_SORT_SIZE:
662 sort_cb = compare_size;
663 break;
665 sort_cb = compare_extension;
666 break;
668 sort_cb = compare_asset_catalog;
669 break;
671 default:
672 BLI_assert(0);
673 break;
674 }
675
676 FileSortData sort_data{};
677 sort_data.inverted = (filelist->flags & FL_SORT_INVERT) != 0;
678 BLI_listbase_sort_r(&filelist->filelist_intern.entries, sort_cb, &sort_data);
679
681 filelist->flags &= ~FL_NEED_SORTING;
682 }
683}
684
685void filelist_setsorting(FileList *filelist, const short sort, bool invert_sort)
686{
687 const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
688
689 if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
690 filelist->sort = sort;
691 filelist->flags |= FL_NEED_SORTING;
692 filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
693 (filelist->flags & ~FL_SORT_INVERT);
694 }
695}
696
697/* ********** Filter helpers ********** */
698
699/* True if should be hidden, based on current filtering. */
700static bool is_filtered_hidden(const char *filename,
701 const FileListFilter *filter,
702 const FileListInternEntry *file)
703{
704 if ((filename[0] == '.') && (filename[1] == '\0')) {
705 return true; /* Ignore. */
706 }
707
708 if (filter->flags & FLF_HIDE_PARENT) {
709 if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
710 return true; /* Ignore. */
711 }
712 }
713
714 /* Check for _OUR_ "hidden" attribute. This not only mirrors OS-level hidden file
715 * attribute but is also set for Linux/Mac "dot" files. See `filelist_readjob_list_dir`.
716 */
717 if ((filter->flags & FLF_HIDE_DOT) && (file->attributes & FILE_ATTR_HIDDEN)) {
718 return true;
719 }
720
721 /* For data-blocks (but not the group directories), check the asset-only filter. */
722 if (!(file->typeflag & FILE_TYPE_DIR) && (file->typeflag & FILE_TYPE_BLENDERLIB) &&
723 (filter->flags & FLF_ASSETS_ONLY) && !(file->typeflag & FILE_TYPE_ASSET))
724 {
725 return true;
726 }
727
728 return false;
729}
730
736{
737 if (filter->filter_search[0] == '\0') {
738 return true;
739 }
740
741 /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
742 return fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) == 0;
743}
744
750{
751 if (filter->filter_search[0] == '\0') {
752 return true;
753 }
754
755 /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
756 return fnmatch(filter->filter_search, file->name, FNM_CASEFOLD) == 0;
757}
758
761{
762 if (is_filtered_hidden(file->relpath, filter, file)) {
763 return false;
764 }
765
766 if (FILENAME_IS_CURRPAR(file->relpath)) {
767 return false;
768 }
769
770 /* We only check for types if some type are enabled in filtering. */
771 if (filter->filter && (filter->flags & FLF_DO_FILTER)) {
772 if (file->typeflag & FILE_TYPE_DIR) {
775 return false;
776 }
777 }
778 else {
779 if (!(filter->filter & FILE_TYPE_FOLDER)) {
780 return false;
781 }
782 }
783 }
784 else {
785 if (!(file->typeflag & filter->filter)) {
786 return false;
787 }
788 }
789 }
790 return true;
791}
792
795 const char * /*root*/,
797{
798 return is_filtered_file_type(file, filter) &&
800}
801
803 const short id_code,
804 const char *name,
805 const FileListFilter *filter)
806{
807 if (!is_filtered_file_type(file, filter)) {
808 return false;
809 }
810
811 /* We only check for types if some type are enabled in filtering. */
812 if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) {
813 if (id_code) {
814 if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) {
815 return false;
816 }
817
818 const uint64_t filter_id = BKE_idtype_idcode_to_idfilter(id_code);
819 if (!(filter_id & filter->filter_id)) {
820 return false;
821 }
822 }
823 }
824
825 return true;
826}
827
833{
834 if (asset_system::AssetRepresentation *asset = file->get_asset()) {
835 return &asset->get_metadata();
836 }
837 return nullptr;
838}
839
841{
842 /* Not used yet for the asset view template. */
843 if (!filter->asset_catalog_filter) {
844 return;
845 }
847 "prepare_filter_asset_library() should only be called when the file browser is "
848 "in asset browser mode");
849
850 file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library);
851}
852
865static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data)
866{
867 LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) {
868 if (BLI_strcasestr(asset_tag->name, filter_search) != nullptr) {
869 return true;
870 }
871 }
872 return false;
873}
874
876{
878
879 /* Not used yet for the asset view template. */
880 if (filter->asset_catalog_filter &&
881 !file_is_asset_visible_in_catalog_filter_settings(filter->asset_catalog_filter, asset_data))
882 {
883 return false;
884 }
885
886 if (filter->filter_search[0] == '\0') {
887 /* If there is no filter text, everything matches. */
888 return true;
889 }
890
891 /* filter->filter_search contains "*the search text*". */
892 char filter_search[66]; /* sizeof(FileListFilter::filter_search) */
893 const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search);
894
895 /* When doing a name comparison, get rid of the leading/trailing asterisks. */
896 filter_search[string_length - 1] = '\0';
897 if (BLI_strcasestr(file->name, filter_search + 1) != nullptr) {
898 return true;
899 }
900 return asset_tag_matches_filter(filter_search + 1, asset_data);
901}
902
904 const char * /*root*/,
906{
907 if (file->typeflag & FILE_TYPE_BLENDERLIB) {
908 return is_filtered_id_file_type(file, file->blentype, file->name, filter);
909 }
910 return is_filtered_file_type(file, filter);
911}
912
913static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
914{
915 return is_filtered_lib_type(file, root, filter) && is_filtered_file_relpath(file, filter);
916}
917
919 const char * /*dir*/,
921{
922 return !is_filtered_hidden(file->relpath, filter, file);
923}
924
926 const char * /*dir*/,
928{
929 /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */
930 return is_filtered_id_file_type(file, file->blentype, file->name, filter) &&
932}
933
935 const char *root,
937{
939 return is_filtered_main_assets(file, root, filter);
940 }
941
942 return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter);
943}
944
946{
947 filelist->flags |= FL_NEED_FILTERING;
948}
949
951{
952 return (filelist->flags & FL_NEED_FILTERING);
953}
954
956{
957 int num_filtered = 0;
958 const int num_files = filelist->filelist.entries_num;
959 FileListInternEntry **filtered_tmp;
960
962 return;
963 }
964
965 if (!(filelist->flags & FL_NEED_FILTERING)) {
966 /* Assume it has already been filtered, nothing else to do! */
967 return;
968 }
969
971 if (filelist->max_recursion) {
972 /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless
973 * root path is a blend file. */
974 char dir[FILE_MAX_LIBEXTRA];
975 if (!filelist_islibrary(filelist, dir, nullptr)) {
977 }
978 }
979
980 if (filelist->prepare_filter_fn) {
981 filelist->prepare_filter_fn(filelist, &filelist->filter_data);
982 }
983
984 filtered_tmp = static_cast<FileListInternEntry **>(
985 MEM_mallocN(sizeof(*filtered_tmp) * size_t(num_files), __func__));
986
987 /* Filter remap & count how many files are left after filter in a single loop. */
989 if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) {
990 filtered_tmp[num_filtered++] = file;
991 }
992 }
993
994 if (filelist->filelist_intern.filtered) {
996 }
997 filelist->filelist_intern.filtered = static_cast<FileListInternEntry **>(
998 MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * size_t(num_filtered), __func__));
999 memcpy(filelist->filelist_intern.filtered,
1000 filtered_tmp,
1001 sizeof(*filelist->filelist_intern.filtered) * size_t(num_filtered));
1002 filelist->filelist.entries_filtered_num = num_filtered;
1003 // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.entries_num);
1004
1006 filelist->flags &= ~FL_NEED_FILTERING;
1007
1008 MEM_freeN(filtered_tmp);
1009}
1010
1012 const bool do_filter,
1013 const bool hide_dot,
1014 const bool hide_parent,
1015 const uint64_t filter,
1016 const uint64_t filter_id,
1017 const bool filter_assets_only,
1018 const char *filter_glob,
1019 const char *filter_search)
1020{
1021 bool update = false;
1022
1023 if (((filelist->filter_data.flags & FLF_DO_FILTER) != 0) != (do_filter != 0)) {
1024 filelist->filter_data.flags ^= FLF_DO_FILTER;
1025 update = true;
1026 }
1027 if (((filelist->filter_data.flags & FLF_HIDE_DOT) != 0) != (hide_dot != 0)) {
1028 filelist->filter_data.flags ^= FLF_HIDE_DOT;
1029 update = true;
1030 }
1031 if (((filelist->filter_data.flags & FLF_HIDE_PARENT) != 0) != (hide_parent != 0)) {
1032 filelist->filter_data.flags ^= FLF_HIDE_PARENT;
1033 update = true;
1034 }
1035 if (((filelist->filter_data.flags & FLF_ASSETS_ONLY) != 0) != (filter_assets_only != 0)) {
1036 filelist->filter_data.flags ^= FLF_ASSETS_ONLY;
1037 update = true;
1038 }
1039 if (filelist->filter_data.filter != filter) {
1040 filelist->filter_data.filter = filter;
1041 update = true;
1042 }
1043 const uint64_t new_filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL;
1044 if (filelist->filter_data.filter_id != new_filter_id) {
1045 filelist->filter_data.filter_id = new_filter_id;
1046 update = true;
1047 }
1048 if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) {
1049 STRNCPY(filelist->filter_data.filter_glob, filter_glob);
1050 update = true;
1051 }
1052 if (BLI_strcmp_ignore_pad(filelist->filter_data.filter_search, filter_search, '*') != 0) {
1054 filter_search,
1055 '*',
1056 sizeof(filelist->filter_data.filter_search));
1057 update = true;
1058 }
1059
1060 if (update) {
1061 /* And now, free filtered data so that we know we have to filter again. */
1063 }
1064}
1065
1066void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
1067{
1068 BLI_assert(filelist);
1069 BLI_assert(indexer);
1070
1071 filelist->indexer = indexer;
1072}
1073
1075 FileList *filelist,
1076 eFileSel_Params_AssetCatalogVisibility catalog_visibility,
1077 const ::bUUID *catalog_id)
1078{
1079 if (!filelist->filter_data.asset_catalog_filter) {
1080 /* There's no filter data yet. */
1083 }
1084
1085 const bool needs_update = file_set_asset_catalog_filter_settings(
1086 filelist->filter_data.asset_catalog_filter, catalog_visibility, *catalog_id);
1087
1088 if (needs_update) {
1090 }
1091}
1092
1098 const AssetLibraryReference *library_b)
1099{
1100 if (library_a->type != library_b->type) {
1101 return false;
1102 }
1103 if (library_a->type == ASSET_LIBRARY_CUSTOM) {
1104 /* Don't only check the index, also check that it's valid. */
1106 &U, library_a->custom_library_index);
1107 return (library_ptr_a != nullptr) &&
1108 (library_a->custom_library_index == library_b->custom_library_index);
1109 }
1110
1111 return true;
1112}
1113
1114void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
1115{
1116 /* Unset if needed. */
1117 if (!asset_library_ref) {
1118 if (filelist->asset_library_ref) {
1120 filelist->flags |= FL_FORCE_RESET;
1121 }
1122 return;
1123 }
1124
1125 if (!filelist->asset_library_ref) {
1126 filelist->asset_library_ref = MEM_callocN<AssetLibraryReference>("filelist asset library");
1127 *filelist->asset_library_ref = *asset_library_ref;
1128
1129 filelist->flags |= FL_FORCE_RESET;
1130 }
1131 else if (!filelist_compare_asset_libraries(filelist->asset_library_ref, asset_library_ref)) {
1132 *filelist->asset_library_ref = *asset_library_ref;
1133 filelist->flags |= FL_FORCE_RESET;
1134 }
1135}
1136
1137/* ********** Icon/image helpers ********** */
1138
1140{
1141 BLI_assert(G.background == false);
1142
1143 for (int i = 0; i < int(SpecialFileImages::_Max); i++) {
1145 gSpecialFileImages[i] = nullptr;
1146 }
1147}
1148
1150 const FileDirEntry *file,
1151 char r_filepath[FILE_MAX_LIBEXTRA])
1152{
1153 if (file->asset) {
1154 const std::string asset_path = file->asset->full_path();
1155 BLI_strncpy(r_filepath, asset_path.c_str(), FILE_MAX_LIBEXTRA);
1156 return;
1157 }
1158
1159 const char *root = filelist_dir(filelist);
1160 BLI_path_join(r_filepath, FILE_MAX_LIBEXTRA, root, file->relpath);
1161}
1162
1164{
1165 /* Actual preview loading is only started after the filelist is loaded, so the file isn't flagged
1166 * with #FILE_ENTRY_PREVIEW_LOADING yet. */
1167 const bool filelist_ready = filelist_is_ready(filelist);
1168 return !filelist_ready || file->flags & FILE_ENTRY_PREVIEW_LOADING;
1169}
1170
1171static FileDirEntry *filelist_geticon_get_file(FileList *filelist, const int index)
1172{
1173 BLI_assert(G.background == false);
1174
1175 return filelist_file(filelist, index);
1176}
1177
1178ImBuf *filelist_get_preview_image(FileList *filelist, const int index)
1179{
1180 FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1181
1182 return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : nullptr;
1183}
1184
1189
1191{
1192 ImBuf *ibuf = gSpecialFileImages[int(image)];
1193 if (ibuf) {
1194 return ibuf;
1195 }
1196 return gSpecialFileImages[int(image)] = UI_svg_icon_bitmap(icon, 256.0f, false);
1197}
1198
1200{
1201 ImBuf *ibuf = nullptr;
1202
1203 if (file->typeflag & FILE_TYPE_DIR) {
1204 if (FILENAME_IS_PARENT(file->relpath)) {
1205 ibuf = filelist_ensure_special_file_image(SpecialFileImages::Parent, ICON_FILE_PARENT_LARGE);
1206 }
1207 else {
1208 ibuf = filelist_ensure_special_file_image(SpecialFileImages::Folder, ICON_FILE_FOLDER_LARGE);
1209 }
1210 }
1211 else {
1213 }
1214
1215 return ibuf;
1216}
1217
1219{
1220 FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1222}
1223
1224static int filelist_geticon_file_type_ex(const FileList *filelist,
1225 const FileDirEntry *file,
1226 const bool is_main,
1227 const bool ignore_libdir)
1228{
1229 const eFileSel_File_Types typeflag = (eFileSel_File_Types)file->typeflag;
1230
1231 if ((typeflag & FILE_TYPE_DIR) &&
1232 !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER))))
1233 {
1234 if (FILENAME_IS_PARENT(file->relpath)) {
1235 return is_main ? ICON_FILE_PARENT : ICON_NONE;
1236 }
1237 if (typeflag & FILE_TYPE_BUNDLE) {
1238 return ICON_UGLYPACKAGE;
1239 }
1240 if (typeflag & FILE_TYPE_BLENDER) {
1241 return ICON_FILE_BLEND;
1242 }
1243 if (is_main) {
1244 /* Do not return icon for folders if icons are not 'main' draw type
1245 * (e.g. when used over previews). */
1246 return (file->attributes & FILE_ATTR_ANY_LINK) ? ICON_FOLDER_REDIRECT : ICON_FILE_FOLDER;
1247 }
1248
1249 /* If this path is in System list or path cache then use that icon. */
1250 FSMenu *fsmenu = ED_fsmenu_get();
1251 FSMenuCategory categories[] = {
1255 };
1256
1257 for (int i = 0; i < ARRAY_SIZE(categories); i++) {
1258 FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]);
1259 char fullpath[FILE_MAX_LIBEXTRA];
1260 char *target = fullpath;
1261 if (file->redirection_path) {
1262 target = file->redirection_path;
1263 }
1264 else if (filelist) {
1265 filelist_file_get_full_path(filelist, file, fullpath);
1266 BLI_path_slash_ensure(fullpath, sizeof(fullpath));
1267 }
1268 for (; tfsm; tfsm = tfsm->next) {
1269 if (STREQ(tfsm->path, target)) {
1270 /* Never want a little folder inside a large one. */
1271 return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
1272 }
1273 }
1274 }
1275
1276 if (file->attributes & FILE_ATTR_OFFLINE) {
1277 return ICON_ERROR;
1278 }
1279 if (file->attributes & FILE_ATTR_TEMPORARY) {
1280 return ICON_FILE_CACHE;
1281 }
1282 if (file->attributes & FILE_ATTR_SYSTEM) {
1283 return ICON_SYSTEM;
1284 }
1285 }
1286
1287 if (typeflag & FILE_TYPE_BLENDER) {
1288 return (is_main || file->preview_icon_id) ? ICON_FILE_BLEND : ICON_BLENDER;
1289 }
1290 if (typeflag & FILE_TYPE_BLENDER_BACKUP) {
1291 return ICON_FILE_BACKUP;
1292 }
1293 if (typeflag & FILE_TYPE_IMAGE) {
1294 return ICON_FILE_IMAGE;
1295 }
1296 if (typeflag & FILE_TYPE_MOVIE) {
1297 return ICON_FILE_MOVIE;
1298 }
1299 if (typeflag & FILE_TYPE_PYSCRIPT) {
1300 return ICON_FILE_SCRIPT;
1301 }
1302 if (typeflag & FILE_TYPE_SOUND) {
1303 return ICON_FILE_SOUND;
1304 }
1305 if (typeflag & FILE_TYPE_FTFONT) {
1306 return ICON_FILE_FONT;
1307 }
1308 if (typeflag & FILE_TYPE_BTX) {
1309 return ICON_FILE_BLANK;
1310 }
1311 if (typeflag & FILE_TYPE_COLLADA) {
1312 return ICON_FILE_3D;
1313 }
1314 if (typeflag & FILE_TYPE_ALEMBIC) {
1315 return ICON_FILE_3D;
1316 }
1317 if (typeflag & FILE_TYPE_USD) {
1318 return ICON_FILE_3D;
1319 }
1320 if (typeflag & FILE_TYPE_VOLUME) {
1321 return ICON_FILE_VOLUME;
1322 }
1323 if (typeflag & FILE_TYPE_OBJECT_IO) {
1324 return ICON_FILE_3D;
1325 }
1326 if (typeflag & FILE_TYPE_TEXT) {
1327 return ICON_FILE_TEXT;
1328 }
1329 if (typeflag & FILE_TYPE_ARCHIVE) {
1330 return ICON_FILE_ARCHIVE;
1331 }
1332 if (typeflag & FILE_TYPE_BLENDERLIB) {
1333 const int ret = UI_icon_from_idcode(file->blentype);
1334 if (ret != ICON_NONE) {
1335 return ret;
1336 }
1337 }
1338 return is_main ? ICON_FILE_BLANK : ICON_NONE;
1339}
1340
1341int filelist_geticon_file_type(FileList *filelist, const int index, const bool is_main)
1342{
1343 FileDirEntry *file = filelist_geticon_get_file(filelist, index);
1344
1345 return filelist_geticon_file_type_ex(filelist, file, is_main, false);
1346}
1347
1349{
1350 return file->preview_icon_id ? file->preview_icon_id :
1351 filelist_geticon_file_type_ex(nullptr, file, false, false);
1352}
1353
1355{
1356 return intern_entry->local_data.id != nullptr;
1357}
1358
1359/* ********** Main ********** */
1360
1362{
1363 /* Only allow absolute paths as CWD relative doesn't make sense from the UI. */
1365 return;
1366 }
1367
1368#ifdef WIN32
1370#else
1371 ARRAY_SET_ITEMS(dir, '/', '\0');
1372#endif
1373}
1374
1375static bool filelist_checkdir_dir(const FileList * /*filelist*/,
1376 char dirpath[FILE_MAX_LIBEXTRA],
1377 const bool do_change)
1378{
1379 bool is_valid;
1380 if (do_change) {
1382 is_valid = true;
1383 }
1384 else {
1385 is_valid = BLI_path_is_abs_from_cwd(dirpath) && BLI_is_dir(dirpath);
1386 }
1387 return is_valid;
1388}
1389
1390static bool filelist_checkdir_lib(const FileList * /*filelist*/,
1391 char dirpath[FILE_MAX_LIBEXTRA],
1392 const bool do_change)
1393{
1394 char tdir[FILE_MAX_LIBEXTRA];
1395 char *name;
1396
1397 const bool is_valid = (BLI_is_dir(dirpath) ||
1398 (BKE_blendfile_library_path_explode(dirpath, tdir, nullptr, &name) &&
1399 BLI_is_file(tdir) && !name));
1400
1401 if (do_change && !is_valid) {
1402 /* if not a valid library, we need it to be a valid directory! */
1404 return true;
1405 }
1406 return is_valid;
1407}
1408
1409static bool filelist_checkdir_main(const FileList *filelist,
1410 char dirpath[FILE_MAX_LIBEXTRA],
1411 const bool do_change)
1412{
1413 /* TODO */
1414 return filelist_checkdir_lib(filelist, dirpath, do_change);
1415}
1416
1417static bool filelist_checkdir_return_always_valid(const FileList * /*filelist*/,
1418 char /*dirpath*/[FILE_MAX_LIBEXTRA],
1419 const bool /*do_change*/)
1420{
1421 return true;
1422}
1423
1425{
1426 if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) {
1427 MEM_freeN((char *)entry->name);
1428 }
1429 if (entry->relpath) {
1430 MEM_freeN(entry->relpath);
1431 }
1432 if (entry->redirection_path) {
1434 }
1435 if (entry->preview_icon_id) {
1437 entry->preview_icon_id = 0;
1438 }
1439}
1440
1442{
1443 filelist_entry_clear(entry);
1444 MEM_freeN(entry);
1445}
1446
1448{
1449#if 0
1450 FileDirEntry *entry, *entry_next;
1451
1452 for (entry = array->entries.first; entry; entry = entry_next) {
1453 entry_next = entry->next;
1454 filelist_entry_free(entry);
1455 }
1456 BLI_listbase_clear(&array->entries);
1457#else
1459#endif
1460 array->entries_num = FILEDIR_NBR_ENTRIES_UNSET;
1461 array->entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
1462}
1463
1465{
1466 if (auto asset_ptr = entry->asset.lock()) {
1467 BLI_assert(filelist->asset_library);
1468 filelist->asset_library->remove_asset(*asset_ptr);
1469 }
1470
1471 if (entry->relpath) {
1472 MEM_freeN(entry->relpath);
1473 }
1474 if (entry->redirection_path) {
1476 }
1477 if (entry->name && entry->free_name) {
1478 MEM_freeN((char *)entry->name);
1479 }
1480 MEM_delete(entry);
1481}
1482
1483static void filelist_intern_free(FileList *filelist)
1484{
1485 FileListIntern *filelist_intern = &filelist->filelist_intern;
1486 LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
1487 filelist_intern_entry_free(filelist, entry);
1488 }
1489 BLI_listbase_clear(&filelist_intern->entries);
1490
1491 MEM_SAFE_FREE(filelist_intern->filtered);
1492}
1493
1498{
1499 FileListIntern *filelist_intern = &filelist->filelist_intern;
1500 int removed_counter = 0;
1501 LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
1503 continue;
1504 }
1505
1506 BLI_remlink(&filelist_intern->entries, entry);
1507 filelist_intern_entry_free(filelist, entry);
1508 removed_counter++;
1509 }
1510
1511 if (removed_counter > 0) {
1512 MEM_SAFE_FREE(filelist_intern->filtered);
1513 }
1514 return removed_counter;
1515}
1516
1517static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
1518{
1519 FileListEntryCache *cache = static_cast<FileListEntryCache *>(BLI_task_pool_user_data(pool));
1520 FileListEntryPreviewTaskData *preview_taskdata = static_cast<FileListEntryPreviewTaskData *>(
1521 taskdata);
1522 FileListEntryPreview *preview = preview_taskdata->preview;
1523
1524 /* XXX #THB_SOURCE_IMAGE for "historic" reasons. The case of an undefined source should be
1525 * handled better. */
1527
1528 // printf("%s: Start (%d)...\n", __func__, threadid);
1529
1530 // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
1531 BLI_assert(preview->flags &
1534
1535 if (preview->flags & FILE_TYPE_IMAGE) {
1536 source = THB_SOURCE_IMAGE;
1537 }
1539 {
1540 source = THB_SOURCE_BLEND;
1541 }
1542 else if (preview->flags & FILE_TYPE_MOVIE) {
1543 source = THB_SOURCE_MOVIE;
1544 }
1545 else if (preview->flags & FILE_TYPE_FTFONT) {
1546 source = THB_SOURCE_FONT;
1547 }
1548 else if (preview->flags & FILE_TYPE_OBJECT_IO) {
1549 source = THB_SOURCE_OBJECT_IO;
1550 }
1551
1552 IMB_thumb_path_lock(preview->filepath);
1553 /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
1554 * in case user switch to a bigger preview size. */
1555 ImBuf *imbuf = IMB_thumb_manage(preview->filepath, THB_LARGE, source);
1557 if (imbuf) {
1559 }
1560
1561 /* Move ownership to the done queue. */
1562 preview_taskdata->preview = nullptr;
1563
1564 BLI_thread_queue_push(cache->previews_done, preview);
1565
1566 // printf("%s: End (%d)...\n", __func__, threadid);
1567}
1568
1569static void filelist_cache_preview_freef(TaskPool *__restrict /*pool*/, void *taskdata)
1570{
1571 FileListEntryPreviewTaskData *preview_taskdata = static_cast<FileListEntryPreviewTaskData *>(
1572 taskdata);
1573
1574 /* In case the preview wasn't moved to the "done" queue yet. */
1575 if (preview_taskdata->preview) {
1576 MEM_freeN(preview_taskdata->preview);
1577 }
1578
1579 MEM_freeN(preview_taskdata);
1580}
1581
1592
1594{
1595 if (cache->previews_pool) {
1597
1598 LISTBASE_FOREACH (FileDirEntry *, entry, &cache->cached_entries) {
1599 entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING;
1600 }
1601
1602 FileListEntryPreview *preview;
1603 while ((preview = static_cast<FileListEntryPreview *>(
1605 {
1606 // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path,
1607 // preview->img);
1608 if (preview->icon_id) {
1609 BKE_icon_delete(preview->icon_id);
1610 }
1611 MEM_freeN(preview);
1612 }
1613 cache->previews_todo_count = 0;
1614 }
1615}
1616
1618{
1619 if (cache->previews_pool) {
1621
1623
1626 cache->previews_pool = nullptr;
1627 cache->previews_done = nullptr;
1628 cache->previews_todo_count = 0;
1629
1631 }
1632
1633 cache->flags &= ~FLC_PREVIEWS_ACTIVE;
1634}
1635
1642{
1644 return false;
1645 }
1646
1647 if (!(entry->typeflag &
1650 {
1651 return false;
1652 }
1653
1654 /* If we know this is an external ID without a preview, skip loading the preview. Can save quite
1655 * some time in heavy files, because otherwise for each missing preview and for each preview
1656 * reload, we'd reopen the .blend to look for the preview. */
1657 if ((entry->typeflag & FILE_TYPE_BLENDERLIB) &&
1659 {
1660 return false;
1661 }
1662
1663 /* External ID that is also a directory is never previewed. */
1664 if ((entry->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR)) ==
1666 {
1667 return false;
1668 }
1669
1670 return true;
1671}
1672
1677static bool filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
1678{
1679 FileListEntryCache *cache = &filelist->filelist_cache;
1680
1682
1683 if (entry->preview_icon_id) {
1684 return false;
1685 }
1686
1687 if (!filelist_file_preview_load_poll(entry)) {
1688 return false;
1689 }
1690
1691 FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
1692 const PreviewImage *preview_in_memory = intern_entry->local_data.preview_image;
1693 if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) {
1694 /* Nothing to set yet. Wait for next call. */
1695 return false;
1696 }
1697
1700
1702 preview->index = index;
1703 preview->flags = entry->typeflag;
1704 preview->icon_id = 0;
1705
1706 if (preview_in_memory) {
1707 /* TODO(mano-wii): No need to use the thread API here. */
1709 preview->filepath[0] = '\0';
1711 if (imbuf) {
1713 }
1714 BLI_thread_queue_push(cache->previews_done, preview);
1715 }
1716 else {
1717 if (entry->redirection_path) {
1719 }
1720 else {
1721 filelist_file_get_full_path(filelist, entry, preview->filepath);
1722 }
1723 // printf("%s: %d - %s\n", __func__, preview->index, preview->filepath);
1724
1726 __func__);
1727 preview_taskdata->preview = preview;
1730 preview_taskdata,
1731 true,
1733 }
1734 cache->previews_todo_count++;
1735
1736 return true;
1737}
1738
1739static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
1740{
1742
1743 cache->block_cursor = cache->block_start_index = cache->block_center_index =
1744 cache->block_end_index = 0;
1745 cache->block_entries = static_cast<FileDirEntry **>(
1746 MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__));
1747
1748 cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size);
1749 cache->misc_entries_indices = MEM_malloc_arrayN<int>(cache_size, __func__);
1750 copy_vn_i(cache->misc_entries_indices, cache_size, -1);
1751 cache->misc_cursor = 0;
1752
1753 cache->uids = BLI_ghash_new_ex(
1754 BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__, cache_size * 2);
1755
1756 cache->size = cache_size;
1757 cache->flags = FLC_IS_INIT;
1758
1759 cache->previews_todo_count = 0;
1760}
1761
1763{
1764 if (!(cache->flags & FLC_IS_INIT)) {
1765 return;
1766 }
1767
1769
1770 MEM_freeN(cache->block_entries);
1771
1772 BLI_ghash_free(cache->misc_entries, nullptr, nullptr);
1774
1775 BLI_ghash_free(cache->uids, nullptr, nullptr);
1776
1778 filelist_entry_free(entry);
1779 }
1781}
1782
1783static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
1784{
1785 if (!(cache->flags & FLC_IS_INIT)) {
1786 return;
1787 }
1788
1790
1791 cache->block_cursor = cache->block_start_index = cache->block_center_index =
1792 cache->block_end_index = 0;
1793 if (new_size != cache->size) {
1794 cache->block_entries = static_cast<FileDirEntry **>(
1795 MEM_reallocN(cache->block_entries, sizeof(*cache->block_entries) * new_size));
1796 }
1797
1798 BLI_ghash_clear_ex(cache->misc_entries, nullptr, nullptr, new_size);
1799 if (new_size != cache->size) {
1800 cache->misc_entries_indices = static_cast<int *>(MEM_reallocN(
1801 cache->misc_entries_indices, sizeof(*cache->misc_entries_indices) * new_size));
1802 }
1803 copy_vn_i(cache->misc_entries_indices, new_size, -1);
1804
1805 BLI_ghash_clear_ex(cache->uids, nullptr, nullptr, new_size * 2);
1806
1807 cache->size = new_size;
1808
1810 filelist_entry_free(entry);
1811 }
1813}
1814
1827
1828void filelist_settype(FileList *filelist, short type)
1829{
1830 if (filelist->type == type) {
1831 return;
1832 }
1833
1834 filelist->type = (eFileSelectType)type;
1835 filelist->tags = 0;
1836 filelist->indexer = &file_indexer_noop;
1837 switch (filelist->type) {
1838 case FILE_MAIN:
1841 filelist->prepare_filter_fn = nullptr;
1842 filelist->filter_fn = is_filtered_main;
1843 break;
1844 case FILE_LOADLIB:
1847 filelist->prepare_filter_fn = nullptr;
1848 filelist->filter_fn = is_filtered_lib;
1849 break;
1850 case FILE_ASSET_LIBRARY:
1856 break;
1857 case FILE_MAIN_ASSET:
1863 break;
1870 break;
1871 default:
1874 filelist->prepare_filter_fn = nullptr;
1875 filelist->filter_fn = is_filtered_file;
1876 break;
1877 }
1878
1879 filelist->flags |= FL_FORCE_RESET;
1880}
1881
1883{
1884 /* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */
1885 filelist->asset_library = nullptr;
1886 file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter);
1887}
1888
1890 const bool do_asset_library,
1891 const bool do_cache,
1892 const bool do_selection)
1893{
1894 if (!filelist) {
1895 return;
1896 }
1897
1899
1900 if (do_cache) {
1902 }
1903
1904 filelist_intern_free(filelist);
1905
1907
1908 if (do_selection && filelist->selection_state) {
1909 BLI_ghash_clear(filelist->selection_state, nullptr, nullptr);
1910 }
1911
1912 if (do_asset_library) {
1914 }
1915}
1916
1918 const bool do_asset_library,
1919 const bool do_cache,
1920 const bool do_selection)
1921{
1922 if (!filelist || !(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) {
1923 return;
1924 }
1926 return;
1927 }
1928 const int removed_files = filelist_intern_free_main_files(filelist);
1929 /* File list contains no main files to clear. */
1930 if (removed_files == 0) {
1931 return;
1932 }
1933
1935
1936 if (do_cache) {
1938 }
1939
1940 filelist->filelist.entries_num -= removed_files;
1943
1944 if (do_selection && filelist->selection_state) {
1945 BLI_ghash_clear(filelist->selection_state, nullptr, nullptr);
1946 }
1947
1948 if (do_asset_library) {
1950 }
1951}
1952
1954{
1955 filelist_clear_ex(filelist, true, true, true);
1956}
1957
1959{
1960 /* Do a full clear if needed. */
1961 if (filelist->flags & FL_FORCE_RESET) {
1962 filelist_clear(filelist);
1963 return;
1964 }
1965
1966 if (filelist->flags & FL_FORCE_RESET_MAIN_FILES) {
1967 filelist_clear_main_files(filelist, false, true, false);
1968 return;
1969 }
1970}
1971
1973{
1974 if (!filelist) {
1975 printf("Attempting to delete empty filelist.\n");
1976 return;
1977 }
1978
1979 /* No need to clear cache & selection_state, we free them anyway. */
1980 filelist_clear_ex(filelist, true, false, false);
1982
1983 if (filelist->selection_state) {
1984 BLI_ghash_free(filelist->selection_state, nullptr, nullptr);
1985 filelist->selection_state = nullptr;
1986 }
1987
1989
1990 memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
1991
1992 filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
1993
1994 MEM_freeN(filelist);
1995}
1996
2001
2003{
2004 if (filelist->libfiledata) {
2006 }
2007 filelist->libfiledata = nullptr;
2008}
2009
2010BlendHandle *filelist_lib(FileList *filelist)
2011{
2012 return filelist->libfiledata;
2013}
2014
2016{
2017 return filelist->filelist.entries_num;
2018}
2019
2020static const char *fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff)
2021{
2022 if (asset_system::AssetRepresentation *asset = entry->get_asset()) {
2023 const StringRefNull asset_name = asset->get_name();
2024 return BLI_strdupn(asset_name.c_str(), asset_name.size());
2025 }
2026
2027 const char *relpath = entry->relpath;
2028 const eFileSel_File_Types typeflag = entry->typeflag;
2029 char *name = nullptr;
2030
2031 if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) {
2032 char abspath[FILE_MAX_LIBEXTRA];
2033 BLI_path_join(abspath, sizeof(abspath), root, relpath);
2034 name = BLF_display_name_from_file(abspath);
2035 if (name) {
2036 /* Allocated string, so no need to #BLI_strdup. */
2037 return name;
2038 }
2039 }
2040
2041 if (typeflag & FILE_TYPE_BLENDERLIB) {
2042 char abspath[FILE_MAX_LIBEXTRA];
2043 char *group;
2044
2045 BLI_path_join(abspath, sizeof(abspath), root, relpath);
2046 BKE_blendfile_library_path_explode(abspath, buff, &group, &name);
2047 if (!name) {
2048 name = group;
2049 }
2050 }
2051 /* Depending on platforms, 'my_file.blend/..' might be viewed as dir or not... */
2052 if (!name) {
2053 if (typeflag & FILE_TYPE_DIR) {
2054 name = (char *)relpath;
2055 }
2056 else {
2057 name = (char *)BLI_path_basename(relpath);
2058 }
2059 }
2060 BLI_assert(name);
2061
2062 return BLI_strdup(name);
2063}
2064
2065const char *filelist_dir(const FileList *filelist)
2066{
2067 return filelist->filelist.root;
2068}
2069
2070bool filelist_is_dir(const FileList *filelist, const char *path)
2071{
2072 return filelist->check_dir_fn(filelist, (char *)path, false);
2073}
2074
2075void filelist_setdir(FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA])
2076{
2077 const bool allow_invalid = filelist->asset_library_ref != nullptr;
2078 BLI_assert(strlen(dirpath) < FILE_MAX_LIBEXTRA);
2079
2082 const bool is_valid_path = filelist->check_dir_fn(filelist, dirpath, !allow_invalid);
2083 BLI_assert(is_valid_path || allow_invalid);
2084 UNUSED_VARS_NDEBUG(is_valid_path);
2085
2086 if (!STREQ(filelist->filelist.root, dirpath)) {
2087 STRNCPY(filelist->filelist.root, dirpath);
2088 filelist->flags |= FL_FORCE_RESET;
2089 }
2090}
2091
2092void filelist_setrecursion(FileList *filelist, const int recursion_level)
2093{
2094 if (filelist->max_recursion != recursion_level) {
2095 filelist->max_recursion = recursion_level;
2096 filelist->flags |= FL_FORCE_RESET;
2097 }
2098}
2099
2101{
2102 return (filelist->flags & (FL_FORCE_RESET | FL_FORCE_RESET_MAIN_FILES)) != 0;
2103}
2104
2106{
2107 filelist->flags |= FL_FORCE_RESET;
2108}
2109
2111{
2112 if (!(filelist->tags & FILELIST_TAGS_USES_MAIN_DATA)) {
2113 return;
2114 }
2115 filelist->flags |= FL_FORCE_RESET_MAIN_FILES;
2116}
2117
2119{
2120 filelist->flags |= FL_RELOAD_ASSET_LIBRARY;
2121}
2122
2123bool filelist_is_ready(const FileList *filelist)
2124{
2125 return (filelist->flags & FL_IS_READY) != 0;
2126}
2127
2128bool filelist_pending(const FileList *filelist)
2129{
2130 return (filelist->flags & FL_IS_PENDING) != 0;
2131}
2132
2134{
2135 return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0;
2136}
2137
2139{
2140 if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) {
2141 filelist_sort(filelist);
2142 filelist_filter(filelist);
2143 }
2144
2145 return filelist->filelist.entries_filtered_num;
2146}
2147
2148static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
2149{
2150 FileListInternEntry *entry = filelist->filelist_intern.filtered[index];
2151 FileListEntryCache *cache = &filelist->filelist_cache;
2153
2154 ret = MEM_callocN<FileDirEntry>(__func__);
2155
2156 ret->size = uint64_t(entry->st.st_size);
2157 ret->time = int64_t(entry->st.st_mtime);
2158
2159 ret->relpath = BLI_strdup(entry->relpath);
2160 if (entry->free_name) {
2161 ret->name = BLI_strdup(entry->name);
2162 ret->flags |= FILE_ENTRY_NAME_FREE;
2163 }
2164 else {
2165 ret->name = entry->name;
2166 }
2167 ret->uid = entry->uid;
2168 ret->blentype = entry->blentype;
2169 ret->typeflag = entry->typeflag;
2170 ret->attributes = entry->attributes;
2171 if (entry->redirection_path) {
2172 ret->redirection_path = BLI_strdup(entry->redirection_path);
2173 }
2174 ret->id = entry->local_data.id;
2175 ret->asset = entry->get_asset();
2176 /* For some file types the preview is already available. */
2177 if (entry->local_data.preview_image &&
2179 {
2181 if (ibuf) {
2182 ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
2183 }
2184 }
2185 if (entry->blenderlib_has_no_preview) {
2187 }
2188 BLI_addtail(&cache->cached_entries, ret);
2189 return ret;
2190}
2191
2193{
2194 BLI_remlink(&filelist->filelist_cache.cached_entries, entry);
2195 filelist_entry_free(entry);
2196}
2197
2199{
2200 /* If the file is cached, we can get it from either the block or the misc entry storage. */
2201
2202 if (index >= cache->block_start_index && index < cache->block_end_index) {
2203 const int idx = (index - cache->block_start_index + cache->block_cursor) % cache->size;
2204 return cache->block_entries[idx];
2205 }
2206
2207 return static_cast<FileDirEntry *>(
2209}
2210
2211FileDirEntry *filelist_file_ex(FileList *filelist, const int index, const bool use_request)
2212{
2213 FileDirEntry *ret = nullptr, *old;
2214 FileListEntryCache *cache = &filelist->filelist_cache;
2215 int old_index;
2216
2217 if ((index < 0) || (index >= filelist->filelist.entries_filtered_num)) {
2218 return ret;
2219 }
2220
2221 if ((ret = filelist_cache_file_lookup(cache, index))) {
2222 return ret;
2223 }
2224
2225 if (!use_request) {
2226 return nullptr;
2227 }
2228
2229 // printf("requesting file %d (not yet cached)\n", index);
2230
2231 /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */
2232 ret = filelist_file_create_entry(filelist, index);
2233 old_index = cache->misc_entries_indices[cache->misc_cursor];
2234 if ((old = static_cast<FileDirEntry *>(
2235 BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), nullptr))))
2236 {
2237 BLI_ghash_remove(cache->uids, POINTER_FROM_UINT(old->uid), nullptr, nullptr);
2238 filelist_file_release_entry(filelist, old);
2239 }
2242
2243 cache->misc_entries_indices[cache->misc_cursor] = index;
2244 cache->misc_cursor = (cache->misc_cursor + 1) % cache->size;
2245
2246#if 0 /* Actually no, only block cached entries should have preview IMHO. */
2247 if (cache->previews_pool) {
2248 filelist_cache_previews_push(filelist, ret, index);
2249 }
2250#endif
2251
2252 return ret;
2253}
2254
2256{
2257 return filelist_file_ex(filelist, index, true);
2258}
2259
2260int filelist_file_find_path(FileList *filelist, const char *filename)
2261{
2263 return -1;
2264 }
2265
2266 /* XXX TODO: Cache could probably use a ghash on paths too? Not really urgent though.
2267 * This is only used to find again renamed entry,
2268 * annoying but looks hairy to get rid of it currently. */
2269
2270 for (int fidx = 0; fidx < filelist->filelist.entries_filtered_num; fidx++) {
2271 FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
2272 if (STREQ(entry->relpath, filename)) {
2273 return fidx;
2274 }
2275 }
2276
2277 return -1;
2278}
2279
2280int filelist_file_find_id(const FileList *filelist, const ID *id)
2281{
2283 return -1;
2284 }
2285
2286 for (int fidx = 0; fidx < filelist->filelist.entries_filtered_num; fidx++) {
2287 FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
2288 if (entry->local_data.id == id) {
2289 return fidx;
2290 }
2291 }
2292
2293 return -1;
2294}
2295
2296static FileListInternEntry *filelist_entry_intern_get(const FileList *filelist, const int index)
2297{
2298 BLI_assert(index >= 0 && index < filelist->filelist.entries_filtered_num);
2299 return filelist->filelist_intern.filtered[index];
2300}
2301
2302ID *filelist_entry_get_id(const FileList *filelist, const int index)
2303{
2304 const FileListInternEntry *intern_entry = filelist_entry_intern_get(filelist, index);
2305 return intern_entry->local_data.id;
2306}
2307
2309 const FileList *filelist, const int index)
2310{
2311 const FileListInternEntry *intern_entry = filelist_entry_intern_get(filelist, index);
2312 return intern_entry->get_asset();
2313}
2314
2316{
2317 return file->id;
2318}
2319
2320const char *filelist_entry_get_relpath(const FileList *filelist, int index)
2321{
2322 const FileListInternEntry *intern_entry = filelist_entry_intern_get(filelist, index);
2323 return intern_entry->relpath;
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
2348void 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 int i, idx;
2373
2374 for (i = 0, idx = start_index; i < size; i++, idx++, cursor++) {
2375 FileDirEntry *entry;
2376
2377 /* That entry might have already been requested and stored in misc cache... */
2378 if ((entry = static_cast<FileDirEntry *>(
2379 BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), nullptr))) == nullptr)
2380 {
2381 entry = filelist_file_create_entry(filelist, idx);
2382 BLI_ghash_insert(cache->uids, POINTER_FROM_UINT(entry->uid), entry);
2383 }
2384 cache->block_entries[cursor] = entry;
2385 }
2386 return true;
2387}
2388
2389static void filelist_file_cache_block_release(FileList *filelist, const int size, int cursor)
2390{
2391 FileListEntryCache *cache = &filelist->filelist_cache;
2392
2393 int i;
2394
2395 for (i = 0; i < size; i++, cursor++) {
2396 FileDirEntry *entry = cache->block_entries[cursor];
2397#if 0
2398 printf("%s: release cacheidx %d (%%p %%s)\n",
2399 __func__,
2400 cursor /*, cache->block_entries[cursor], cache->block_entries[cursor]->relpath*/);
2401#endif
2402 BLI_ghash_remove(cache->uids, POINTER_FROM_UINT(entry->uid), nullptr, nullptr);
2403 filelist_file_release_entry(filelist, entry);
2404#ifndef NDEBUG
2405 cache->block_entries[cursor] = nullptr;
2406#endif
2407 }
2408}
2409
2410bool filelist_file_cache_block(FileList *filelist, const int index)
2411{
2412 FileListEntryCache *cache = &filelist->filelist_cache;
2413 const size_t cache_size = cache->size;
2414
2415 const int entries_num = filelist->filelist.entries_filtered_num;
2416 int start_index = max_ii(0, index - (cache_size / 2));
2417 int end_index = min_ii(entries_num, index + (cache_size / 2));
2418 int i;
2419 const bool full_refresh = (filelist->flags & FL_IS_READY) == 0;
2420
2421 if ((index < 0) || (index >= entries_num)) {
2422 // printf("Wrong index %d ([%d:%d])", index, 0, entries_num);
2423 return false;
2424 }
2425
2426 /* Maximize cached range! */
2427 if ((end_index - start_index) < cache_size) {
2428 if (start_index == 0) {
2429 end_index = min_ii(entries_num, start_index + cache_size);
2430 }
2431 else if (end_index == entries_num) {
2432 start_index = max_ii(0, end_index - cache_size);
2433 }
2434 }
2435
2436 BLI_assert((end_index - start_index) <= cache_size);
2437
2438 // printf("%s: [%d:%d] around index %d (current cache: [%d:%d])\n", __func__,
2439 // start_index, end_index, index, cache->block_start_index, cache->block_end_index);
2440
2441 /* If we have something to (re)cache... */
2442 if (full_refresh || (start_index != cache->block_start_index) ||
2443 (end_index != cache->block_end_index))
2444 {
2445 if (full_refresh || (start_index >= cache->block_end_index) ||
2446 (end_index <= cache->block_start_index))
2447 {
2448 int size1 = cache->block_end_index - cache->block_start_index;
2449 int size2 = 0;
2450 int idx1 = cache->block_cursor, idx2 = 0;
2451
2452 // printf("Full Recaching!\n");
2453
2454 if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2456 }
2457
2458 if (idx1 + size1 > cache_size) {
2459 size2 = idx1 + size1 - cache_size;
2460 size1 -= size2;
2461 filelist_file_cache_block_release(filelist, size2, idx2);
2462 }
2463 filelist_file_cache_block_release(filelist, size1, idx1);
2464
2465 cache->block_start_index = cache->block_end_index = cache->block_cursor = 0;
2466
2467 /* New cached block does not overlap existing one, simple. */
2468 if (!filelist_file_cache_block_create(filelist, start_index, end_index - start_index, 0)) {
2469 return false;
2470 }
2471
2472 cache->block_start_index = start_index;
2473 cache->block_end_index = end_index;
2474 }
2475 else {
2476 // printf("Partial Recaching!\n");
2477
2478 /* At this point, we know we keep part of currently cached entries, so update previews
2479 * if needed, and remove everything from working queue - we'll add all newly needed
2480 * entries at the end. */
2481 if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2484 }
2485
2486 // printf("\tpreview cleaned up...\n");
2487
2488 if (start_index > cache->block_start_index) {
2489 int size1 = start_index - cache->block_start_index;
2490 int size2 = 0;
2491 int idx1 = cache->block_cursor, idx2 = 0;
2492
2493 // printf("\tcache releasing: [%d:%d] (%d, %d)\n",
2494 // cache->block_start_index, cache->block_start_index + size1,
2495 // cache->block_cursor, size1);
2496
2497 if (idx1 + size1 > cache_size) {
2498 size2 = idx1 + size1 - cache_size;
2499 size1 -= size2;
2500 filelist_file_cache_block_release(filelist, size2, idx2);
2501 }
2502 filelist_file_cache_block_release(filelist, size1, idx1);
2503
2504 cache->block_cursor = (idx1 + size1 + size2) % cache_size;
2505 cache->block_start_index = start_index;
2506 }
2507 if (end_index < cache->block_end_index) {
2508 int size1 = cache->block_end_index - end_index;
2509 int size2 = 0;
2510 int idx1, idx2 = 0;
2511
2512#if 0
2513 printf("\tcache releasing: [%d:%d] (%d)\n",
2514 cache->block_end_index - size1,
2515 cache->block_end_index,
2516 cache->block_cursor);
2517#endif
2518
2519 idx1 = (cache->block_cursor + end_index - cache->block_start_index) % cache_size;
2520 if (idx1 + size1 > cache_size) {
2521 size2 = idx1 + size1 - cache_size;
2522 size1 -= size2;
2523 filelist_file_cache_block_release(filelist, size2, idx2);
2524 }
2525 filelist_file_cache_block_release(filelist, size1, idx1);
2526
2527 cache->block_end_index = end_index;
2528 }
2529
2530 // printf("\tcache cleaned up...\n");
2531
2532 if (start_index < cache->block_start_index) {
2533 /* Add (request) needed entries before already cached ones. */
2534 /* NOTE: We need some index black magic to wrap around (cycle)
2535 * inside our cache_size array... */
2536 int size1 = cache->block_start_index - start_index;
2537 int size2 = 0;
2538 int idx1, idx2;
2539
2540 if (size1 > cache->block_cursor) {
2541 size2 = size1;
2542 size1 -= cache->block_cursor;
2543 size2 -= size1;
2544 idx2 = 0;
2545 idx1 = cache_size - size1;
2546 }
2547 else {
2548 idx1 = cache->block_cursor - size1;
2549 }
2550
2551 if (size2) {
2552 if (!filelist_file_cache_block_create(filelist, start_index + size1, size2, idx2)) {
2553 return false;
2554 }
2555 }
2556 if (!filelist_file_cache_block_create(filelist, start_index, size1, idx1)) {
2557 return false;
2558 }
2559
2560 cache->block_cursor = idx1;
2561 cache->block_start_index = start_index;
2562 }
2563 // printf("\tstart-extended...\n");
2564 if (end_index > cache->block_end_index) {
2565 /* Add (request) needed entries after already cached ones. */
2566 /* NOTE: We need some index black magic to wrap around (cycle)
2567 * inside our cache_size array... */
2568 int size1 = end_index - cache->block_end_index;
2569 int size2 = 0;
2570 int idx1, idx2;
2571
2572 idx1 = (cache->block_cursor + end_index - cache->block_start_index - size1) % cache_size;
2573 if ((idx1 + size1) > cache_size) {
2574 size2 = size1;
2575 size1 = cache_size - idx1;
2576 size2 -= size1;
2577 idx2 = 0;
2578 }
2579
2580 if (size2) {
2581 if (!filelist_file_cache_block_create(filelist, end_index - size2, size2, idx2)) {
2582 return false;
2583 }
2584 }
2585 if (!filelist_file_cache_block_create(filelist, end_index - size1 - size2, size1, idx1)) {
2586 return false;
2587 }
2588
2589 cache->block_end_index = end_index;
2590 }
2591
2592 // printf("\tend-extended...\n");
2593 }
2594 }
2595 else if ((cache->block_center_index != index) && (cache->flags & FLC_PREVIEWS_ACTIVE)) {
2596 /* We try to always preview visible entries first, so 'restart' preview background task. */
2599 }
2600
2601 // printf("Re-queueing previews...\n");
2602
2603 if (cache->flags & FLC_PREVIEWS_ACTIVE) {
2604 /* Note we try to preview first images around given index - i.e. assumed visible ones. */
2605 int block_index = cache->block_cursor + (index - start_index);
2606 int offs_max = max_ii(end_index - index, index - start_index);
2607 for (i = 0; i <= offs_max; i++) {
2608 int offs = i;
2609 do {
2610 int offs_idx = index + offs;
2611 if (start_index <= offs_idx && offs_idx < end_index) {
2612 int offs_block_idx = (block_index + offs) % int(cache_size);
2613 filelist_cache_previews_push(filelist, cache->block_entries[offs_block_idx], offs_idx);
2614 }
2615 } while ((offs = -offs) < 0); /* Switch between negative and positive offset. */
2616 }
2617 }
2618
2619 cache->block_center_index = index;
2620
2621 // printf("%s Finished!\n", __func__);
2622
2623 return true;
2624}
2625
2626void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
2627{
2628 FileListEntryCache *cache = &filelist->filelist_cache;
2629
2630 if (use_previews == ((cache->flags & FLC_PREVIEWS_ACTIVE) != 0)) {
2631 return;
2632 }
2633 /* Do not start preview work while listing, gives nasty flickering! */
2634 if (use_previews && (filelist->flags & FL_IS_READY)) {
2635 cache->flags |= FLC_PREVIEWS_ACTIVE;
2636
2637 BLI_assert((cache->previews_pool == nullptr) && (cache->previews_done == nullptr) &&
2638 (cache->previews_todo_count == 0));
2639
2640 // printf("%s: Init Previews...\n", __func__);
2641
2642 /* No need to populate preview queue here, filelist_file_cache_block() handles this. */
2643 }
2644 else {
2645 // printf("%s: Clear Previews...\n", __func__);
2646
2648 }
2649}
2650
2652{
2653 FileListEntryCache *cache = &filelist->filelist_cache;
2654 TaskPool *pool = cache->previews_pool;
2655 bool changed = false;
2656
2657 if (!pool) {
2658 return changed;
2659 }
2660
2661 // printf("%s: Update Previews...\n", __func__);
2662
2663 while (!BLI_thread_queue_is_empty(cache->previews_done)) {
2664 FileListEntryPreview *preview = static_cast<FileListEntryPreview *>(
2666 FileDirEntry *entry;
2667
2668 /* Paranoid (should never happen currently
2669 * since we consume this queue from a single thread), but... */
2670 if (!preview) {
2671 continue;
2672 }
2673 /* entry might have been removed from cache in the mean time,
2674 * we do not want to cache it again here. */
2675 entry = filelist_file_ex(filelist, preview->index, false);
2676
2677 // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->filepath, preview->img);
2678
2679 if (entry) {
2680 if (preview->icon_id) {
2681 /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous
2682 * process from trying to generate the same preview icon. */
2683 BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet");
2684
2685 /* Move ownership over icon. */
2686 entry->preview_icon_id = preview->icon_id;
2687 preview->icon_id = 0;
2688 }
2689 else {
2690 /* We want to avoid re-processing this entry continuously!
2691 * Note that, since entries only live in cache,
2692 * preview will be retried quite often anyway. */
2694 }
2696 changed = true;
2697 }
2698 else {
2699 BKE_icon_delete(preview->icon_id);
2700 }
2701
2702 MEM_freeN(preview);
2703 cache->previews_todo_count--;
2704 }
2705
2706 return changed;
2707}
2708
2710{
2711 FileListEntryCache *cache = &filelist->filelist_cache;
2712
2713 return (cache->previews_pool != nullptr);
2714}
2715
2717{
2718 FileListEntryCache *cache = &filelist->filelist_cache;
2719 if ((cache->flags & FLC_PREVIEWS_ACTIVE) == 0) {
2720 /* There are no previews. */
2721 return false;
2722 }
2723
2724 return (cache->previews_pool == nullptr) || (cache->previews_done == nullptr) ||
2725 (cache->previews_todo_count == 0);
2726}
2727
2728/* would recognize .blend as well */
2729static bool file_is_blend_backup(const char *str)
2730{
2731 const size_t a = strlen(str);
2732 size_t b = 7;
2733 bool retval = false;
2734
2735 if (a == 0 || b >= a) {
2736 /* pass */
2737 }
2738 else {
2739 const char *loc;
2740
2741 if (a > b + 1) {
2742 b++;
2743 }
2744
2745 /* allow .blend1 .blend2 .blend32 */
2746 loc = BLI_strcasestr(str + a - b, ".blend");
2747
2748 if (loc) {
2749 retval = true;
2750 }
2751 }
2752
2753 return retval;
2754}
2755
2756int ED_path_extension_type(const char *path)
2757{
2758 /* ATTENTION: Never return OR'ed bit-flags here, always return a single enum value! Some code
2759 * using this may do `ELEM()`-like checks. */
2760
2762 return FILE_TYPE_BLENDER;
2763 }
2764 if (file_is_blend_backup(path)) {
2766 }
2767#ifdef __APPLE__
2769 /* Application bundle */
2770 ".app",
2771 /* Safari in-progress/paused download */
2772 ".download",
2773 nullptr))
2774 {
2775 return FILE_TYPE_BUNDLE;
2776 }
2777#endif
2778 if (BLI_path_extension_check(path, ".py")) {
2779 return FILE_TYPE_PYSCRIPT;
2780 }
2782 ".txt",
2783 ".glsl",
2784 ".osl",
2785 ".data",
2786 ".pov",
2787 ".ini",
2788 ".mcr",
2789 ".inc",
2790 ".fountain",
2791 nullptr))
2792 {
2793 return FILE_TYPE_TEXT;
2794 }
2795
2796 /* NOTE: While `.ttc` & `.otc` files can be loaded, only a single "face" is supported,
2797 * users will have to extract bold/italic etc manually for Blender to use them, see #44254. */
2798 if (BLI_path_extension_check_n(path, ".ttf", ".pfb", ".otf", ".woff", ".woff2", nullptr)) {
2799 return FILE_TYPE_FTFONT;
2800 }
2801 if (BLI_path_extension_check(path, ".btx")) {
2802 return FILE_TYPE_BTX;
2803 }
2804 if (BLI_path_extension_check(path, ".dae")) {
2805 return FILE_TYPE_COLLADA;
2806 }
2807 if (BLI_path_extension_check(path, ".abc")) {
2808 return FILE_TYPE_ALEMBIC;
2809 }
2810 if (BLI_path_extension_check_n(path, ".usd", ".usda", ".usdc", ".usdz", nullptr)) {
2811 return FILE_TYPE_USD;
2812 }
2813 if (BLI_path_extension_check(path, ".vdb")) {
2814 return FILE_TYPE_VOLUME;
2815 }
2816 if (BLI_path_extension_check(path, ".zip")) {
2817 return FILE_TYPE_ARCHIVE;
2818 }
2820 path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".ply", ".stl", nullptr))
2821 {
2822 return FILE_TYPE_OBJECT_IO;
2823 }
2825 return FILE_TYPE_IMAGE;
2826 }
2827 if (BLI_path_extension_check(path, ".ogg")) {
2828 if (MOV_is_movie_file(path)) {
2829 return FILE_TYPE_MOVIE;
2830 }
2831 return FILE_TYPE_SOUND;
2832 }
2834 return FILE_TYPE_MOVIE;
2835 }
2837 return FILE_TYPE_SOUND;
2838 }
2839 return 0;
2840}
2841
2842int ED_file_extension_icon(const char *path)
2843{
2844 const int type = ED_path_extension_type(path);
2845
2846 switch (type) {
2847 case FILE_TYPE_BLENDER:
2848 return ICON_FILE_BLEND;
2850 return ICON_FILE_BACKUP;
2851 case FILE_TYPE_IMAGE:
2852 return ICON_FILE_IMAGE;
2853 case FILE_TYPE_MOVIE:
2854 return ICON_FILE_MOVIE;
2855 case FILE_TYPE_PYSCRIPT:
2856 return ICON_FILE_SCRIPT;
2857 case FILE_TYPE_SOUND:
2858 return ICON_FILE_SOUND;
2859 case FILE_TYPE_FTFONT:
2860 return ICON_FILE_FONT;
2861 case FILE_TYPE_BTX:
2862 return ICON_FILE_BLANK;
2863 case FILE_TYPE_COLLADA:
2864 case FILE_TYPE_ALEMBIC:
2866 return ICON_FILE_3D;
2867 case FILE_TYPE_TEXT:
2868 return ICON_FILE_TEXT;
2869 case FILE_TYPE_ARCHIVE:
2870 return ICON_FILE_ARCHIVE;
2871 case FILE_TYPE_VOLUME:
2872 return ICON_FILE_VOLUME;
2873 default:
2874 return ICON_FILE_BLANK;
2875 }
2876}
2877
2879{
2880 return (filelist->filelist.entries_num == FILEDIR_NBR_ENTRIES_UNSET) ||
2882}
2883
2885 const FileDirEntry *entry,
2888 FileCheckType check)
2889{
2890 /* Default nullptr pointer if not found is fine here! */
2891 void **es_p = BLI_ghash_lookup_p(filelist->selection_state, POINTER_FROM_UINT(entry->uid));
2892 eDirEntry_SelectFlag entry_flag = eDirEntry_SelectFlag(es_p ? POINTER_AS_UINT(*es_p) : 0);
2893 const eDirEntry_SelectFlag org_entry_flag = entry_flag;
2894
2895 BLI_assert(entry);
2897
2898 if ((check == CHECK_ALL) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
2899 ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR)))
2900 {
2901 switch (select) {
2902 case FILE_SEL_REMOVE:
2903 entry_flag &= ~flag;
2904 break;
2905 case FILE_SEL_ADD:
2906 entry_flag |= flag;
2907 break;
2908 case FILE_SEL_TOGGLE:
2909 entry_flag ^= flag;
2910 break;
2911 }
2912 }
2913
2914 if (entry_flag != org_entry_flag) {
2915 if (es_p) {
2916 if (entry_flag) {
2917 *es_p = POINTER_FROM_UINT(entry_flag);
2918 }
2919 else {
2921 filelist->selection_state, POINTER_FROM_UINT(entry->uid), nullptr, nullptr);
2922 }
2923 }
2924 else if (entry_flag) {
2926 filelist->selection_state, POINTER_FROM_UINT(entry->uid), POINTER_FROM_UINT(entry_flag));
2927 }
2928 }
2929
2930 return entry_flag;
2931}
2932
2934 const int index,
2937 FileCheckType check)
2938{
2939 FileDirEntry *entry = filelist_file(filelist, index);
2940
2941 if (entry) {
2942 filelist_entry_select_set(filelist, entry, select, flag, check);
2943 }
2944}
2945
2947 FileSelection *sel,
2950 FileCheckType check)
2951{
2952 /* select all valid files between first and last indicated */
2953 if ((sel->first >= 0) && (sel->first < filelist->filelist.entries_filtered_num) &&
2954 (sel->last >= 0) && (sel->last < filelist->filelist.entries_filtered_num))
2955 {
2956 int current_file;
2957 for (current_file = sel->first; current_file <= sel->last; current_file++) {
2958 filelist_entry_select_index_set(filelist, current_file, select, flag, check);
2959 }
2960 }
2961}
2962
2964 FileDirEntry *entry,
2965 FileCheckType check)
2966{
2967 BLI_assert(entry);
2969
2970 if ((check == CHECK_ALL) || ((check == CHECK_DIRS) && (entry->typeflag & FILE_TYPE_DIR)) ||
2971 ((check == CHECK_FILES) && !(entry->typeflag & FILE_TYPE_DIR)))
2972 {
2973 /* Default nullptr pointer if not found is fine here! */
2976 }
2977
2978 return eDirEntry_SelectFlag(0);
2979}
2980
2982 const int index,
2983 FileCheckType check)
2984{
2985 FileDirEntry *entry = filelist_file(filelist, index);
2986
2987 if (entry) {
2988 return filelist_entry_select_get(filelist, entry, check);
2989 }
2990
2991 return eDirEntry_SelectFlag(0);
2992}
2993
2994bool filelist_entry_is_selected(FileList *filelist, const int index)
2995{
2996 BLI_assert(index >= 0 && index < filelist->filelist.entries_filtered_num);
2997 FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
2998
2999 /* BLI_ghash_lookup returns nullptr if not found, which gets mapped to 0, which gets mapped to
3000 * "not selected". */
3002 BLI_ghash_lookup(filelist->selection_state, POINTER_FROM_UINT(intern_entry->uid))));
3003
3004 return selection_state != 0;
3005}
3006
3010 FileCheckType check)
3011{
3012 if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
3013 filelist_entry_select_index_set(filelist, 0, select, flag, check);
3014 }
3015}
3016
3017bool filelist_islibrary(FileList *filelist, char *dir, char **r_group)
3018{
3019 if (filelist->asset_library) {
3020 return true;
3021 }
3022 return BKE_blendfile_library_path_explode(filelist->filelist.root, dir, r_group, nullptr);
3023}
3024
3025static int groupname_to_code(const char *group)
3026{
3027 char buf[BLO_GROUP_MAX];
3028 char *lslash;
3029
3030 BLI_assert(group);
3031
3032 STRNCPY(buf, group);
3033 lslash = (char *)BLI_path_slash_rfind(buf);
3034 if (lslash) {
3035 lslash[0] = '\0';
3036 }
3037
3038 return buf[0] ? BKE_idtype_idcode_from_name(buf) : 0;
3039}
3040
3046struct TodoDir {
3048 char *dir;
3049};
3050
3054 Main *current_main = nullptr;
3055 FileList *filelist = nullptr;
3056
3061 char cur_relbase[FILE_MAX_LIBEXTRA] = "";
3062
3070 bool only_main_data = false;
3074
3086};
3087
3093static char *current_relpath_append(const FileListReadJob *job_params, const char *filename)
3094{
3095 const char *relbase = job_params->cur_relbase;
3096
3097 /* Early exit, nothing to join. */
3098 if (!relbase[0]) {
3099 return BLI_strdup(filename);
3100 }
3101
3102 BLI_assert(ELEM(relbase[strlen(relbase) - 1], SEP, ALTSEP));
3103 BLI_assert(BLI_path_is_rel(relbase));
3104
3105 char relpath[FILE_MAX_LIBEXTRA];
3106 /* Using #BLI_path_join works but isn't needed as `rel_subdir` has a trailing slash. */
3107 BLI_string_join(relpath,
3108 sizeof(relpath),
3109 /* + 2 to remove "//" relative path prefix. */
3110 relbase + 2,
3111 filename);
3112
3113 return BLI_strdup(relpath);
3114}
3115
3117 const char *root,
3118 ListBase *entries,
3119 const char *filter_glob,
3120 const bool do_lib,
3121 const char *main_filepath,
3122 const bool skip_currpar)
3123{
3124 direntry *files;
3125 int entries_num = 0;
3126 /* Full path of the item. */
3127 char full_path[FILE_MAX];
3128
3129 const int files_num = BLI_filelist_dir_contents(root, &files);
3130 if (files) {
3131 int i = files_num;
3132 while (i--) {
3133 FileListInternEntry *entry;
3134
3135 if (skip_currpar && FILENAME_IS_CURRPAR(files[i].relname)) {
3136 continue;
3137 }
3138
3139 entry = MEM_new<FileListInternEntry>(__func__);
3140 entry->relpath = current_relpath_append(job_params, files[i].relname);
3141 entry->st = files[i].s;
3142
3143 BLI_path_join(full_path, FILE_MAX, root, files[i].relname);
3144 char *target = full_path;
3145
3146 /* Set initial file type and attributes. */
3147 entry->attributes = BLI_file_attributes(full_path);
3148 if (S_ISDIR(files[i].s.st_mode)
3149#ifdef __APPLE__
3150 && !(ED_path_extension_type(full_path) & FILE_TYPE_BUNDLE)
3151#endif
3152 )
3153 {
3154 entry->typeflag = FILE_TYPE_DIR;
3155 }
3156
3157 /* Is this a file that points to another file? */
3158 if (entry->attributes & FILE_ATTR_ALIAS) {
3160 if (BLI_file_alias_target(full_path, entry->redirection_path)) {
3161 if (BLI_is_dir(entry->redirection_path)) {
3162 entry->typeflag = FILE_TYPE_DIR;
3164 }
3165 else {
3167 }
3168 target = entry->redirection_path;
3169#ifdef WIN32
3170 /* On Windows don't show `.lnk` extension for valid shortcuts. */
3172#endif
3173 }
3174 else {
3176 entry->redirection_path = nullptr;
3177 entry->attributes |= FILE_ATTR_HIDDEN;
3178 }
3179 }
3180
3181 if (!(entry->typeflag & FILE_TYPE_DIR)) {
3182 if (do_lib && BKE_blendfile_extension_check(target)) {
3183 /* If we are considering .blend files as libraries, promote them to directory status. */
3184 entry->typeflag = FILE_TYPE_BLENDER;
3185 /* prevent current file being used as acceptable dir */
3186 if (BLI_path_cmp(main_filepath, target) != 0) {
3187 entry->typeflag |= FILE_TYPE_DIR;
3188 }
3189 }
3190 else {
3192 if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) {
3193 entry->typeflag |= FILE_TYPE_OPERATOR;
3194 }
3195 }
3196 }
3197
3198#ifndef WIN32
3199 /* Set linux-style dot files hidden too. */
3201 entry->attributes |= FILE_ATTR_HIDDEN;
3202 }
3203#endif
3204
3205 BLI_addtail(entries, entry);
3206 entries_num++;
3207 }
3208 BLI_filelist_free(files, files_num);
3209 }
3210 return entries_num;
3211}
3212
3215
3216 /* Will read both the groups + actual ids from the library. Reduces the amount of times that
3217 * a library needs to be opened. */
3219
3220 /* Will only list assets. */
3222
3223 /* Add given root as result. */
3225};
3227
3229 const FileListReadJob *job_params, const int idcode, const char *group_name)
3230{
3231 FileListInternEntry *entry = MEM_new<FileListInternEntry>(__func__);
3232 entry->relpath = current_relpath_append(job_params, group_name);
3234 entry->blentype = idcode;
3235 return entry;
3236}
3237
3243 ListBase *entries,
3244 BLODataBlockInfo *datablock_info,
3245 const bool prefix_relpath_with_group_name,
3246 const int idcode,
3247 const char *group_name)
3248{
3249 FileListInternEntry *entry = MEM_new<FileListInternEntry>(__func__);
3250 if (prefix_relpath_with_group_name) {
3251 std::string datablock_path = StringRef(group_name) + SEP_STR + datablock_info->name;
3252 entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
3253 }
3254 else {
3255 entry->relpath = current_relpath_append(job_params, datablock_info->name);
3256 }
3258 if (datablock_info) {
3259 entry->blenderlib_has_no_preview = datablock_info->no_preview_found;
3260
3261 if (datablock_info->name[0] == '.') {
3262 entry->attributes |= FILE_ATTR_HIDDEN;
3263 }
3264
3265 if (datablock_info->asset_data) {
3266 entry->typeflag |= FILE_TYPE_ASSET;
3267
3268 if (job_params->load_asset_library) {
3269 /* Take ownership over the asset data (shallow copies into unique_ptr managed memory) to
3270 * pass it on to the asset system. */
3271 std::unique_ptr metadata = std::make_unique<AssetMetaData>(
3272 std::move(*datablock_info->asset_data));
3273 MEM_delete(datablock_info->asset_data);
3274 /* Give back a non-owning pointer, because the data-block info is still needed (e.g. to
3275 * update the asset index). */
3276 datablock_info->asset_data = metadata.get();
3277 datablock_info->free_asset_data = false;
3278
3279 entry->asset = job_params->load_asset_library->add_external_asset(
3280 entry->relpath, datablock_info->name, idcode, std::move(metadata));
3281 }
3282 }
3283 }
3284 entry->blentype = idcode;
3285 BLI_addtail(entries, entry);
3286}
3287
3289 ListBase *entries,
3290 LinkNode *datablock_infos,
3291 const bool prefix_relpath_with_group_name,
3292 const int idcode,
3293 const char *group_name)
3294{
3295 for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
3296 BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link);
3298 job_params, entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
3299 }
3300}
3301
3303 FileListReadJob *job_params,
3304 ListBase *entries,
3305 const FileIndexerEntries *indexer_entries,
3306 const bool prefix_relpath_with_group_name)
3307{
3308 for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
3309 FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(ln->link);
3310 const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
3312 entries,
3313 &indexer_entry->datablock_info,
3314 prefix_relpath_with_group_name,
3315 indexer_entry->idcode,
3316 group_name);
3317 }
3318}
3319
3321 const FileListReadJob *job_params)
3322{
3323 FileListInternEntry *entry = MEM_new<FileListInternEntry>(__func__);
3324 entry->relpath = current_relpath_append(job_params, FILENAME_PARENT);
3326 return entry;
3327}
3328
3334
3339};
3340
3342 ListBase *entries,
3343 const ListLibOptions options,
3344 const int read_from_index,
3345 const FileIndexerEntries *indexer_entries)
3346{
3347 int navigate_to_parent_len = 0;
3350 job_params);
3351 BLI_addtail(entries, entry);
3352 navigate_to_parent_len = 1;
3353 }
3354
3355 filelist_readjob_list_lib_add_from_indexer_entries(job_params, entries, indexer_entries, true);
3356 return read_from_index + navigate_to_parent_len;
3357}
3358
3363static std::optional<int> filelist_readjob_list_lib(FileListReadJob *job_params,
3364 const char *root,
3365 ListBase *entries,
3366 const ListLibOptions options,
3367 FileIndexer *indexer_runtime)
3368{
3369 BLI_assert(indexer_runtime);
3370
3371 char dir[FILE_MAX_LIBEXTRA], *group;
3372
3373 BlendHandle *libfiledata = nullptr;
3374
3375 /* Check if the given root is actually a library. All folders are passed to
3376 * `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do`
3377 * will do a dir listing only when this function does not return any entries. */
3378 /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and
3379 * call it directly from `filelist_readjob_do` to increase readability. */
3380 const bool is_lib = BKE_blendfile_library_path_explode(root, dir, &group, nullptr);
3381 if (!is_lib) {
3382 return std::nullopt;
3383 }
3384
3385 /* The root path contains an ID group (e.g. "Materials" or "Objects"). */
3386 const bool has_group = group != nullptr;
3387
3388 /* Try read from indexer_runtime. */
3389 /* Indexing returns all entries in a blend file. We should ignore the index when listing a group
3390 * inside a blend file, so the `entries` isn't filled with undesired entries.
3391 * This happens when linking or appending data-blocks, where you can navigate into a group (ie
3392 * Materials/Objects) where you only want to work with partial indexes.
3393 *
3394 * Adding support for partial reading/updating indexes would increase the complexity.
3395 */
3396 const bool use_indexer = !has_group;
3397 FileIndexerEntries indexer_entries = {nullptr};
3398 if (use_indexer) {
3399 int read_from_index = 0;
3400 eFileIndexerResult indexer_result = indexer_runtime->callbacks->read_index(
3401 dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
3402 if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
3404 job_params, entries, options, read_from_index, &indexer_entries);
3405 ED_file_indexer_entries_clear(&indexer_entries);
3406 return entries_read;
3407 }
3408 }
3409
3410 /* Open the library file. */
3411 BlendFileReadReport bf_reports{};
3412 libfiledata = BLO_blendhandle_from_file(dir, &bf_reports);
3413 if (libfiledata == nullptr) {
3414 return std::nullopt;
3415 }
3416
3417 /* Add current parent when requested. */
3418 /* Is the navigate to previous level added to the list of entries. When added the return value
3419 * should be increased to match the actual number of entries added. It is introduced to keep
3420 * the code clean and readable and not counting in a single variable. */
3421 int navigate_to_parent_len = 0;
3424 job_params);
3425 BLI_addtail(entries, entry);
3426 navigate_to_parent_len = 1;
3427 }
3428
3429 int group_len = 0;
3430 int datablock_len = 0;
3431 /* Read only the datablocks from this group. */
3432 if (has_group) {
3433 const int idcode = groupname_to_code(group);
3435 libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len);
3437 job_params, entries, datablock_infos, false, idcode, group);
3438 BLO_datablock_info_linklist_free(datablock_infos);
3439 }
3440 /* Read all datablocks from all groups. */
3441 else {
3442 LinkNode *groups = BLO_blendhandle_get_linkable_groups(libfiledata);
3443 group_len = BLI_linklist_count(groups);
3444
3445 for (LinkNode *ln = groups; ln; ln = ln->next) {
3446 const char *group_name = static_cast<char *>(ln->link);
3447 const int idcode = groupname_to_code(group_name);
3449 job_params, idcode, group_name);
3450 BLI_addtail(entries, group_entry);
3451
3453 int group_datablock_len;
3454 LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info(
3455 libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
3457 job_params, entries, group_datablock_infos, true, idcode, group_name);
3458 if (use_indexer) {
3460 &indexer_entries, group_datablock_infos, idcode);
3461 }
3462 BLO_datablock_info_linklist_free(group_datablock_infos);
3463 datablock_len += group_datablock_len;
3464 }
3465 }
3466
3467 BLI_linklist_freeN(groups);
3468 }
3469
3470 BLO_blendhandle_close(libfiledata);
3471
3472 /* Update the index. */
3473 if (use_indexer) {
3474 indexer_runtime->callbacks->update_index(dir, &indexer_entries, indexer_runtime->user_data);
3475 ED_file_indexer_entries_clear(&indexer_entries);
3476 }
3477
3478 /* Return the number of items added to entries. */
3479 int added_entries_len = group_len + datablock_len + navigate_to_parent_len;
3480 return added_entries_len;
3481}
3482
3483#if 0
3484/* Kept for reference here, in case we want to add back that feature later.
3485 * We do not need it currently. */
3486/* Code ***NOT*** updated for job stuff! */
3487static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
3488{
3489 ID *id;
3490 FileDirEntry *files, *firstlib = nullptr;
3491 ListBase *lb;
3492 int a, fake, idcode, ok, totlib, totbl;
3493
3494 // filelist->type = FILE_MAIN; /* XXX TODO: add modes to file-browser */
3495
3496 BLI_assert(filelist->filelist.entries == nullptr);
3497
3498 if (filelist->filelist.root[0] == '/') {
3499 filelist->filelist.root[0] = '\0';
3500 }
3501
3502 if (filelist->filelist.root[0]) {
3503 idcode = groupname_to_code(filelist->filelist.root);
3504 if (idcode == 0) {
3505 filelist->filelist.root[0] = '\0';
3506 }
3507 }
3508
3509 if (filelist->dir[0] == 0) {
3510 /* make directories */
3511# ifdef WITH_FREESTYLE
3512 filelist->filelist.entries_num = 27;
3513# else
3514 filelist->filelist.entries_num = 26;
3515# endif
3516 filelist_resize(filelist, filelist->filelist.entries_num);
3517
3518 for (a = 0; a < filelist->filelist.entries_num; a++) {
3519 filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR;
3520 }
3521
3522 filelist->filelist.entries[0].entry->relpath = BLI_strdup(FILENAME_PARENT);
3523 filelist->filelist.entries[1].entry->relpath = BLI_strdup("Scene");
3524 filelist->filelist.entries[2].entry->relpath = BLI_strdup("Object");
3525 filelist->filelist.entries[3].entry->relpath = BLI_strdup("Mesh");
3526 filelist->filelist.entries[4].entry->relpath = BLI_strdup("Curve");
3527 filelist->filelist.entries[5].entry->relpath = BLI_strdup("Metaball");
3528 filelist->filelist.entries[6].entry->relpath = BLI_strdup("Material");
3529 filelist->filelist.entries[7].entry->relpath = BLI_strdup("Texture");
3530 filelist->filelist.entries[8].entry->relpath = BLI_strdup("Image");
3531 filelist->filelist.entries[9].entry->relpath = BLI_strdup("Ika");
3532 filelist->filelist.entries[10].entry->relpath = BLI_strdup("Wave");
3533 filelist->filelist.entries[11].entry->relpath = BLI_strdup("Lattice");
3534 filelist->filelist.entries[12].entry->relpath = BLI_strdup("Light");
3535 filelist->filelist.entries[13].entry->relpath = BLI_strdup("Camera");
3536 filelist->filelist.entries[14].entry->relpath = BLI_strdup("Ipo");
3537 filelist->filelist.entries[15].entry->relpath = BLI_strdup("World");
3538 filelist->filelist.entries[16].entry->relpath = BLI_strdup("Screen");
3539 filelist->filelist.entries[17].entry->relpath = BLI_strdup("VFont");
3540 filelist->filelist.entries[18].entry->relpath = BLI_strdup("Text");
3541 filelist->filelist.entries[19].entry->relpath = BLI_strdup("Armature");
3542 filelist->filelist.entries[20].entry->relpath = BLI_strdup("Action");
3543 filelist->filelist.entries[21].entry->relpath = BLI_strdup("NodeTree");
3544 filelist->filelist.entries[22].entry->relpath = BLI_strdup("Speaker");
3545 filelist->filelist.entries[23].entry->relpath = BLI_strdup("Curves");
3546 filelist->filelist.entries[24].entry->relpath = BLI_strdup("Point Cloud");
3547 filelist->filelist.entries[25].entry->relpath = BLI_strdup("Volume");
3548# ifdef WITH_FREESTYLE
3549 filelist->filelist.entries[26].entry->relpath = BLI_strdup("FreestyleLineStyle");
3550# endif
3551 }
3552 else {
3553 /* make files */
3554 idcode = groupname_to_code(filelist->filelist.root);
3555
3556 lb = which_libbase(bmain, idcode);
3557 if (lb == nullptr) {
3558 return;
3559 }
3560
3561 filelist->filelist.entries_num = 0;
3562 for (id = lb->first; id; id = id->next) {
3563 if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
3564 filelist->filelist.entries_num++;
3565 }
3566 }
3567
3568 /* XXX TODO: if data-browse or append/link #FLF_HIDE_PARENT has to be set. */
3569 if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
3570 filelist->filelist.entries_num++;
3571 }
3572
3573 if (filelist->filelist.entries_num > 0) {
3574 filelist_resize(filelist, filelist->filelist.entries_num);
3575 }
3576
3577 files = filelist->filelist.entries;
3578
3579 if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
3580 files->entry->relpath = BLI_strdup(FILENAME_PARENT);
3581 files->typeflag |= FILE_TYPE_DIR;
3582
3583 files++;
3584 }
3585
3586 totlib = totbl = 0;
3587 for (id = lb->first; id; id = id->next) {
3588 ok = 1;
3589 if (ok) {
3590 if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
3591 if (!ID_IS_LINKED(id)) {
3592 files->entry->relpath = BLI_strdup(id->name + 2);
3593 }
3594 else {
3595 char relname[FILE_MAX + (MAX_ID_NAME - 2) + 3];
3596 SNPRINTF(relname, "%s | %s", id->lib->filepath, id->name + 2);
3597 files->entry->relpath = BLI_strdup(relname);
3598 }
3599// files->type |= S_IFREG;
3600# if 0 /* XXX TODO: show the selection status of the objects. */
3601 if (!filelist->has_func) { /* F4 DATA BROWSE */
3602 if (idcode == ID_OB) {
3603 if (((Object *)id)->flag & SELECT) {
3604 files->entry->selflag |= FILE_SEL_SELECTED;
3605 }
3606 }
3607 else if (idcode == ID_SCE) {
3608 if (((Scene *)id)->r.scemode & R_BG_RENDER) {
3609 files->entry->selflag |= FILE_SEL_SELECTED;
3610 }
3611 }
3612 }
3613# endif
3614 // files->entry->nr = totbl + 1;
3615 files->entry->poin = id;
3616 fake = id->flag & ID_FLAG_FAKEUSER;
3617 if (ELEM(idcode, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM)) {
3618 files->typeflag |= FILE_TYPE_IMAGE;
3619 }
3620# if 0
3621 if (id->lib && fake) {
3622 SNPRINTF(files->extra, "LF %d", id->us);
3623 }
3624 else if (id->lib) {
3625 SNPRINTF(files->extra, "L %d", id->us);
3626 }
3627 else if (fake) {
3628 SNPRINTF(files->extra, "F %d", id->us);
3629 }
3630 else {
3631 SNPRINTF(files->extra, " %d", id->us);
3632 }
3633# endif
3634
3635 if (id->lib) {
3636 if (totlib == 0) {
3637 firstlib = files;
3638 }
3639 totlib++;
3640 }
3641
3642 files++;
3643 }
3644 totbl++;
3645 }
3646 }
3647
3648 /* only qsort of library blocks */
3649 if (totlib > 1) {
3650 qsort(firstlib, totlib, sizeof(*files), compare_name);
3651 }
3652 }
3653}
3654#endif
3655
3660 ListBase *from_entries,
3661 int from_entries_num)
3662{
3663 BLI_assert(BLI_listbase_count(from_entries) == from_entries_num);
3664 if (from_entries_num <= 0) {
3665 return false;
3666 }
3667
3668 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3669 std::scoped_lock lock(job_params->lock);
3670 BLI_movelisttolist(&filelist->filelist.entries, from_entries);
3671 filelist->filelist.entries_num += from_entries_num;
3672
3673 return true;
3674}
3675
3676static bool filelist_readjob_should_recurse_into_entry(const int max_recursion,
3677 const bool is_lib,
3678 const int current_recursion_level,
3679 FileListInternEntry *entry)
3680{
3681 if (max_recursion == 0) {
3682 /* Recursive loading is disabled. */
3683 return false;
3684 }
3685 if (!is_lib && current_recursion_level > max_recursion) {
3686 /* No more levels of recursion left. */
3687 return false;
3688 }
3689 /* Show entries when recursion is set to `Blend file` even when `current_recursion_level`
3690 * exceeds `max_recursion`. */
3691 if (!is_lib && (current_recursion_level >= max_recursion) &&
3693 {
3694 return false;
3695 }
3696 if (entry->typeflag & FILE_TYPE_BLENDERLIB) {
3697 /* Libraries are already loaded recursively when recursive loaded is used. No need to add
3698 * them another time. This loading is done with the `LIST_LIB_RECURSIVE` option. */
3699 return false;
3700 }
3701 if (!(entry->typeflag & FILE_TYPE_DIR)) {
3702 /* Cannot recurse into regular file entries. */
3703 return false;
3704 }
3705 if (FILENAME_IS_CURRPAR(entry->relpath)) {
3706 /* Don't schedule go to parent entry, (`..`) */
3707 return false;
3708 }
3709
3710 return true;
3711}
3712
3713static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
3714 FileListReadJob *job_params,
3715 const bool *stop,
3716 bool *do_update,
3717 float *progress)
3718{
3719 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3720 ListBase entries = {nullptr};
3721 BLI_Stack *todo_dirs;
3722 TodoDir *td_dir;
3723 char dir[FILE_MAX_LIBEXTRA];
3724 char filter_glob[FILE_MAXFILE];
3725 const char *root = filelist->filelist.root;
3726 const int max_recursion = filelist->max_recursion;
3727 int dirs_done_count = 0, dirs_todo_count = 1;
3728
3729 todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__);
3730 td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs));
3731 td_dir->level = 1;
3732
3733 STRNCPY(dir, filelist->filelist.root);
3734 STRNCPY(filter_glob, filelist->filter_data.filter_glob);
3735
3736 BLI_path_abs(dir, job_params->main_filepath);
3737 BLI_path_normalize_dir(dir, sizeof(dir));
3738 td_dir->dir = BLI_strdup(dir);
3739
3740 /* Init the file indexer. */
3741 FileIndexer indexer_runtime{};
3742 indexer_runtime.callbacks = filelist->indexer;
3743 if (indexer_runtime.callbacks->init_user_data) {
3744 indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir));
3745 }
3746
3747 while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
3748 int entries_num = 0;
3749
3750 char *subdir;
3751 char rel_subdir[FILE_MAX_LIBEXTRA];
3752 int recursion_level;
3753 bool skip_currpar;
3754
3755 td_dir = static_cast<TodoDir *>(BLI_stack_peek(todo_dirs));
3756 subdir = td_dir->dir;
3757 recursion_level = td_dir->level;
3758 skip_currpar = (recursion_level > 1);
3759
3760 BLI_stack_discard(todo_dirs);
3761
3762 /* ARRRG! We have to be very careful *not to use* common `BLI_path_utils.hh` helpers over
3763 * entry->relpath itself (nor any path containing it), since it may actually be a datablock
3764 * name inside .blend file, which can have slashes and backslashes! See #46827.
3765 * Note that in the end, this means we 'cache' valid relative subdir once here,
3766 * this is actually better. */
3767 STRNCPY(rel_subdir, subdir);
3768 BLI_path_abs(rel_subdir, root);
3769 BLI_path_normalize_dir(rel_subdir, sizeof(rel_subdir));
3770 BLI_path_rel(rel_subdir, root);
3771
3772 /* Update the current relative base path within the filelist root. */
3773 STRNCPY(job_params->cur_relbase, rel_subdir);
3774
3775 bool is_lib = false;
3776 if (do_lib) {
3777 ListLibOptions list_lib_options = LIST_LIB_OPTION_NONE;
3778 if (!skip_currpar) {
3779 list_lib_options |= LIST_LIB_ADD_PARENT;
3780 }
3781
3782 /* Libraries are loaded recursively when max_recursion is set. It doesn't check if there is
3783 * still a recursion level over. */
3784 if (max_recursion > 0) {
3785 list_lib_options |= LIST_LIB_RECURSIVE;
3786 }
3787 /* Only load assets when browsing an asset library. For normal file browsing we return all
3788 * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user. */
3789 if (job_params->load_asset_library) {
3790 list_lib_options |= LIST_LIB_ASSETS_ONLY;
3791 }
3792 std::optional<int> lib_entries_num = filelist_readjob_list_lib(
3793 job_params, subdir, &entries, list_lib_options, &indexer_runtime);
3794 if (lib_entries_num) {
3795 is_lib = true;
3796 entries_num += *lib_entries_num;
3797 }
3798 }
3799
3800 if (!is_lib && BLI_is_dir(subdir)) {
3801 entries_num = filelist_readjob_list_dir(job_params,
3802 subdir,
3803 &entries,
3804 filter_glob,
3805 do_lib,
3806 job_params->main_filepath,
3807 skip_currpar);
3808 }
3809
3810 LISTBASE_FOREACH (FileListInternEntry *, entry, &entries) {
3811 entry->uid = filelist_uid_generate(filelist);
3812 entry->name = fileentry_uiname(root, entry, dir);
3813 entry->free_name = true;
3814
3816 max_recursion, is_lib, recursion_level, entry))
3817 {
3818 /* We have a directory we want to list, add it to todo list!
3819 * Using #BLI_path_join works but isn't needed as `root` has a trailing slash. */
3820 BLI_string_join(dir, sizeof(dir), root, entry->relpath);
3821 BLI_path_abs(dir, job_params->main_filepath);
3822 BLI_path_normalize_dir(dir, sizeof(dir));
3823 td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs));
3824 td_dir->level = recursion_level + 1;
3825 td_dir->dir = BLI_strdup(dir);
3826 dirs_todo_count++;
3827 }
3828 }
3829
3830 if (filelist_readjob_append_entries(job_params, &entries, entries_num)) {
3831 *do_update = true;
3832 }
3833
3834 dirs_done_count++;
3835 *progress = float(dirs_done_count) / float(dirs_todo_count);
3836 MEM_freeN(subdir);
3837 }
3838
3839 /* Finalize and free indexer. */
3840 if (indexer_runtime.callbacks->filelist_finished && BLI_stack_is_empty(todo_dirs)) {
3841 indexer_runtime.callbacks->filelist_finished(indexer_runtime.user_data);
3842 }
3843 if (indexer_runtime.callbacks->free_user_data && indexer_runtime.user_data) {
3844 indexer_runtime.callbacks->free_user_data(indexer_runtime.user_data);
3845 indexer_runtime.user_data = nullptr;
3846 }
3847
3848 /* If we were interrupted by stop, stack may not be empty and we need to free
3849 * pending dir paths. */
3850 while (!BLI_stack_is_empty(todo_dirs)) {
3851 td_dir = static_cast<TodoDir *>(BLI_stack_peek(todo_dirs));
3852 MEM_freeN(td_dir->dir);
3853 BLI_stack_discard(todo_dirs);
3854 }
3855 BLI_stack_free(todo_dirs);
3856}
3857
3858static void filelist_readjob_do(const bool do_lib,
3859 FileListReadJob *job_params,
3860 const bool *stop,
3861 bool *do_update,
3862 float *progress)
3863{
3864 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3865
3866 // BLI_assert(filelist->filtered == nullptr);
3869
3870 /* A valid, but empty directory from now. */
3871 filelist->filelist.entries_num = 0;
3872
3874}
3875
3877 bool *stop,
3878 bool *do_update,
3879 float *progress)
3880{
3881 filelist_readjob_do(false, job_params, stop, do_update, progress);
3882}
3883
3885 bool *stop,
3886 bool *do_update,
3887 float *progress)
3888{
3889 filelist_readjob_do(true, job_params, stop, do_update, progress);
3890}
3891
3896{
3897 FileList *tmp_filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3898
3899 *do_update = false;
3900
3901 if (job_params->filelist->asset_library_ref == nullptr) {
3902 return;
3903 }
3904 if (tmp_filelist->asset_library != nullptr && job_params->reload_asset_library == false) {
3905 /* Asset library itself is already loaded. Load assets into this. */
3906 job_params->load_asset_library = tmp_filelist->asset_library;
3907 return;
3908 }
3909
3910 /* Load asset catalogs, into the temp filelist for thread-safety.
3911 * #filelist_readjob_endjob() will move it into the real filelist. */
3912 tmp_filelist->asset_library = AS_asset_library_load(job_params->current_main,
3913 *job_params->filelist->asset_library_ref);
3914 /* Set asset library to load (may be overridden later for loading nested ones). */
3915 job_params->load_asset_library = tmp_filelist->asset_library;
3916 *do_update = true;
3917}
3918
3920 bool * /*stop*/,
3921 bool *do_update,
3922 float * /*progress*/)
3923{
3924 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3925
3926 FileListInternEntry *entry;
3927 ListBase tmp_entries = {nullptr};
3928 ID *id_iter;
3929 int entries_num = 0;
3930
3931 /* Make sure no IDs are added/removed/reallocated in the main thread while this is running in
3932 * parallel. */
3933 BKE_main_lock(job_params->current_main);
3934
3935 FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) {
3936 if (!id_iter->asset_data || ID_IS_LINKED(id_iter)) {
3937 continue;
3938 }
3939
3940 const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
3941
3942 entry = MEM_new<FileListInternEntry>(__func__);
3943 std::string datablock_path = StringRef(id_code_name) + SEP_STR + (id_iter->name + 2);
3944 entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
3945 entry->name = id_iter->name + 2;
3946 entry->free_name = false;
3948 entry->blentype = GS(id_iter->name);
3949 entry->uid = filelist_uid_generate(filelist);
3951 id_iter);
3952 entry->local_data.id = id_iter;
3953 if (job_params->load_asset_library) {
3954 entry->asset = job_params->load_asset_library->add_local_id_asset(entry->relpath, *id_iter);
3955 }
3956 entries_num++;
3957 BLI_addtail(&tmp_entries, entry);
3958 }
3960
3961 BKE_main_unlock(job_params->current_main);
3962
3963 if (entries_num) {
3964 *do_update = true;
3965
3966 BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries);
3967 filelist->filelist.entries_num += entries_num;
3968 filelist->filelist.entries_filtered_num = -1;
3969 }
3970}
3971
3979static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
3980{
3981 if (filelist->asset_library_ref && (filelist->asset_library_ref->type == ASSET_LIBRARY_ALL)) {
3982 return true;
3983 }
3984
3985 const char *blendfile_path = BKE_main_blendfile_path(bmain);
3986 return blendfile_path[0] && BLI_path_contains(filelist->filelist.root, blendfile_path);
3987}
3988
3990 bool *stop,
3991 bool *do_update,
3992 float *progress)
3993{
3994 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
3995
3998
3999 /* A valid, but empty file-list from now. */
4000 filelist->filelist.entries_num = 0;
4001
4002 BLI_assert(job_params->filelist->asset_library_ref != nullptr);
4003
4004 /* NOP if already read. */
4006
4007 if (filelist_contains_main(filelist, job_params->current_main)) {
4008 asset_system::AssetLibrary *original_file_library = job_params->load_asset_library;
4012 job_params->load_asset_library = original_file_library;
4013 }
4014 if (!job_params->only_main_data) {
4016 }
4017}
4018
4020 bool *stop,
4021 bool *do_update,
4022 float *progress)
4023{
4024 /* TODO! */
4026}
4027
4029 bool *stop,
4030 bool *do_update,
4031 float *progress)
4032{
4033 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
4036
4038
4039 /* A valid, but empty file-list from now. */
4040 filelist->filelist.entries_num = 0;
4041
4043}
4044
4046 bool *stop,
4047 bool *do_update,
4048 float *progress)
4049{
4050 FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
4053
4055
4056 /* A valid, but empty file-list from now. */
4057 filelist->filelist.entries_num = 0;
4058
4059 asset_system::AssetLibrary *current_file_library;
4060 {
4061 AssetLibraryReference library_ref{};
4062 library_ref.custom_library_index = -1;
4063 library_ref.type = ASSET_LIBRARY_LOCAL;
4064
4065 current_file_library = AS_asset_library_load(job_params->current_main, library_ref);
4066 }
4067
4068 job_params->load_asset_library = current_file_library;
4070
4071 /* When only doing partially reload for main data, we're done. */
4072 if (job_params->only_main_data) {
4073 return;
4074 }
4075
4076 /* Count how many asset libraries need to be loaded, for progress reporting. Not very precise. */
4077 int library_count = 0;
4078 asset_system::AssetLibrary::foreach_loaded([&library_count](auto &) { library_count++; }, false);
4079
4080 BLI_assert(filelist->asset_library != nullptr);
4081
4082 int libraries_done_count = 0;
4083 /* The "All" asset library was loaded, which means all other asset libraries are also loaded.
4084 * Load their assets from disk into the "All" library. */
4086 [&](asset_system::AssetLibrary &nested_library) {
4087 StringRefNull root_path = nested_library.root_path();
4088 if (root_path.is_empty()) {
4089 return;
4090 }
4091 if (&nested_library == current_file_library) {
4092 /* Skip the "Current File" library, it's already loaded above. */
4093 return;
4094 }
4095
4096 /* Override library info to read this library. */
4097 job_params->load_asset_library = &nested_library;
4098 STRNCPY(filelist->filelist.root, root_path.c_str());
4099
4100 float progress_this = 0.0f;
4102 true, job_params, stop, do_update, &progress_this);
4103
4104 libraries_done_count++;
4105 *progress = float(libraries_done_count) / library_count;
4106 },
4107 false);
4108}
4109
4114{
4115 return read_job->only_main_data;
4116}
4117
4123static void filelist_readjob_startjob(void *flrjv, wmJobWorkerStatus *worker_status)
4124{
4125 FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv);
4126
4127 // printf("START filelist reading (%d files, main thread: %d)\n",
4128 // flrj->filelist->filelist.entries_num, BLI_thread_is_main());
4129
4130 {
4131 std::scoped_lock lock(flrj->lock);
4132 BLI_assert((flrj->tmp_filelist == nullptr) && flrj->filelist);
4133
4134 flrj->tmp_filelist = static_cast<FileList *>(MEM_dupallocN(flrj->filelist));
4135
4138
4139 flrj->tmp_filelist->filelist_intern.filtered = nullptr;
4142 /* Don't unset the current UID on partial read, would give duplicates otherwise. */
4143 }
4144 else {
4146 }
4147
4148 flrj->tmp_filelist->libfiledata = nullptr;
4149 memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache));
4150 flrj->tmp_filelist->selection_state = nullptr;
4151 flrj->tmp_filelist->asset_library_ref = nullptr;
4153 }
4154
4156 flrj, &worker_status->stop, &worker_status->do_update, &worker_status->progress);
4157}
4158
4164static void filelist_readjob_update(void *flrjv)
4165{
4166 FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv);
4167 FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
4168 ListBase new_entries = {nullptr};
4169 int entries_num, new_entries_num = 0;
4170
4171 BLI_movelisttolist(&new_entries, &fl_intern->entries);
4172 entries_num = flrj->filelist->filelist.entries_num;
4173
4174 {
4175 std::scoped_lock lock(flrj->lock);
4176 if (flrj->tmp_filelist->filelist.entries_num > 0) {
4177 /* We just move everything out of 'thread context' into final list. */
4178 new_entries_num = flrj->tmp_filelist->filelist.entries_num;
4179 BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
4181 }
4182
4183 if (flrj->tmp_filelist->asset_library) {
4185 }
4186
4187 /* Important for partial reads: Copy increased UID counter back to the real list. */
4188 fl_intern->curr_uid = std::max(flrj->tmp_filelist->filelist_intern.curr_uid,
4189 fl_intern->curr_uid);
4190 }
4191
4192 if (new_entries_num) {
4193 /* Do not clear selection cache, we can assume already 'selected' UIDs are still valid! Keep
4194 * the asset library data we just read. */
4195 filelist_clear_ex(flrj->filelist, false, true, false);
4196
4198 }
4199
4200 /* if no new_entries_num, this is NOP */
4201 BLI_movelisttolist(&fl_intern->entries, &new_entries);
4202 flrj->filelist->filelist.entries_num = std::max(entries_num, 0) + new_entries_num;
4203}
4204
4205static void filelist_readjob_endjob(void *flrjv)
4206{
4207 FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv);
4208
4209 /* In case there would be some dangling update... */
4211
4212 flrj->filelist->flags &= ~FL_IS_PENDING;
4213 flrj->filelist->flags |= FL_IS_READY;
4214}
4215
4216static void filelist_readjob_free(void *flrjv)
4217{
4218 FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv);
4219
4220 // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.entries_num);
4221
4222 if (flrj->tmp_filelist) {
4223 /* tmp_filelist shall never ever be filtered! */
4226
4229 }
4230
4231 MEM_delete(flrj);
4232}
4233
4235{
4236 if (filelist->asset_library_ref) {
4238 }
4240}
4241
4242/* TODO(Julian): This is temporary, because currently the job system identifies jobs to suspend by
4243 * the startjob callback, rather than the type. See PR #123033. */
4244static void assetlibrary_readjob_startjob(void *flrjv, wmJobWorkerStatus *worker_status)
4245{
4246 filelist_readjob_startjob(flrjv, worker_status);
4247}
4248
4250 const int space_notifier,
4251 const bContext *C,
4252 const bool force_blocking_read)
4253{
4254 Main *bmain = CTX_data_main(C);
4255 wmJob *wm_job;
4256 FileListReadJob *flrj;
4257
4258 if (!filelist_is_dir(filelist, filelist->filelist.root)) {
4259 return;
4260 }
4261
4262 /* prepare job data */
4263 flrj = MEM_new<FileListReadJob>(__func__);
4264 flrj->filelist = filelist;
4265 flrj->current_main = bmain;
4267 if ((filelist->flags & FL_FORCE_RESET_MAIN_FILES) && !(filelist->flags & FL_FORCE_RESET) &&
4269 {
4270 flrj->only_main_data = true;
4271 }
4272 if (filelist->flags & FL_RELOAD_ASSET_LIBRARY) {
4273 flrj->reload_asset_library = true;
4274 }
4275
4277 FL_IS_READY);
4278 filelist->flags |= FL_IS_PENDING;
4279
4280 /* The file list type may not support threading so execute immediately. Same when only rereading
4281 * #Main data (which we do quite often on changes to #Main, since it's the easiest and safest way
4282 * to ensure the displayed data is up to date), because some operations executing right after
4283 * main data changed may need access to the ID files (see #93691). */
4284 const bool no_threads = (filelist->tags & FILELIST_TAGS_NO_THREADS) || flrj->only_main_data;
4285
4286 if (force_blocking_read || no_threads) {
4287 /* Single threaded execution. Just directly call the callbacks. */
4288 wmJobWorkerStatus worker_status = {};
4289 filelist_readjob_startjob(flrj, &worker_status);
4292
4293 WM_event_add_notifier(C, space_notifier | NA_JOB_FINISHED, nullptr);
4294 return;
4295 }
4296
4297 /* setup job */
4298 wm_job = WM_jobs_get(CTX_wm_manager(C),
4300 filelist,
4301 "Listing Dirs...",
4303 filelist_jobtype_get(filelist));
4305 WM_jobs_timer(wm_job, 0.01, space_notifier, space_notifier | NA_JOB_FINISHED);
4306 WM_jobs_callbacks(wm_job,
4309 nullptr,
4312
4313 /* start the job */
4314 WM_jobs_start(CTX_wm_manager(C), wm_job);
4315}
4316
4317void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
4318{
4319 filelist_readjob_start_ex(filelist, space_notifier, C, false);
4320}
4321
4322void filelist_readjob_blocking_run(FileList *filelist, int space_notifier, const bContext *C)
4323{
4324 filelist_readjob_start_ex(filelist, space_notifier, C, true);
4325}
4326
4328{
4329 WM_jobs_kill_type(wm, filelist, filelist_jobtype_get(filelist));
4330}
4331
4333{
4334 return WM_jobs_test(wm, filelist, filelist_jobtype_get(filelist));
4335}
blender::asset_system::AssetLibrary * AS_asset_library_load(const Main *bmain, const AssetLibraryReference &library_reference)
Main runtime representation of an asset.
PreviewImage * BKE_asset_metadata_preview_get_from_id(const AssetMetaData *asset_data, const ID *owner_id)
Definition asset.cc:189
bool BKE_blendfile_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition blendfile.cc:90
bool BKE_blendfile_extension_check(const char *str)
Definition blendfile.cc:84
wmWindow * CTX_wm_window(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT
Definition icons.cc:375
struct ImBuf * BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT
Definition icons.cc:385
bool BKE_icon_delete(int icon_id)
Definition icons.cc:455
uint64_t BKE_idtype_idcode_to_idfilter(short idcode)
Definition idtype.cc:366
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:165
short BKE_idtype_idcode_from_name(const char *idtype_name)
Definition idtype.cc:186
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:563
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:882
void BKE_main_lock(Main *bmain)
Definition main.cc:479
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
void BKE_main_unlock(Main *bmain)
Definition main.cc:484
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:877
struct bUserAssetLibrary * BKE_preferences_asset_library_find_index(const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
ImBuf * BKE_previewimg_to_imbuf(const PreviewImage *prv, int size)
bool BKE_previewimg_is_finished(const PreviewImage *prv, int size)
char * BLF_display_name_from_file(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition blf.cc:1063
#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.cc:250
#define FILE_ATTR_ANY_LINK
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:461
bool BLI_file_alias_target(const char *filepath, char r_targetpath[768]) ATTR_WARN_UNUSED_RESULT
struct stat BLI_stat_t
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:456
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
eFileAttributes
@ FILE_ATTR_ALIAS
@ FILE_ATTR_TEMPORARY
@ FILE_ATTR_HIDDEN
@ FILE_ATTR_SYSTEM
@ FILE_ATTR_OFFLINE
Some types for dealing with directories.
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:855
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:745
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:802
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghashutil_intcmp(const void *a, const void *b)
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.cc:678
unsigned int BLI_ghashutil_inthash_p(const void *ptr)
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, unsigned int nentries_reserve)
Definition BLI_ghash.cc:842
void void void BLI_movelisttolist(ListBase *dst, ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void copy_vn_i(int *array_tar, int size, int val)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL(1)
#define ALTSEP
bool bool BLI_path_extension_strip(char *path) ATTR_NONNULL(1)
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int BLI_path_normalize_dir(char *dir, size_t dir_maxncpy) ATTR_NONNULL(1)
bool BLI_path_has_hidden_component(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAXFILE
bool BLI_path_extension_check_array(const char *path, const char **ext_array) ATTR_NONNULL(1
#define FILE_MAX
bool BLI_path_contains(const char *container_path, const char *containee_path) ATTR_NONNULL(1
#define BLI_path_join(...)
#define FILENAME_IS_CURRENT(_n)
bool BLI_path_is_abs_from_cwd(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILENAME_IS_CURRPAR(_n)
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define SEP
bool BLI_path_extension_check(const char *path, const char *ext) ATTR_NONNULL(1
#define FILENAME_PARENT
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
bool BLI_path_extension_check_n(const char *path,...) ATTR_NONNULL(1) ATTR_SENTINEL(0)
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
const char * BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAXDIR
bool BLI_path_extension_check_glob(const char *path, const char *ext_fnmatch) ATTR_NONNULL(1
#define BLI_path_cmp
#define FILENAME_IS_PARENT(_n)
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:250
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:96
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:169
void * BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:103
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:176
#define BLI_stack_new(esize, descr)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define STRNCPY_RLEN(dst, src)
Definition BLI_string.h:598
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int char char int int int int BLI_strcmp_ignore_pad(const char *str1, const char *str2, char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
int char char int int int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, char pad, size_t dst_maxncpy) ATTR_NONNULL(1
int char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define BLI_string_join(...)
unsigned int uint
@ TASK_PRIORITY_LOW
Definition BLI_task.h:52
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:546
void BLI_task_pool_cancel(TaskPool *pool)
Definition task_pool.cc:536
TaskPool * BLI_task_pool_create_background(void *userdata, eTaskPriority priority)
Definition task_pool.cc:485
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:517
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:522
void BLI_thread_queue_push(ThreadQueue *queue, void *work)
Definition threads.cc:642
void * BLI_thread_queue_pop(ThreadQueue *queue)
Definition threads.cc:653
ThreadQueue * BLI_thread_queue_init(void)
Definition threads.cc:616
void BLI_thread_queue_free(ThreadQueue *queue)
Definition threads.cc:630
bool BLI_thread_queue_is_empty(ThreadQueue *queue)
Definition threads.cc:757
void BLI_thread_queue_nowait(ThreadQueue *queue)
Definition threads.cc:768
void * BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
Definition threads.cc:712
#define ARRAY_SIZE(arr)
#define ARRAY_SET_ITEMS(...)
#define ENUM_OPERATORS(_type, _max)
#define POINTER_FROM_INT(i)
#define POINTER_AS_UINT(i)
#define UNUSED_VARS_NDEBUG(...)
#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)
void BLO_datablock_info_linklist_free(LinkNode *datablock_infos)
LinkNode * BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, bool use_assets_only, int *r_tot_info_items)
#define BLO_GROUP_MAX
BlendHandle * BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports)
void BLO_blendhandle_close(BlendHandle *bh) ATTR_NONNULL(1)
LinkNode * BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:682
@ ICON_SIZE_PREVIEW
@ ID_TE
@ ID_IM
@ ID_LA
@ ID_SCE
@ ID_WO
@ ID_MA
@ ID_OB
@ ASSET_LIBRARY_CUSTOM
@ ASSET_LIBRARY_LOCAL
@ ASSET_LIBRARY_ALL
@ R_BG_RENDER
@ FILE_SORT_ASSET_CATALOG
@ 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
@ FILE_ASSET_LIBRARY_ALL
@ FILE_ENTRY_BLENDERLIB_NO_PREVIEW
@ FILE_ENTRY_PREVIEW_LOADING
@ FILE_ENTRY_NAME_FREE
@ FILE_ENTRY_INVALID_PREVIEW
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
eFileSel_Params_AssetCatalogVisibility
eDirEntry_SelectFlag
@ FILE_SEL_SELECTED
#define FILE_MAX_LIBEXTRA
eFileIndexerResult
@ FILE_INDEXER_ENTRIES_LOADED
void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries)
void ED_file_indexer_entries_extend_from_datablock_infos(FileIndexerEntries *indexer_entries, LinkNode *datablock_infos, int idcode)
FSMenu * ED_fsmenu_get()
Definition fsmenu.cc:46
FSMenuCategory
@ FS_CATEGORY_SYSTEM_BOOKMARKS
@ FS_CATEGORY_OTHER
@ FS_CATEGORY_SYSTEM
FSMenuEntry * ED_fsmenu_get_category(FSMenu *fsmenu, FSMenuCategory category)
Definition fsmenu.cc:54
int ED_path_extension_type(const char *path)
Definition filelist.cc:2756
void IMB_freeImBuf(ImBuf *ibuf)
const char * imb_ext_movie[]
const char * imb_ext_audio[]
const char * imb_ext_image[]
@ THB_LARGE
Definition IMB_thumbs.hh:23
void IMB_thumb_path_unlock(const char *path)
Definition thumbs.cc:719
ThumbSource
Definition IMB_thumbs.hh:27
@ THB_SOURCE_IMAGE
Definition IMB_thumbs.hh:28
@ THB_SOURCE_FONT
Definition IMB_thumbs.hh:31
@ THB_SOURCE_BLEND
Definition IMB_thumbs.hh:30
@ THB_SOURCE_MOVIE
Definition IMB_thumbs.hh:29
@ THB_SOURCE_OBJECT_IO
Definition IMB_thumbs.hh:32
void IMB_thumb_locks_acquire()
Definition thumbs.cc:672
ImBuf * IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
Definition thumbs.cc:534
void IMB_thumb_path_lock(const char *path)
Definition thumbs.cc:703
void IMB_thumb_locks_release()
Definition thumbs.cc:688
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
int UI_icon_from_idcode(int idcode)
ImBuf * UI_svg_icon_bitmap(uint icon_id, float size, bool multicolor=false)
eWM_JobType
Definition WM_api.hh:1723
@ WM_JOB_TYPE_ASSET_LIBRARY_LOAD
Definition WM_api.hh:1737
@ WM_JOB_TYPE_FILESEL_READDIR
Definition WM_api.hh:1736
@ WM_JOB_PROGRESS
Definition WM_api.hh:1716
bool stop
Definition WM_types.hh:1016
bool do_update
Definition WM_types.hh:1008
float progress
Definition WM_types.hh:1019
#define NA_JOB_FINISHED
Definition WM_types.hh:589
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)
volatile int lock
#define U
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
Definition btDbvt.cpp:418
constexpr bool is_empty() const
constexpr int64_t size() const
constexpr const char * c_str() const
AssetCatalog * find_catalog(CatalogID catalog_id) const
std::weak_ptr< AssetRepresentation > add_local_id_asset(StringRef relative_asset_path, ID &id)
AssetCatalogService & catalog_service() const
static void foreach_loaded(FunctionRef< void(AssetLibrary &)> fn, bool include_all_library)
bool remove_asset(AssetRepresentation &asset)
std::weak_ptr< AssetRepresentation > add_external_asset(StringRef relative_asset_path, StringRef name, int id_type, std::unique_ptr< AssetMetaData > metadata)
#define SELECT
CCL_NAMESPACE_BEGIN struct Options options
#define str(s)
const FileIndexerType file_indexer_noop
eDirEntry_SelectFlag filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
Definition filelist.cc:2981
int ED_file_icon(const FileDirEntry *file)
Definition filelist.cc:1348
#define FILELIST_ENTRYCACHESIZE_DEFAULT
Definition filelist.cc:164
static int compare_apply_inverted(int val, const FileSortData *sort_data)
Definition filelist.cc:369
static char * current_relpath_append(const FileListReadJob *job_params, const char *filename)
Definition filelist.cc:3093
static bool is_filtered_main_assets(FileListInternEntry *file, const char *, FileListFilter *filter)
Definition filelist.cc:925
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.cc:3676
void filelist_freelib(FileList *filelist)
Definition filelist.cc:2002
@ FLF_DO_FILTER
Definition filelist.cc:228
@ FLF_HIDE_LIB_DIR
Definition filelist.cc:231
@ FLF_HIDE_PARENT
Definition filelist.cc:230
@ FLF_ASSETS_ONLY
Definition filelist.cc:232
@ FLF_HIDE_DOT
Definition filelist.cc:229
void filelist_entry_parent_select_set(FileList *filelist, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:3007
void filelist_tag_force_reset(FileList *filelist)
Definition filelist.cc:2105
int filelist_files_num_entries(FileList *filelist)
Definition filelist.cc:2015
static eWM_JobType filelist_jobtype_get(const FileList *filelist)
Definition filelist.cc:4234
static std::optional< int > filelist_readjob_list_lib(FileListReadJob *job_params, const char *root, ListBase *entries, const ListLibOptions options, FileIndexer *indexer_runtime)
Definition filelist.cc:3363
static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
Definition filelist.cc:389
bool filelist_islibrary(FileList *filelist, char *dir, char **r_group)
Definition filelist.cc:3017
void filelist_entries_select_index_range_set(FileList *filelist, FileSelection *sel, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2946
static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter)
Definition filelist.cc:735
static void filelist_readjob_list_lib_add_datablocks(FileListReadJob *job_params, ListBase *entries, LinkNode *datablock_infos, const bool prefix_relpath_with_group_name, const int idcode, const char *group_name)
Definition filelist.cc:3288
const char * filelist_dir(const FileList *filelist)
Definition filelist.cc:2065
BlendHandle * filelist_lib(FileList *filelist)
Definition filelist.cc:2010
static void filelist_cache_previews_clear(FileListEntryCache *cache)
Definition filelist.cc:1593
void filelist_tag_needs_filtering(FileList *filelist)
Definition filelist.cc:945
void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
Definition filelist.cc:2626
static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter)
Definition filelist.cc:840
static bool filelist_readjob_append_entries(FileListReadJob *job_params, ListBase *from_entries, int from_entries_num)
Definition filelist.cc:3659
static void assetlibrary_readjob_startjob(void *flrjv, wmJobWorkerStatus *worker_status)
Definition filelist.cc:4244
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
Definition filelist.cc:1739
static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
Definition filelist.cc:1517
#define FILEDIR_NBR_ENTRIES_UNSET
Definition filelist.cc:88
static bool filelist_checkdir_main(const FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA], const bool do_change)
Definition filelist.cc:1409
static FileListInternEntry * filelist_entry_intern_get(const FileList *filelist, const int index)
Definition filelist.cc:2296
static void filelist_file_cache_block_release(FileList *filelist, const int size, int cursor)
Definition filelist.cc:2389
static void filelist_intern_free(FileList *filelist)
Definition filelist.cc:1483
static void filelist_cache_preview_freef(TaskPool *__restrict, void *taskdata)
Definition filelist.cc:1569
static void filelist_clear_main_files(FileList *filelist, const bool do_asset_library, const bool do_cache, const bool do_selection)
Definition filelist.cc:1917
blender::asset_system::AssetLibrary * filelist_asset_library(FileList *filelist)
Definition filelist.cc:1997
bool filelist_needs_force_reset(const FileList *filelist)
Definition filelist.cc:2100
static int compare_asset_catalog(void *user_data, const void *a1, const void *a2)
Definition filelist.cc:593
static void filelist_readjob_lib(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:3884
void filelist_readjob_blocking_run(FileList *filelist, int space_notifier, const bContext *C)
Definition filelist.cc:4322
bool filelist_file_is_preview_pending(const FileList *filelist, const FileDirEntry *file)
Definition filelist.cc:1163
static int filelist_readjob_list_dir(FileListReadJob *job_params, const char *root, ListBase *entries, const char *filter_glob, const bool do_lib, const char *main_filepath, const bool skip_currpar)
Definition filelist.cc:3116
static void filelist_readjob_start_ex(FileList *filelist, const int space_notifier, const bContext *C, const bool force_blocking_read)
Definition filelist.cc:4249
static FileDirEntry * filelist_file_create_entry(FileList *filelist, const int index)
Definition filelist.cc:2148
FileListTags
Definition filelist.cc:315
@ FILELIST_TAGS_USES_MAIN_DATA
Definition filelist.cc:317
@ FILELIST_TAGS_NO_THREADS
Definition filelist.cc:319
void filelist_clear_from_reset_tag(FileList *filelist)
Definition filelist.cc:1958
static void filelist_readjob_startjob(void *flrjv, wmJobWorkerStatus *worker_status)
Definition filelist.cc:4123
bool filelist_pending(const FileList *filelist)
Definition filelist.cc:2128
static void filelist_direntryarr_free(FileDirEntryArr *array)
Definition filelist.cc:1447
bool filelist_cache_previews_running(FileList *filelist)
Definition filelist.cc:2709
static FileDirEntry * filelist_cache_file_lookup(FileListEntryCache *cache, const int index)
Definition filelist.cc:2198
static void parent_dir_until_exists_or_default_root(char *dir)
Definition filelist.cc:1361
static bool filelist_checkdir_dir(const FileList *, char dirpath[FILE_MAX_LIBEXTRA], const bool do_change)
Definition filelist.cc:1375
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.cc:1011
static void filelist_readjob_do(const bool do_lib, FileListReadJob *job_params, const bool *stop, bool *do_update, float *progress)
Definition filelist.cc:3858
void filelist_set_asset_catalog_filter_options(FileList *filelist, eFileSel_Params_AssetCatalogVisibility catalog_visibility, const ::bUUID *catalog_id)
Definition filelist.cc:1074
void filelist_free(FileList *filelist)
Definition filelist.cc:1972
static void filelist_readjob_all_asset_library(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:4045
void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_library_ref)
Definition filelist.cc:1114
static AssetMetaData * filelist_file_internal_get_asset_data(const FileListInternEntry *file)
Definition filelist.cc:832
static void filelist_cache_previews_free(FileListEntryCache *cache)
Definition filelist.cc:1617
bool filelist_file_cache_block(FileList *filelist, const int index)
Definition filelist.cc:2410
static bool is_filtered_main(FileListInternEntry *file, const char *, FileListFilter *filter)
Definition filelist.cc:918
asset_system::AssetRepresentation * filelist_entry_get_asset_representation(const FileList *filelist, const int index)
Definition filelist.cc:2308
bool filelist_cache_previews_done(FileList *filelist)
Definition filelist.cc:2716
static int groupname_to_code(const char *group)
Definition filelist.cc:3025
static void filelist_readjob_dir(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:3876
static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition filelist.cc:913
void filelist_clear(FileList *filelist)
Definition filelist.cc:1953
static void filelist_readjob_main_assets(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:4028
ImBuf * filelist_get_preview_image(FileList *filelist, const int index)
Definition filelist.cc:1178
static void filelist_readjob_endjob(void *flrjv)
Definition filelist.cc:4205
void filelist_clear_ex(FileList *filelist, const bool do_asset_library, const bool do_cache, const bool do_selection)
Definition filelist.cc:1889
void filelist_free_icons()
Definition filelist.cc:1139
static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry)
Definition filelist.cc:2192
static bool filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
Definition filelist.cc:1677
const char * filelist_entry_get_relpath(const FileList *filelist, int index)
Definition filelist.cc:2320
void filelist_setdir(FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA])
Definition filelist.cc:2075
void filelist_tag_reload_asset_library(FileList *filelist)
Definition filelist.cc:2118
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size)
Definition filelist.cc:1783
ImBuf * filelist_geticon_special_file_image_ex(const FileDirEntry *file)
Definition filelist.cc:1199
int ED_file_extension_icon(const char *path)
Definition filelist.cc:2842
void filelist_setrecursion(FileList *filelist, const int recursion_level)
Definition filelist.cc:2092
static int compare_extension(void *user_data, const void *a1, const void *a2)
Definition filelist.cc:538
static int compare_size(void *user_data, const void *a1, const void *a2)
Definition filelist.cc:514
void filelist_setsorting(FileList *filelist, const short sort, bool invert_sort)
Definition filelist.cc:685
#define FILE_UID_UNSET
Definition filelist.cc:2326
ID * filelist_file_get_id(const FileDirEntry *file)
Definition filelist.cc:2315
bool filelist_cache_previews_update(FileList *filelist)
Definition filelist.cc:2651
static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter)
Definition filelist.cc:875
int filelist_file_find_path(FileList *filelist, const char *filename)
Definition filelist.cc:2260
static FileListInternEntry * filelist_readjob_list_lib_group_create(const FileListReadJob *job_params, const int idcode, const char *group_name)
Definition filelist.cc:3228
static FileDirEntry * filelist_geticon_get_file(FileList *filelist, const int index)
Definition filelist.cc:1171
static int compare_name(void *user_data, const void *a1, const void *a2)
Definition filelist.cc:476
static void filelist_entry_free(FileDirEntry *entry)
Definition filelist.cc:1441
void filelist_settype(FileList *filelist, short type)
Definition filelist.cc:1828
static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, bool *, bool *do_update, float *)
Definition filelist.cc:3919
FileList * filelist_new(short type)
Definition filelist.cc:1815
void filelist_entry_select_index_set(FileList *filelist, const int index, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2933
int filelist_file_find_id(const FileList *filelist, const ID *id)
Definition filelist.cc:2280
static void filelist_cache_free(FileListEntryCache *cache)
Definition filelist.cc:1762
static bool filelist_contains_main(const FileList *filelist, const Main *bmain)
Definition filelist.cc:3979
static void filelist_clear_asset_library(FileList *filelist)
Definition filelist.cc:1882
static FileListInternEntry * filelist_readjob_list_lib_navigate_to_parent_entry_create(const FileListReadJob *job_params)
Definition filelist.cc:3320
static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
Definition filelist.cc:425
FileDirEntry * filelist_file_ex(FileList *filelist, const int index, const bool use_request)
Definition filelist.cc:2211
bool filelist_uid_is_set(const FileUID uid)
Definition filelist.cc:2336
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:4327
static int filelist_readjob_list_lib_populate_from_index(FileListReadJob *job_params, ListBase *entries, const ListLibOptions options, const int read_from_index, const FileIndexerEntries *indexer_entries)
Definition filelist.cc:3341
static void filelist_readjob_update(void *flrjv)
Definition filelist.cc:4164
static void filelist_readjob_list_lib_add_from_indexer_entries(FileListReadJob *job_params, ListBase *entries, const FileIndexerEntries *indexer_entries, const bool prefix_relpath_with_group_name)
Definition filelist.cc:3302
int filelist_geticon_file_type(FileList *filelist, const int index, const bool is_main)
Definition filelist.cc:1341
static bool filelist_compare_asset_libraries(const AssetLibraryReference *library_a, const AssetLibraryReference *library_b)
Definition filelist.cc:1097
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
Definition filelist.cc:1582
int filelist_needs_reading(const FileList *filelist)
Definition filelist.cc:2878
static void filelist_readjob_recursive_dir_add_items(const bool do_lib, FileListReadJob *job_params, const bool *stop, bool *do_update, float *progress)
Definition filelist.cc:3713
ID * filelist_entry_get_id(const FileList *filelist, const int index)
Definition filelist.cc:2302
static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params, bool *do_update)
Definition filelist.cc:3895
void filelist_file_cache_slidingwindow_set(FileList *filelist, size_t window_size)
Definition filelist.cc:2348
@ FL_NEED_SORTING
Definition filelist.cc:306
@ FL_IS_PENDING
Definition filelist.cc:305
@ FL_SORT_INVERT
Definition filelist.cc:308
@ FL_IS_READY
Definition filelist.cc:304
@ FL_FORCE_RESET_MAIN_FILES
Definition filelist.cc:303
@ FL_NEED_FILTERING
Definition filelist.cc:307
@ FL_FORCE_RESET
Definition filelist.cc:300
@ FL_RELOAD_ASSET_LIBRARY
Definition filelist.cc:311
static bool filelist_file_cache_block_create(FileList *filelist, const int start_index, const int size, int cursor)
Definition filelist.cc:2365
static bool is_filtered_file_type(const FileListInternEntry *file, const FileListFilter *filter)
Definition filelist.cc:760
static void filelist_intern_entry_free(FileList *filelist, FileListInternEntry *entry)
Definition filelist.cc:1464
SpecialFileImages
Definition filelist.cc:322
static int compare_date(void *user_data, const void *a1, const void *a2)
Definition filelist.cc:490
int ED_path_extension_type(const char *path)
Definition filelist.cc:2756
int filelist_readjob_running(FileList *filelist, wmWindowManager *wm)
Definition filelist.cc:4332
ImBuf * filelist_file_get_preview_image(const FileDirEntry *file)
Definition filelist.cc:1185
void filelist_filter(FileList *filelist)
Definition filelist.cc:955
static bool is_filtered_hidden(const char *filename, const FileListFilter *filter, const FileListInternEntry *file)
Definition filelist.cc:700
static bool is_filtered_file(FileListInternEntry *file, const char *, FileListFilter *filter)
Definition filelist.cc:794
void filelist_tag_force_reset_mainfiles(FileList *filelist)
Definition filelist.cc:2110
static void filelist_entry_clear(FileDirEntry *entry)
Definition filelist.cc:1424
bool filelist_is_dir(const FileList *filelist, const char *path)
Definition filelist.cc:2070
static bool is_filtered_file_name(const FileListInternEntry *file, const FileListFilter *filter)
Definition filelist.cc:749
static int filelist_intern_free_main_files(FileList *filelist)
Definition filelist.cc:1497
bool filelist_needs_reset_on_main_changes(const FileList *filelist)
Definition filelist.cc:2133
int filelist_files_ensure(FileList *filelist)
Definition filelist.cc:2138
void filelist_sort(FileList *filelist)
Definition filelist.cc:649
static bool is_filtered_asset_library(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition filelist.cc:934
static void filelist_readjob_main(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:4019
static const char * fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff)
Definition filelist.cc:2020
static int filelist_geticon_file_type_ex(const FileList *filelist, const FileDirEntry *file, const bool is_main, const bool ignore_libdir)
Definition filelist.cc:1224
bool filelist_entry_is_selected(FileList *filelist, const int index)
Definition filelist.cc:2994
static bool is_filtered_lib_type(FileListInternEntry *file, const char *, FileListFilter *filter)
Definition filelist.cc:903
void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
Definition filelist.cc:1066
void filelist_file_get_full_path(const FileList *filelist, const FileDirEntry *file, char r_filepath[FILE_MAX_LIBEXTRA])
Definition filelist.cc:1149
FileDirEntry * filelist_file(FileList *filelist, int index)
Definition filelist.cc:2255
bool filelist_is_ready(const FileList *filelist)
Definition filelist.cc:2123
uint filelist_entry_select_set(const FileList *filelist, const FileDirEntry *entry, FileSelType select, const eDirEntry_SelectFlag flag, FileCheckType check)
Definition filelist.cc:2884
@ FLC_PREVIEWS_ACTIVE
Definition filelist.cc:199
@ FLC_IS_INIT
Definition filelist.cc:198
ListLibOptions
Definition filelist.cc:3213
@ LIST_LIB_ASSETS_ONLY
Definition filelist.cc:3221
@ LIST_LIB_OPTION_NONE
Definition filelist.cc:3214
@ LIST_LIB_ADD_PARENT
Definition filelist.cc:3224
@ LIST_LIB_RECURSIVE
Definition filelist.cc:3218
bool filelist_needs_filtering(FileList *filelist)
Definition filelist.cc:950
static bool filelist_checkdir_return_always_valid(const FileList *, char[FILE_MAX_LIBEXTRA], const bool)
Definition filelist.cc:1417
static bool filelist_readjob_is_partial_read(const FileListReadJob *read_job)
Definition filelist.cc:4113
ImBuf * filelist_geticon_special_file_image(FileList *filelist, const int index)
Definition filelist.cc:1218
void filelist_readjob_start(FileList *filelist, const int space_notifier, const bContext *C)
Definition filelist.cc:4317
static void filelist_readjob_free(void *flrjv)
Definition filelist.cc:4216
eDirEntry_SelectFlag filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
Definition filelist.cc:2963
static void filelist_readjob_list_lib_add_datablock(FileListReadJob *job_params, ListBase *entries, BLODataBlockInfo *datablock_info, const bool prefix_relpath_with_group_name, const int idcode, const char *group_name)
Definition filelist.cc:3242
static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry)
Definition filelist.cc:1354
static bool filelist_checkdir_lib(const FileList *, char dirpath[FILE_MAX_LIBEXTRA], const bool do_change)
Definition filelist.cc:1390
static ImBuf * filelist_ensure_special_file_image(SpecialFileImages image, int icon)
Definition filelist.cc:1190
static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data)
Definition filelist.cc:865
void filelist_uid_unset(FileUID *r_uid)
Definition filelist.cc:2343
static bool file_is_blend_backup(const char *str)
Definition filelist.cc:2729
static FileUID filelist_uid_generate(FileList *filelist)
Definition filelist.cc:2328
static bool is_filtered_id_file_type(const FileListInternEntry *file, const short id_code, const char *name, const FileListFilter *filter)
Definition filelist.cc:802
static ImBuf * gSpecialFileImages[int(SpecialFileImages::_Max)]
Definition filelist.cc:330
static void filelist_readjob_asset_library(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:3989
static bool filelist_file_preview_load_poll(const FileDirEntry *entry)
Definition filelist.cc:1641
uint32_t FileUID
Definition filelist.hh:33
FileSelType
Definition filelist.hh:35
@ FILE_SEL_REMOVE
Definition filelist.hh:36
@ FILE_SEL_ADD
Definition filelist.hh:37
@ FILE_SEL_TOGGLE
Definition filelist.hh:38
FileCheckType
Definition filelist.hh:41
@ CHECK_FILES
Definition filelist.hh:43
@ CHECK_DIRS
Definition filelist.hh:42
@ CHECK_ALL
Definition filelist.hh:44
#define select(A, B, C)
#define filter
#define printf(...)
#define FILTER_ID_ALL
#define MEM_SAFE_FREE(v)
#define ID_IS_LINKED(_id)
#define MAX_ID_NAME
#define MEM_reallocN(vmemh, len)
#define GS(a)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
bool MOV_is_movie_file(const char *filepath)
AssetLibraryReference current_file_library_reference()
AssetCatalogFilterSettings * file_create_asset_catalog_filter_settings()
std::mutex Mutex
Definition BLI_mutex.hh:47
static void update(bNodeTree *ntree)
return ret
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
struct bUUID catalog_id
User defined tag. Currently only used by assets, could be used more often at some point....
AssetMetaData * asset_data
FSMenuEntry * next
struct FileDirEntry * next
AssetRepresentationHandle * asset
char * redirection_path
const char * name
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.cc:3338
const FileIndexerType * callbacks
Definition filelist.cc:3333
TaskPool * previews_pool
Definition filelist.cc:188
ThreadQueue * previews_done
Definition filelist.cc:189
ListBase cached_entries
Definition filelist.cc:171
int * misc_entries_indices
Definition filelist.cc:181
FileDirEntry ** block_entries
Definition filelist.cc:175
FileListEntryPreview * preview
Definition filelist.cc:213
char filepath[FILE_MAX_LIBEXTRA]
Definition filelist.cc:204
char filter_glob[FILE_MAXFILE]
Definition filelist.cc:219
blender::ed::asset_browser::AssetCatalogFilterSettings * asset_catalog_filter
Definition filelist.cc:223
char filter_search[66]
Definition filelist.cc:220
uint64_t filter_id
Definition filelist.cc:218
uint64_t filter
Definition filelist.cc:217
PreviewImage * preview_image
Definition filelist.cc:119
eFileAttributes attributes
Definition filelist.cc:135
eFileSel_File_Types typeflag
Definition filelist.cc:97
struct FileListInternEntry::@323235363311344055157072064130162321141235372073 local_data
std::weak_ptr< asset_system::AssetRepresentation > asset
Definition filelist.cc:129
FileListInternEntry * next
Definition filelist.cc:93
FileListInternEntry * prev
Definition filelist.cc:93
bool blenderlib_has_no_preview
Definition filelist.cc:132
asset_system::AssetRepresentation * get_asset() const
Definition filelist.cc:142
const char * name
Definition filelist.cc:105
ListBase entries
Definition filelist.cc:158
FileUID curr_uid
Definition filelist.cc:161
FileListInternEntry ** filtered
Definition filelist.cc:159
asset_system::AssetLibrary * load_asset_library
Definition filelist.cc:3067
Main * current_main
Definition filelist.cc:3054
blender::Mutex lock
Definition filelist.cc:3052
FileList * tmp_filelist
Definition filelist.cc:3085
FileList * filelist
Definition filelist.cc:3055
char main_filepath[FILE_MAX]
Definition filelist.cc:3053
bool reload_asset_library
Definition filelist.cc:3073
void(* prepare_filter_fn)(const FileList *filelist, FileListFilter *filter)
Definition filelist.cc:292
bool(* filter_fn)(FileListInternEntry *file, const char *root, FileListFilter *filter)
Definition filelist.cc:290
FileDirEntryArr filelist
Definition filelist.cc:237
bool(* check_dir_fn)(const FileList *filelist, char dirpath[FILE_MAX_LIBEXTRA], const bool do_change)
Definition filelist.cc:282
short sort
Definition filelist.cc:246
short flags
Definition filelist.cc:244
AssetLibraryReference * asset_library_ref
Definition filelist.cc:241
void(* read_job_fn)(FileListReadJob *job_params, bool *stop, bool *do_update, float *progress)
Definition filelist.cc:287
short tags
Definition filelist.cc:295
FileListEntryCache filelist_cache
Definition filelist.cc:257
GHash * selection_state
Definition filelist.cc:269
short max_recursion
Definition filelist.cc:271
FileListIntern filelist_intern
Definition filelist.cc:255
eFileSelectType type
Definition filelist.cc:239
asset_system::AssetLibrary * asset_library
Definition filelist.cc:242
short recursion_level
Definition filelist.cc:272
BlendHandle * libfiledata
Definition filelist.cc:274
FileListFilter filter_data
Definition filelist.cc:248
const FileIndexerType * indexer
Definition filelist.cc:253
Definition DNA_ID.h:404
struct AssetMetaData * asset_data
Definition DNA_ID.h:413
struct Library * lib
Definition DNA_ID.h:410
int us
Definition DNA_ID.h:425
short flag
Definition DNA_ID.h:420
void * next
Definition DNA_ID.h:407
char name[66]
Definition DNA_ID.h:415
char filepath[1024]
Definition DNA_ID.h:507
struct LinkNode * next
void * first
int level
Definition filelist.cc:3047
char * dir
Definition filelist.cc:3048
struct stat s
i
Definition text_draw.cc:230
#define SEP_STR
Definition unit.cc:39
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:353
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:456
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:598
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:190
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:365
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:224
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:337
uint8_t flag
Definition wm_window.cc:139