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