Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_file/filelist.c
| Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | |||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "UI_interface_icons.h" | #include "UI_interface_icons.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "atomic_ops.h" | #include "atomic_ops.h" | ||||
| #include "file_indexer.h" | |||||
| #include "file_intern.h" | #include "file_intern.h" | ||||
| #include "filelist.h" | #include "filelist.h" | ||||
| #define FILEDIR_NBR_ENTRIES_UNSET -1 | #define FILEDIR_NBR_ENTRIES_UNSET -1 | ||||
| /* ----------------- FOLDERLIST (previous/next) -------------- */ | /* ----------------- FOLDERLIST (previous/next) -------------- */ | ||||
| typedef struct FolderList { | typedef struct FolderList { | ||||
| ▲ Show 20 Lines • Show All 247 Lines • ▼ Show 20 Lines | enum { | ||||
| FLC_IS_INIT = 1 << 0, | FLC_IS_INIT = 1 << 0, | ||||
| FLC_PREVIEWS_ACTIVE = 1 << 1, | FLC_PREVIEWS_ACTIVE = 1 << 1, | ||||
| }; | }; | ||||
| typedef struct FileListEntryPreview { | typedef struct FileListEntryPreview { | ||||
| char path[FILE_MAX]; | char path[FILE_MAX]; | ||||
| uint flags; | uint flags; | ||||
| int index; | int index; | ||||
| /* Some file types load the memory from runtime data, not from disk. We just wait until it's done | |||||
| * generating (BKE_previewimg_is_finished()). */ | |||||
| PreviewImage *in_memory_preview; | |||||
| int icon_id; | int icon_id; | ||||
| } FileListEntryPreview; | } FileListEntryPreview; | ||||
| /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing | /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing | ||||
| * tasks' data (see T74609). */ | * tasks' data (see T74609). */ | ||||
| typedef struct FileListEntryPreviewTaskData { | typedef struct FileListEntryPreviewTaskData { | ||||
| FileListEntryPreview *preview; | FileListEntryPreview *preview; | ||||
| Show All 28 Lines | typedef struct FileList { | ||||
| struct AssetLibrary *asset_library; /* Non-owning pointer. */ | struct AssetLibrary *asset_library; /* Non-owning pointer. */ | ||||
| short flags; | short flags; | ||||
| short sort; | short sort; | ||||
| FileListFilter filter_data; | FileListFilter filter_data; | ||||
| /** | |||||
| * File indexer to use. Attribute is always set. | |||||
| */ | |||||
| const struct FileIndexerType *indexer; | |||||
| struct FileListIntern filelist_intern; | struct FileListIntern filelist_intern; | ||||
| struct FileListEntryCache filelist_cache; | struct FileListEntryCache filelist_cache; | ||||
| /* We need to keep those info outside of actual filelist items, | /* We need to keep those info outside of actual filelist items, | ||||
| * because those are no more persistent | * because those are no more persistent | ||||
| * (only generated on demand, and freed as soon as possible). | * (only generated on demand, and freed as soon as possible). | ||||
| * Persistent part (mere list of paths + stat info) | * Persistent part (mere list of paths + stat info) | ||||
| ▲ Show 20 Lines • Show All 507 Lines • ▼ Show 20 Lines | static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter) | ||||
| BLI_assert_msg(filelist->asset_library, | BLI_assert_msg(filelist->asset_library, | ||||
| "prepare_filter_asset_library() should only be called when the file browser is " | "prepare_filter_asset_library() should only be called when the file browser is " | ||||
| "in asset browser mode"); | "in asset browser mode"); | ||||
| file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library); | file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library); | ||||
| } | } | ||||
| /** | /** | ||||
| * Copy a string from source to `dest`, but prefix and suffix it with a single space. | |||||
| * Assumes `dest` has at least space enough for the two spaces. | |||||
| */ | |||||
| static void tag_copy_with_spaces(char *dest, const char *source, const size_t dest_size) | |||||
| { | |||||
| BLI_assert(dest_size > 2); | |||||
| const size_t source_length = BLI_strncpy_rlen(dest + 1, source, dest_size - 2); | |||||
| dest[0] = ' '; | |||||
| dest[source_length + 1] = ' '; | |||||
| dest[source_length + 2] = '\0'; | |||||
| } | |||||
| /** | |||||
| * Return whether at least one tag matches the search filter. | * Return whether at least one tag matches the search filter. | ||||
| * Tags are searched as "entire words", so instead of searching for "tag" in the | * Tags are searched as "entire words", so instead of searching for "tag" in the | ||||
| * filter string, this function searches for " tag ". Assumes the search filter | * filter string, this function searches for " tag ". Assumes the search filter | ||||
| * starts and ends with a space. | * starts and ends with a space. | ||||
| * | * | ||||
| * Here the tags on the asset are written in set notation: | * Here the tags on the asset are written in set notation: | ||||
| * | * | ||||
| * `asset_tag_matches_filter(" some tags ", {"some", "blue"})` -> true | * `asset_tag_matches_filter(" some tags ", {"some", "blue"})` -> true | ||||
| * `asset_tag_matches_filter(" some tags ", {"som", "tag"})` -> false | * `asset_tag_matches_filter(" some tags ", {"som", "tag"})` -> false | ||||
| * `asset_tag_matches_filter(" some tags ", {})` -> false | * `asset_tag_matches_filter(" some tags ", {})` -> false | ||||
| */ | */ | ||||
| static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data) | static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data) | ||||
| { | { | ||||
| LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) { | LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) { | ||||
| char tag_name[MAX_NAME + 2]; /* sizeof(AssetTag::name) + 2 */ | if (BLI_strcasestr(asset_tag->name, filter_search) != NULL) { | ||||
| tag_copy_with_spaces(tag_name, asset_tag->name, sizeof(tag_name)); | |||||
| if (BLI_strcasestr(filter_search, tag_name) != NULL) { | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter) | static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter) | ||||
| { | { | ||||
| Show All 14 Lines | static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter) | ||||
| char filter_search[66]; /* sizeof(FileListFilter::filter_search) */ | char filter_search[66]; /* sizeof(FileListFilter::filter_search) */ | ||||
| const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search); | const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search); | ||||
| /* When doing a name comparison, get rid of the leading/trailing asterisks. */ | /* When doing a name comparison, get rid of the leading/trailing asterisks. */ | ||||
| filter_search[string_length - 1] = '\0'; | filter_search[string_length - 1] = '\0'; | ||||
| if (BLI_strcasestr(file->name, filter_search + 1) != NULL) { | if (BLI_strcasestr(file->name, filter_search + 1) != NULL) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| return asset_tag_matches_filter(filter_search + 1, asset_data); | |||||
| /* Replace the asterisks with spaces, so that we can do matching on " sometag "; that way | |||||
| * an artist searching for "redder" doesn't result in a match for the tag "red". */ | |||||
| filter_search[string_length - 1] = ' '; | |||||
| filter_search[0] = ' '; | |||||
| return asset_tag_matches_filter(filter_search, asset_data); | |||||
| } | } | ||||
| static bool is_filtered_lib_type(FileListInternEntry *file, | static bool is_filtered_lib_type(FileListInternEntry *file, | ||||
| const char *root, | const char *root, | ||||
| FileListFilter *filter) | FileListFilter *filter) | ||||
| { | { | ||||
| char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; | char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; | ||||
| ▲ Show 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | void filelist_setfilter_options(FileList *filelist, | ||||
| if (update) { | if (update) { | ||||
| /* And now, free filtered data so that we know we have to filter again. */ | /* And now, free filtered data so that we know we have to filter again. */ | ||||
| filelist_tag_needs_filtering(filelist); | filelist_tag_needs_filtering(filelist); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Set the indexer to be used by the filelist. | |||||
| * | |||||
| * The given indexer allocation should be handled by the caller or defined statically. | |||||
| */ | |||||
| void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer) | |||||
| { | |||||
| BLI_assert(filelist); | |||||
| BLI_assert(indexer); | |||||
| filelist->indexer = indexer; | |||||
| } | |||||
| /** | |||||
| * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is | * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is | ||||
| * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise. | * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise. | ||||
| */ | */ | ||||
| void filelist_set_asset_catalog_filter_options( | void filelist_set_asset_catalog_filter_options( | ||||
| FileList *filelist, | FileList *filelist, | ||||
| eFileSel_Params_AssetCatalogVisibility catalog_visibility, | eFileSel_Params_AssetCatalogVisibility catalog_visibility, | ||||
| const bUUID *catalog_id) | const bUUID *catalog_id) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | if (file->attributes & FILE_ATTR_TEMPORARY) { | ||||
| return ICON_FILE_CACHE; | return ICON_FILE_CACHE; | ||||
| } | } | ||||
| if (file->attributes & FILE_ATTR_SYSTEM) { | if (file->attributes & FILE_ATTR_SYSTEM) { | ||||
| return ICON_SYSTEM; | return ICON_SYSTEM; | ||||
| } | } | ||||
| } | } | ||||
| if (typeflag & FILE_TYPE_BLENDER) { | if (typeflag & FILE_TYPE_BLENDER) { | ||||
| return ICON_FILE_BLEND; | return (is_main || file->preview_icon_id) ? ICON_FILE_BLEND : ICON_BLENDER; | ||||
| } | } | ||||
| if (typeflag & FILE_TYPE_BLENDER_BACKUP) { | if (typeflag & FILE_TYPE_BLENDER_BACKUP) { | ||||
| return ICON_FILE_BACKUP; | return ICON_FILE_BACKUP; | ||||
| } | } | ||||
| if (typeflag & FILE_TYPE_IMAGE) { | if (typeflag & FILE_TYPE_IMAGE) { | ||||
| return ICON_FILE_IMAGE; | return ICON_FILE_IMAGE; | ||||
| } | } | ||||
| if (typeflag & FILE_TYPE_MOVIE) { | if (typeflag & FILE_TYPE_MOVIE) { | ||||
| ▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | |||||
| static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata) | static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata) | ||||
| { | { | ||||
| FileListEntryCache *cache = BLI_task_pool_user_data(pool); | FileListEntryCache *cache = BLI_task_pool_user_data(pool); | ||||
| FileListEntryPreviewTaskData *preview_taskdata = taskdata; | FileListEntryPreviewTaskData *preview_taskdata = taskdata; | ||||
| FileListEntryPreview *preview = preview_taskdata->preview; | FileListEntryPreview *preview = preview_taskdata->preview; | ||||
| ThumbSource source = 0; | ThumbSource source = 0; | ||||
| bool done = false; | |||||
| // printf("%s: Start (%d)...\n", __func__, threadid); | // printf("%s: Start (%d)...\n", __func__, threadid); | ||||
| if (preview->in_memory_preview) { | |||||
| if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) { | |||||
| ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW); | |||||
| if (imbuf) { | |||||
| preview->icon_id = BKE_icon_imbuf_create(imbuf); | |||||
| } | |||||
| done = true; | |||||
| } | |||||
| } | |||||
| else { | |||||
| // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); | // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); | ||||
| BLI_assert(preview->flags & | BLI_assert(preview->flags & | ||||
| (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | | (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | | ||||
| FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); | ||||
| if (preview->flags & FILE_TYPE_IMAGE) { | if (preview->flags & FILE_TYPE_IMAGE) { | ||||
| source = THB_SOURCE_IMAGE; | source = THB_SOURCE_IMAGE; | ||||
| } | } | ||||
| else if (preview->flags & | else if (preview->flags & | ||||
| (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { | (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { | ||||
| source = THB_SOURCE_BLEND; | source = THB_SOURCE_BLEND; | ||||
| } | } | ||||
| else if (preview->flags & FILE_TYPE_MOVIE) { | else if (preview->flags & FILE_TYPE_MOVIE) { | ||||
| source = THB_SOURCE_MOVIE; | source = THB_SOURCE_MOVIE; | ||||
| } | } | ||||
| else if (preview->flags & FILE_TYPE_FTFONT) { | else if (preview->flags & FILE_TYPE_FTFONT) { | ||||
| source = THB_SOURCE_FONT; | source = THB_SOURCE_FONT; | ||||
| } | } | ||||
| IMB_thumb_path_lock(preview->path); | IMB_thumb_path_lock(preview->path); | ||||
| /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate | /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate | ||||
| * in case user switch to a bigger preview size. */ | * in case user switch to a bigger preview size. */ | ||||
| ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source); | ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source); | ||||
| IMB_thumb_path_unlock(preview->path); | IMB_thumb_path_unlock(preview->path); | ||||
| if (imbuf) { | if (imbuf) { | ||||
| preview->icon_id = BKE_icon_imbuf_create(imbuf); | preview->icon_id = BKE_icon_imbuf_create(imbuf); | ||||
| } | } | ||||
| done = true; | |||||
| } | |||||
| if (done) { | |||||
| /* That way task freeing function won't free th preview, since it does not own it anymore. */ | |||||
| atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL); | |||||
| BLI_thread_queue_push(cache->previews_done, preview); | BLI_thread_queue_push(cache->previews_done, preview); | ||||
| atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); | atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); | ||||
| } | |||||
| // printf("%s: End (%d)...\n", __func__, threadid); | // printf("%s: End (%d)...\n", __func__, threadid); | ||||
| } | } | ||||
| static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata) | static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata) | ||||
| { | { | ||||
| FileListEntryPreviewTaskData *preview_taskdata = taskdata; | FileListEntryPreviewTaskData *preview_taskdata = taskdata; | ||||
| FileListEntryPreview *preview = preview_taskdata->preview; | |||||
| /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent | |||||
| * to previews_done queue. */ | |||||
| if (preview != NULL) { | |||||
| if (preview->icon_id) { | |||||
| BKE_icon_delete(preview->icon_id); | |||||
| } | |||||
| MEM_freeN(preview); | |||||
| } | |||||
| MEM_freeN(preview_taskdata); | MEM_freeN(preview_taskdata); | ||||
| } | } | ||||
| static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) | static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) | ||||
| { | { | ||||
| if (!cache->previews_pool) { | if (!cache->previews_pool) { | ||||
| cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW); | cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW); | ||||
| cache->previews_done = BLI_thread_queue_init(); | cache->previews_done = BLI_thread_queue_init(); | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (entry->flags & (FILE_ENTRY_INVALID_PREVIEW | FILE_ENTRY_PREVIEW_LOADING)) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (!(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | | if (!(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | | ||||
| FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { | ||||
| return; | return; | ||||
| } | } | ||||
| FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); | |||||
| FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; | FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; | ||||
| PreviewImage *preview_in_memory = intern_entry->local_data.preview_image; | |||||
| if (preview_in_memory && !BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)) { | |||||
| /* Nothing to set yet. Wait for next call. */ | |||||
| return; | |||||
| } | |||||
| filelist_cache_preview_ensure_running(cache); | |||||
| entry->flags |= FILE_ENTRY_PREVIEW_LOADING; | |||||
| FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); | |||||
| preview->index = index; | |||||
| preview->flags = entry->typeflag; | |||||
| preview->icon_id = 0; | |||||
| if (preview_in_memory) { | |||||
| /* TODO(mano-wii): No need to use the thread API here. */ | |||||
| BLI_assert(BKE_previewimg_is_finished(preview_in_memory, ICON_SIZE_PREVIEW)); | |||||
| preview->path[0] = '\0'; | |||||
| ImBuf *imbuf = BKE_previewimg_to_imbuf(preview_in_memory, ICON_SIZE_PREVIEW); | |||||
| if (imbuf) { | |||||
| preview->icon_id = BKE_icon_imbuf_create(imbuf); | |||||
| } | |||||
| BLI_thread_queue_push(cache->previews_done, preview); | |||||
| atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); | |||||
| } | |||||
| else { | |||||
| if (entry->redirection_path) { | if (entry->redirection_path) { | ||||
| BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); | BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_join_dirfile( | BLI_join_dirfile( | ||||
| preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); | preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath); | ||||
| } | } | ||||
| preview->index = index; | |||||
| preview->flags = entry->typeflag; | |||||
| preview->in_memory_preview = intern_entry->local_data.preview_image; | |||||
| preview->icon_id = 0; | |||||
| // printf("%s: %d - %s\n", __func__, preview->index, preview->path); | // printf("%s: %d - %s\n", __func__, preview->index, preview->path); | ||||
| filelist_cache_preview_ensure_running(cache); | |||||
| FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), | FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), | ||||
| __func__); | __func__); | ||||
| preview_taskdata->preview = preview; | preview_taskdata->preview = preview; | ||||
| entry->flags |= FILE_ENTRY_PREVIEW_LOADING; | |||||
| BLI_task_pool_push(cache->previews_pool, | BLI_task_pool_push(cache->previews_pool, | ||||
| filelist_cache_preview_runf, | filelist_cache_preview_runf, | ||||
| preview_taskdata, | preview_taskdata, | ||||
| true, | true, | ||||
| filelist_cache_preview_freef); | filelist_cache_preview_freef); | ||||
| } | } | ||||
| } | |||||
| static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) | static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) | ||||
| { | { | ||||
| BLI_listbase_clear(&cache->cached_entries); | BLI_listbase_clear(&cache->cached_entries); | ||||
| cache->block_cursor = cache->block_start_index = cache->block_center_index = | cache->block_cursor = cache->block_start_index = cache->block_center_index = | ||||
| cache->block_end_index = 0; | cache->block_end_index = 0; | ||||
| cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); | cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | FileList *filelist_new(short type) | ||||
| FileList *p = MEM_callocN(sizeof(*p), __func__); | FileList *p = MEM_callocN(sizeof(*p), __func__); | ||||
| filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); | filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); | ||||
| p->selection_state = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); | p->selection_state = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); | ||||
| p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; | p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; | ||||
| filelist_settype(p, type); | filelist_settype(p, type); | ||||
| p->indexer = &file_indexer_noop; | |||||
| return p; | return p; | ||||
| } | } | ||||
| void filelist_settype(FileList *filelist, short type) | void filelist_settype(FileList *filelist, short type) | ||||
| { | { | ||||
| if (filelist->type == type) { | if (filelist->type == type) { | ||||
| return; | return; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 801 Lines • ▼ Show 20 Lines | while (!BLI_thread_queue_is_empty(cache->previews_done)) { | ||||
| } | } | ||||
| /* entry might have been removed from cache in the mean time, | /* entry might have been removed from cache in the mean time, | ||||
| * we do not want to cache it again here. */ | * we do not want to cache it again here. */ | ||||
| entry = filelist_file_ex(filelist, preview->index, false); | entry = filelist_file_ex(filelist, preview->index, false); | ||||
| // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); | // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); | ||||
| if (entry) { | if (entry) { | ||||
| entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING; | |||||
| if (preview->icon_id) { | if (preview->icon_id) { | ||||
| /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous | /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous | ||||
| * process from trying to generate the same preview icon. */ | * process from trying to generate the same preview icon. */ | ||||
| BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet"); | BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet"); | ||||
| /* Move ownership over icon. */ | /* Move ownership over icon. */ | ||||
| entry->preview_icon_id = preview->icon_id; | entry->preview_icon_id = preview->icon_id; | ||||
| preview->icon_id = 0; | preview->icon_id = 0; | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| else { | else { | ||||
| /* We want to avoid re-processing this entry continuously! | /* We want to avoid re-processing this entry continuously! | ||||
| * Note that, since entries only live in cache, | * Note that, since entries only live in cache, | ||||
| * preview will be retried quite often anyway. */ | * preview will be retried quite often anyway. */ | ||||
| entry->flags |= FILE_ENTRY_INVALID_PREVIEW; | entry->flags |= FILE_ENTRY_INVALID_PREVIEW; | ||||
| } | } | ||||
| entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING; | |||||
| } | } | ||||
| else { | else { | ||||
| BKE_icon_delete(preview->icon_id); | BKE_icon_delete(preview->icon_id); | ||||
| } | } | ||||
| MEM_freeN(preview); | MEM_freeN(preview); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); | FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); | ||||
| entry->relpath = BLI_strdup(group_name); | entry->relpath = BLI_strdup(group_name); | ||||
| entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR; | entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR; | ||||
| entry->blentype = idcode; | entry->blentype = idcode; | ||||
| return entry; | return entry; | ||||
| } | } | ||||
| static void filelist_readjob_list_lib_add_datablocks(ListBase *entries, | static void filelist_readjob_list_lib_add_datablock(ListBase *entries, | ||||
| LinkNode *datablock_infos, | const BLODataBlockInfo *datablock_info, | ||||
| const bool prefix_relpath_with_group_name, | const bool prefix_relpath_with_group_name, | ||||
| const int idcode, | const int idcode, | ||||
| const char *group_name) | const char *group_name) | ||||
| { | { | ||||
| for (LinkNode *ln = datablock_infos; ln; ln = ln->next) { | |||||
| struct BLODataBlockInfo *info = ln->link; | |||||
| FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); | FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); | ||||
| if (prefix_relpath_with_group_name) { | if (prefix_relpath_with_group_name) { | ||||
| entry->relpath = BLI_sprintfN("%s/%s", group_name, info->name); | entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name); | ||||
| } | } | ||||
| else { | else { | ||||
| entry->relpath = BLI_strdup(info->name); | entry->relpath = BLI_strdup(datablock_info->name); | ||||
| } | } | ||||
| entry->typeflag |= FILE_TYPE_BLENDERLIB; | entry->typeflag |= FILE_TYPE_BLENDERLIB; | ||||
| if (info && info->asset_data) { | if (datablock_info && datablock_info->asset_data) { | ||||
| entry->typeflag |= FILE_TYPE_ASSET; | entry->typeflag |= FILE_TYPE_ASSET; | ||||
| /* Moves ownership! */ | /* Moves ownership! */ | ||||
| entry->imported_asset_data = info->asset_data; | entry->imported_asset_data = datablock_info->asset_data; | ||||
| } | } | ||||
| entry->blentype = idcode; | entry->blentype = idcode; | ||||
| BLI_addtail(entries, entry); | BLI_addtail(entries, entry); | ||||
| } | } | ||||
| static void filelist_readjob_list_lib_add_datablocks(ListBase *entries, | |||||
| LinkNode *datablock_infos, | |||||
| const bool prefix_relpath_with_group_name, | |||||
| const int idcode, | |||||
| const char *group_name) | |||||
| { | |||||
| for (LinkNode *ln = datablock_infos; ln; ln = ln->next) { | |||||
| struct BLODataBlockInfo *datablock_info = ln->link; | |||||
| filelist_readjob_list_lib_add_datablock( | |||||
| entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name); | |||||
| } | |||||
| } | |||||
| static void filelist_readjob_list_lib_add_from_indexer_entries( | |||||
| ListBase *entries, | |||||
| const FileIndexerEntries *indexer_entries, | |||||
| const bool prefix_relpath_with_group_name) | |||||
| { | |||||
| for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) { | |||||
| const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link; | |||||
| const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode); | |||||
| filelist_readjob_list_lib_add_datablock(entries, | |||||
| &indexer_entry->datablock_info, | |||||
| prefix_relpath_with_group_name, | |||||
| indexer_entry->idcode, | |||||
| group_name); | |||||
| } | |||||
| } | |||||
| static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(void) | |||||
| { | |||||
| FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); | |||||
| entry->relpath = BLI_strdup(FILENAME_PARENT); | |||||
| entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); | |||||
| return entry; | |||||
| } | |||||
| /** | |||||
| * Structure to keep the file indexer and its user data together. | |||||
| */ | |||||
| typedef struct FileIndexer { | |||||
| const FileIndexerType *callbacks; | |||||
| /** | |||||
| * User data. Contains the result of `callbacks.init_user_data`. | |||||
| */ | |||||
| void *user_data; | |||||
| } FileIndexer; | |||||
| static int filelist_readjob_list_lib_populate_from_index(ListBase *entries, | |||||
| const ListLibOptions options, | |||||
| const int read_from_index, | |||||
| const FileIndexerEntries *indexer_entries) | |||||
| { | |||||
| int navigate_to_parent_len = 0; | |||||
| if (options & LIST_LIB_ADD_PARENT) { | |||||
| FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create(); | |||||
| BLI_addtail(entries, entry); | |||||
| navigate_to_parent_len = 1; | |||||
| } | |||||
| filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true); | |||||
| return read_from_index + navigate_to_parent_len; | |||||
| } | } | ||||
| static int filelist_readjob_list_lib(const char *root, | static int filelist_readjob_list_lib(const char *root, | ||||
| ListBase *entries, | ListBase *entries, | ||||
| const ListLibOptions options) | const ListLibOptions options, | ||||
| FileIndexer *indexer_runtime) | |||||
| { | { | ||||
| BLI_assert(indexer_runtime); | |||||
| char dir[FILE_MAX_LIBEXTRA], *group; | char dir[FILE_MAX_LIBEXTRA], *group; | ||||
| struct BlendHandle *libfiledata = NULL; | struct BlendHandle *libfiledata = NULL; | ||||
| /* Check if the given root is actually a library. All folders are passed to | /* Check if the given root is actually a library. All folders are passed to | ||||
| * `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do` | * `filelist_readjob_list_lib` and based on the number of found entries `filelist_readjob_do` | ||||
| * will do a dir listing only when this function does not return any entries. */ | * will do a dir listing only when this function does not return any entries. */ | ||||
| /* TODO: We should consider introducing its own function to detect if it is a lib and | /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and | ||||
| * call it directly from `filelist_readjob_do` to increase readability. */ | * call it directly from `filelist_readjob_do` to increase readability. */ | ||||
| const bool is_lib = BLO_library_path_explode(root, dir, &group, NULL); | const bool is_lib = BLO_library_path_explode(root, dir, &group, NULL); | ||||
| if (!is_lib) { | if (!is_lib) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| const bool group_came_from_path = group != NULL; | |||||
| /* Try read from indexer_runtime. */ | |||||
| /* Indexing returns all entries in a blend file. We should ignore the index when listing a group | |||||
| * inside a blend file, so the `entries` isn't filled with undesired entries. | |||||
| * This happens when linking or appending data-blocks, where you can navigate into a group (fe | |||||
| * Materials/Objects) where you only want to work with partial indexes. | |||||
| * | |||||
| * Adding support for partial reading/updating indexes would increase the complexity. | |||||
| */ | |||||
| const bool use_indexer = !group_came_from_path; | |||||
| FileIndexerEntries indexer_entries = {NULL}; | |||||
| if (use_indexer) { | |||||
| int read_from_index = 0; | |||||
| eFileIndexerResult indexer_result = indexer_runtime->callbacks->read_index( | |||||
| dir, &indexer_entries, &read_from_index, indexer_runtime->user_data); | |||||
| if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) { | |||||
| int entries_read = filelist_readjob_list_lib_populate_from_index( | |||||
| entries, options, read_from_index, &indexer_entries); | |||||
| ED_file_indexer_entries_clear(&indexer_entries); | |||||
| return entries_read; | |||||
| } | |||||
| } | |||||
| /* Open the library file. */ | /* Open the library file. */ | ||||
| BlendFileReadReport bf_reports = {.reports = NULL}; | BlendFileReadReport bf_reports = {.reports = NULL}; | ||||
| libfiledata = BLO_blendhandle_from_file(dir, &bf_reports); | libfiledata = BLO_blendhandle_from_file(dir, &bf_reports); | ||||
| if (libfiledata == NULL) { | if (libfiledata == NULL) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* Add current parent when requested. */ | /* Add current parent when requested. */ | ||||
| int parent_len = 0; | /* Is the navigate to previous level added to the list of entries. When added the return value | ||||
| * should be increased to match the actual number of entries added. It is introduced to keep | |||||
| * the code clean and readable and not counting in a single variable. */ | |||||
| int navigate_to_parent_len = 0; | |||||
| if (options & LIST_LIB_ADD_PARENT) { | if (options & LIST_LIB_ADD_PARENT) { | ||||
| FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); | FileListInternEntry *entry = filelist_readjob_list_lib_navigate_to_parent_entry_create(); | ||||
| entry->relpath = BLI_strdup(FILENAME_PARENT); | |||||
| entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); | |||||
| BLI_addtail(entries, entry); | BLI_addtail(entries, entry); | ||||
| parent_len = 1; | navigate_to_parent_len = 1; | ||||
| } | } | ||||
| int group_len = 0; | int group_len = 0; | ||||
| int datablock_len = 0; | int datablock_len = 0; | ||||
| const bool group_came_from_path = group != NULL; | |||||
| if (group_came_from_path) { | if (group_came_from_path) { | ||||
| const int idcode = groupname_to_code(group); | const int idcode = groupname_to_code(group); | ||||
| LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info( | LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info( | ||||
| libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len); | libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len); | ||||
| filelist_readjob_list_lib_add_datablocks(entries, datablock_infos, false, idcode, group); | filelist_readjob_list_lib_add_datablocks(entries, datablock_infos, false, idcode, group); | ||||
| BLI_linklist_freeN(datablock_infos); | BLI_linklist_freeN(datablock_infos); | ||||
| } | } | ||||
| else { | else { | ||||
| LinkNode *groups = BLO_blendhandle_get_linkable_groups(libfiledata); | LinkNode *groups = BLO_blendhandle_get_linkable_groups(libfiledata); | ||||
| group_len = BLI_linklist_count(groups); | group_len = BLI_linklist_count(groups); | ||||
| for (LinkNode *ln = groups; ln; ln = ln->next) { | for (LinkNode *ln = groups; ln; ln = ln->next) { | ||||
| const char *group_name = ln->link; | const char *group_name = ln->link; | ||||
| const int idcode = groupname_to_code(group_name); | const int idcode = groupname_to_code(group_name); | ||||
| FileListInternEntry *group_entry = filelist_readjob_list_lib_group_create(idcode, | FileListInternEntry *group_entry = filelist_readjob_list_lib_group_create(idcode, | ||||
| group_name); | group_name); | ||||
| BLI_addtail(entries, group_entry); | BLI_addtail(entries, group_entry); | ||||
| if (options & LIST_LIB_RECURSIVE) { | if (options & LIST_LIB_RECURSIVE) { | ||||
| int group_datablock_len; | int group_datablock_len; | ||||
| LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info( | LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info( | ||||
| libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len); | libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len); | ||||
| filelist_readjob_list_lib_add_datablocks( | filelist_readjob_list_lib_add_datablocks( | ||||
| entries, group_datablock_infos, true, idcode, group_name); | entries, group_datablock_infos, true, idcode, group_name); | ||||
| if (use_indexer) { | |||||
| ED_file_indexer_entries_extend_from_datablock_infos( | |||||
| &indexer_entries, group_datablock_infos, idcode); | |||||
| } | |||||
| BLI_linklist_freeN(group_datablock_infos); | BLI_linklist_freeN(group_datablock_infos); | ||||
| datablock_len += group_datablock_len; | datablock_len += group_datablock_len; | ||||
| } | } | ||||
| } | } | ||||
| BLI_linklist_freeN(groups); | BLI_linklist_freeN(groups); | ||||
| } | } | ||||
| BLO_blendhandle_close(libfiledata); | BLO_blendhandle_close(libfiledata); | ||||
| /* Update the index. */ | |||||
| if (use_indexer) { | |||||
| indexer_runtime->callbacks->update_index(dir, &indexer_entries, indexer_runtime->user_data); | |||||
| ED_file_indexer_entries_clear(&indexer_entries); | |||||
| } | |||||
| /* Return the number of items added to entries. */ | /* Return the number of items added to entries. */ | ||||
| int added_entries_len = group_len + datablock_len + parent_len; | int added_entries_len = group_len + datablock_len + navigate_to_parent_len; | ||||
| return added_entries_len; | return added_entries_len; | ||||
| } | } | ||||
| #if 0 | #if 0 | ||||
| /* Kept for reference here, in case we want to add back that feature later. | /* Kept for reference here, in case we want to add back that feature later. | ||||
| * We do not need it currently. */ | * We do not need it currently. */ | ||||
| /* Code ***NOT*** updated for job stuff! */ | /* Code ***NOT*** updated for job stuff! */ | ||||
| static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist) | static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist) | ||||
| ▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | typedef struct FileListReadJob { | ||||
| * #Main may have received changes of interest (e.g. asset removed or renamed). */ | * #Main may have received changes of interest (e.g. asset removed or renamed). */ | ||||
| bool only_main_data; | bool only_main_data; | ||||
| /** Shallow copy of #filelist for thread-safe access. | /** Shallow copy of #filelist for thread-safe access. | ||||
| * | * | ||||
| * The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist | * The job system calls #filelist_readjob_update which moves any read file from #tmp_filelist | ||||
| * into #filelist in a thread-safe way. | * into #filelist in a thread-safe way. | ||||
| * | * | ||||
| * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread, and | * #tmp_filelist also keeps an `AssetLibrary *` so that it can be loaded in the same thread, | ||||
| * moved to #filelist once all categories are loaded. | * and moved to #filelist once all categories are loaded. | ||||
| * | * | ||||
| * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be set | * NOTE: #tmp_filelist is freed in #filelist_readjob_free, so any copied pointers need to be | ||||
| * to NULL to avoid double-freeing them. */ | * set to NULL to avoid double-freeing them. */ | ||||
| struct FileList *tmp_filelist; | struct FileList *tmp_filelist; | ||||
| } FileListReadJob; | } FileListReadJob; | ||||
| static void filelist_readjob_append_entries(FileListReadJob *job_params, | static void filelist_readjob_append_entries(FileListReadJob *job_params, | ||||
| ListBase *from_entries, | ListBase *from_entries, | ||||
| int nbr_from_entries, | int nbr_from_entries, | ||||
| short *do_update) | short *do_update) | ||||
| { | { | ||||
| Show All 20 Lines | static bool filelist_readjob_should_recurse_into_entry(const int max_recursion, | ||||
| if (max_recursion == 0) { | if (max_recursion == 0) { | ||||
| /* Recursive loading is disabled. */ | /* Recursive loading is disabled. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (!is_lib && current_recursion_level > max_recursion) { | if (!is_lib && current_recursion_level > max_recursion) { | ||||
| /* No more levels of recursion left. */ | /* No more levels of recursion left. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Show entries when recursion is set to `Blend file` even when `current_recursion_level` exceeds | /* Show entries when recursion is set to `Blend file` even when `current_recursion_level` | ||||
| * `max_recursion`. */ | * exceeds `max_recursion`. */ | ||||
| if (!is_lib && (current_recursion_level >= max_recursion) && | if (!is_lib && (current_recursion_level >= max_recursion) && | ||||
| ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) { | ((entry->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) == 0)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (entry->typeflag & FILE_TYPE_BLENDERLIB) { | if (entry->typeflag & FILE_TYPE_BLENDERLIB) { | ||||
| /* Libraries are already loaded recursively when recursive loaded is used. No need to add | /* Libraries are already loaded recursively when recursive loaded is used. No need to add | ||||
| * them another time. This loading is done with the `LIST_LIB_RECURSIVE` option. */ | * them another time. This loading is done with the `LIST_LIB_RECURSIVE` option. */ | ||||
| return false; | return false; | ||||
| Show All 31 Lines | static void filelist_readjob_recursive_dir_add_items(const bool do_lib, | ||||
| td_dir->level = 1; | td_dir->level = 1; | ||||
| BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); | BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); | ||||
| BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); | BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); | ||||
| BLI_path_normalize_dir(job_params->main_name, dir); | BLI_path_normalize_dir(job_params->main_name, dir); | ||||
| td_dir->dir = BLI_strdup(dir); | td_dir->dir = BLI_strdup(dir); | ||||
| /* Init the file indexer. */ | |||||
| FileIndexer indexer_runtime = {.callbacks = filelist->indexer}; | |||||
| if (indexer_runtime.callbacks->init_user_data) { | |||||
| indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir)); | |||||
| } | |||||
| while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { | while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { | ||||
| FileListInternEntry *entry; | FileListInternEntry *entry; | ||||
| int nbr_entries = 0; | int nbr_entries = 0; | ||||
| char *subdir; | char *subdir; | ||||
| char rel_subdir[FILE_MAX_LIBEXTRA]; | char rel_subdir[FILE_MAX_LIBEXTRA]; | ||||
| int recursion_level; | int recursion_level; | ||||
| bool skip_currpar; | bool skip_currpar; | ||||
| Show All 26 Lines | if (do_lib) { | ||||
| if (max_recursion > 0) { | if (max_recursion > 0) { | ||||
| list_lib_options |= LIST_LIB_RECURSIVE; | list_lib_options |= LIST_LIB_RECURSIVE; | ||||
| } | } | ||||
| /* Only load assets when browsing an asset library. For normal file browsing we return all | /* Only load assets when browsing an asset library. For normal file browsing we return all | ||||
| * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user.*/ | * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user.*/ | ||||
| if (filelist->asset_library_ref) { | if (filelist->asset_library_ref) { | ||||
| list_lib_options |= LIST_LIB_ASSETS_ONLY; | list_lib_options |= LIST_LIB_ASSETS_ONLY; | ||||
| } | } | ||||
| nbr_entries = filelist_readjob_list_lib(subdir, &entries, list_lib_options); | nbr_entries = filelist_readjob_list_lib( | ||||
| subdir, &entries, list_lib_options, &indexer_runtime); | |||||
| if (nbr_entries > 0) { | if (nbr_entries > 0) { | ||||
| is_lib = true; | is_lib = true; | ||||
| } | } | ||||
| } | } | ||||
| if (!is_lib) { | if (!is_lib) { | ||||
| nbr_entries = filelist_readjob_list_dir( | nbr_entries = filelist_readjob_list_dir( | ||||
| subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar); | subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar); | ||||
| Show All 25 Lines | while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { | ||||
| filelist_readjob_append_entries(job_params, &entries, nbr_entries, do_update); | filelist_readjob_append_entries(job_params, &entries, nbr_entries, do_update); | ||||
| nbr_done_dirs++; | nbr_done_dirs++; | ||||
| *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; | *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs; | ||||
| MEM_freeN(subdir); | MEM_freeN(subdir); | ||||
| } | } | ||||
| /* Finalize and free indexer. */ | |||||
| if (indexer_runtime.callbacks->filelist_finished && BLI_stack_is_empty(todo_dirs)) { | |||||
| indexer_runtime.callbacks->filelist_finished(indexer_runtime.user_data); | |||||
| } | |||||
| if (indexer_runtime.callbacks->free_user_data && indexer_runtime.user_data) { | |||||
| indexer_runtime.callbacks->free_user_data(indexer_runtime.user_data); | |||||
| indexer_runtime.user_data = NULL; | |||||
| } | |||||
| /* If we were interrupted by stop, stack may not be empty and we need to free | /* If we were interrupted by stop, stack may not be empty and we need to free | ||||
| * pending dir paths. */ | * pending dir paths. */ | ||||
| while (!BLI_stack_is_empty(todo_dirs)) { | while (!BLI_stack_is_empty(todo_dirs)) { | ||||
| td_dir = BLI_stack_peek(todo_dirs); | td_dir = BLI_stack_peek(todo_dirs); | ||||
| MEM_freeN(td_dir->dir); | MEM_freeN(td_dir->dir); | ||||
| BLI_stack_discard(todo_dirs); | BLI_stack_discard(todo_dirs); | ||||
| } | } | ||||
| BLI_stack_free(todo_dirs); | BLI_stack_free(todo_dirs); | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, | ||||
| ID *id_iter; | ID *id_iter; | ||||
| int nbr_entries = 0; | int nbr_entries = 0; | ||||
| /* Make sure no IDs are added/removed/reallocated in the main thread while this is running in | /* Make sure no IDs are added/removed/reallocated in the main thread while this is running in | ||||
| * parallel. */ | * parallel. */ | ||||
| BKE_main_lock(job_params->current_main); | BKE_main_lock(job_params->current_main); | ||||
| FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) { | FOREACH_MAIN_ID_BEGIN (job_params->current_main, id_iter) { | ||||
| if (!id_iter->asset_data) { | if (!id_iter->asset_data || ID_IS_LINKED(id_iter)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name)); | const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name)); | ||||
| entry = MEM_callocN(sizeof(*entry), __func__); | entry = MEM_callocN(sizeof(*entry), __func__); | ||||
| entry->relpath = BLI_strdup(id_code_name); | entry->relpath = BLI_strdup(id_code_name); | ||||
| entry->name = id_iter->name + 2; | entry->name = id_iter->name + 2; | ||||
| ▲ Show 20 Lines • Show All 279 Lines • Show Last 20 Lines | |||||