From 9eb1c784c593df4d291e7415e204c8cbe7afa2cd Mon Sep 17 00:00:00 2001 From: Charliechen114514 <725610365@qq.com> Date: Tue, 30 Jun 2026 15:11:09 +0800 Subject: [PATCH] feat(wallpaper): discover runtime resource packs via Wallpapers path Add support for discovering third-party wallpaper resource packs at runtime, with zero compile-time coupling to any specific pack (e.g. CF-Gallery): no submodule, no #ifdef, no CMake option. Whether a pack is "enabled" is simply whether it is installed into the discovered location. - base/path: add a Wallpapers PathType resolving to /Wallpapers/, auto-created by setup() like the other standard directories. - base/file_operations: add filter_target_recursive(), an additive companion to filter_target() that descends into subdirectories so packs installed under wallpapers// are found. Existing flat callers are unaffected. - desktop/wallpaper: rework make_layer() to pick the first source that actually yields images (config source_path -> Pictures, flat; then Wallpapers, recursive). This also fixes a latent issue where an empty Pictures directory left the desktop without a wallpaper even when a bundled pack was available. Users without a pack see no change. CF-Gallery (CC BY-NC-ND 4.0) is consumed as such a pack: installing it into Wallpapers/cfgallery/ surfaces its images. The pack's own install rule lives in the CF-Gallery repo, not here. The wallpaper animation/rotation engine (gradient/movement switching) remains a follow-up. --- .../base/file_operations/filter_target.cpp | 23 ++++++++++++++++ desktop/base/file_operations/filter_target.h | 24 +++++++++++++++++ .../cfpath/desktop_main_path_resolvers.h | 4 ++- .../shell_layer_impl/wallpaper_setup.cpp | 26 ++++++++++++++++--- document/status/current.md | 1 + document/todo/desktop/aels_cross_repo_deps.md | 1 + 6 files changed, 74 insertions(+), 5 deletions(-) diff --git a/desktop/base/file_operations/filter_target.cpp b/desktop/base/file_operations/filter_target.cpp index ec5079f33..8394f43bb 100644 --- a/desktop/base/file_operations/filter_target.cpp +++ b/desktop/base/file_operations/filter_target.cpp @@ -69,4 +69,27 @@ QStringList filter_target(const QString& dirent_path, const QStringList& filters return result; } +QStringList filter_target_recursive(const QString& dirent_path, const QStringList& filters) { + QStringList result; + QDir dir(dirent_path); + + if (!dir.exists()) { + return result; + } + + // Collect matching files at this level (files only, same as filter_target). + const QFileInfoList files = dir.entryInfoList(filters, QDir::Files | QDir::NoDotAndDotDot); + for (const auto& entry : files) { + result.append(entry.absoluteFilePath()); + } + + // Descend into each subdirectory so nested resource packs are discovered. + const QFileInfoList subdirs = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const auto& sub : subdirs) { + result.append(filter_target_recursive(sub.absoluteFilePath(), filters)); + } + + return result; +} + } // namespace cf::desktop::base::filesystem diff --git a/desktop/base/file_operations/filter_target.h b/desktop/base/file_operations/filter_target.h index d3af46c4f..49dd094d3 100644 --- a/desktop/base/file_operations/filter_target.h +++ b/desktop/base/file_operations/filter_target.h @@ -40,4 +40,28 @@ QStringList& request_filterlist(const FilterType what); * @return QStringList */ QStringList filter_target(const QString& dirent_path, const QStringList& filters); + +/** + * @brief Recursively list files matching the filters under a directory. + * + * Like filter_target(), but descends into subdirectories so that files + * nested in pack subdirectories (for example a wallpaper resource pack + * installed under wallpapers//) are discovered. The top-level + * directory and every subdirectory are scanned; matching file paths are + * accumulated. + * + * @param[in] dirent_path Absolute path of the root directory to scan. + * @param[in] filters Name filters to match (for example image globs). + * + * @return Absolute file paths of matching files; empty if the directory + * does not exist or no file matches. + * + * @throws None. + * + * @note None. + * @warning None. + * @since 0.19 + * @ingroup filesystem + */ +QStringList filter_target_recursive(const QString& dirent_path, const QStringList& filters); } // namespace cf::desktop::base::filesystem diff --git a/desktop/base/path/include/cfpath/desktop_main_path_resolvers.h b/desktop/base/path/include/cfpath/desktop_main_path_resolvers.h index b8bf36cda..04cf35f5c 100644 --- a/desktop/base/path/include/cfpath/desktop_main_path_resolvers.h +++ b/desktop/base/path/include/cfpath/desktop_main_path_resolvers.h @@ -22,7 +22,8 @@ namespace cf::desktop::path { * @brief Provider for desktop main directory paths. * * Manages resolution of standard desktop directory paths including Home, - * Desktop, Documents, Downloads, Music, Pictures, Videos, Apps, and Runtime. + * Desktop, Documents, Downloads, Music, Pictures, Wallpapers, Videos, Apps, + * and Runtime. * * @ingroup desktop_base */ @@ -41,6 +42,7 @@ class DesktopMainPathProvider : public aex::Singleton { X(Downloads) \ X(Music) \ X(Pictures) \ + X(Wallpapers) \ X(Videos) \ X(Apps) \ X(Runtime) diff --git a/desktop/ui/components/shell_layer_impl/wallpaper_setup.cpp b/desktop/ui/components/shell_layer_impl/wallpaper_setup.cpp index 91b6a6260..760266a3b 100644 --- a/desktop/ui/components/shell_layer_impl/wallpaper_setup.cpp +++ b/desktop/ui/components/shell_layer_impl/wallpaper_setup.cpp @@ -1,5 +1,6 @@ #include "wallpaper_setup.h" #include "cflog.h" +#include "cfpath/desktop_main_path_resolvers.h" #include "filter_target.h" #include "shell_layer_impl/WallpaperShellLayerStrategy.h" #include "wallpaper/ImageWallPaperLayer.h" @@ -19,13 +20,30 @@ std::unique_ptr make_layer() { using namespace base::filesystem; auto layer = std::make_unique(); - // Resolve wallpaper pictures through policy chain + const QStringList pic_filters = request_filterlist(FilterType::Pictures); + + // Primary source: policy chain (config source_path -> Pictures), flat scan. auto picture_dirent = WallpaperImages().execute(); - if (!picture_dirent.has_value() || picture_dirent->isEmpty()) { - return layer; // return out! + QStringList pictures; + if (picture_dirent.has_value() && !picture_dirent->isEmpty()) { + pictures = filter_target(picture_dirent.value(), pic_filters); + } + + // Fallback: bundled Wallpapers directory, scanned recursively so resource + // packs installed under wallpapers// are discovered. Tried only when + // the primary source yielded nothing, so users with their own pictures are + // unaffected; an empty Pictures directory now falls through to the bundled + // pack instead of leaving the desktop without a wallpaper. + if (pictures.isEmpty()) { + const QString wallpapers_dir = path::DesktopMainPathProvider::instance().absolutePath( + path::DesktopMainPathProvider::PathType::Wallpapers); + pictures = filter_target_recursive(wallpapers_dir, pic_filters); + } + + if (pictures.isEmpty()) { + return layer; // No wallpaper available anywhere. } - auto pictures = filter_target(picture_dirent.value(), request_filterlist(FilterType::Pictures)); auto storage = std::make_unique(); storage->addTokens(WallPaperTokenFactory::fromFiles(pictures)); log::tracef("Initialized with {} files", storage->size()); diff --git a/document/status/current.md b/document/status/current.md index 24d9fd53f..521ccef49 100644 --- a/document/status/current.md +++ b/document/status/current.md @@ -59,6 +59,7 @@ description: CFDesktop 项目进度的唯一事实来源与全局导航。 ## 最近里程碑(git 可证) - **2026-06**:`refactor: refactor the ui subsystem`;`hwtier system enabled`;文档清理 +- **2026-06(壁纸资源包发现)**:壁纸层支持运行时动态发现第三方资源包——新增 `Wallpapers` PathType(`/Wallpapers/`)+ `filter_target_recursive` 递归扫描;`make_layer()` 改为「首个有图的源胜出」(config → Pictures 平铺,空则回退 Wallpapers 递归)。CF-Gallery 等包安装到 `Wallpapers//` 即被发现,**CFDesktop 零编译期耦合**(无 submodule/无 `#ifdef`/无 CMake option)。详见 [aels_cross_repo_deps.md](../todo/desktop/aels_cross_repo_deps.md)。动画轮播引擎(Gradient/Movement)留待下一批。 - **已达成**:Milestone 1「桌面骨架可见」;Phase 0 / 1 / 2 / A(CI) / 6 / G(Widget) / H(显示后端)(详见 [SUMMARY.md](../todo/done/SUMMARY.md)) ## 新人入门 diff --git a/document/todo/desktop/aels_cross_repo_deps.md b/document/todo/desktop/aels_cross_repo_deps.md index 95c81d66c..ea52f7a5c 100644 --- a/document/todo/desktop/aels_cross_repo_deps.md +++ b/document/todo/desktop/aels_cross_repo_deps.md @@ -21,6 +21,7 @@ description: CFDesktop 消费的 AELS 组织独立仓(含拟新建)的跨仓 | **lightroot** | 现代化 BuildRoot(根文件系统构建) | 与 OTA/部署同层 | | **edgecv** | OpenCV 封装(desktop + embedded) | 相机/图像应用可选依赖 | | **bareline** | 嵌入式+PC CLI 交互框架 | 终端 App 的 pty 层可借鉴 | +| **CF-Gallery** | 摄影静物壁纸静态资源包(CC BY-NC-ND 4.0,VitePress 收录站) | **非构建依赖**:运行时动态发现——资源包安装到 `/Wallpapers//`(默认 `~/desktop/Wallpapers/`)即被壁纸层递归扫描消费。CFDesktop 零编译期耦合(**无 submodule、无 `#ifdef`、无 CMake option**);图片绝不进二进制,「开关」=是否安装了该资源包。 | ---