- 桌面应用
【免费下载链接】WinDynamicDesktop
Port of macOS Mojave Dynamic Desktop feature to Windows
导读
WinDynamicDesktop 是一款将 macOS Mojave 独有的 Dynamic Desktop(动态桌面)特性移植到 Windows 10/11 的开源桌面工具,它以用户所在位置推算日出与日落时间,并据此在一天 24 小时内循环切换多张壁纸图片,让桌面壁纸像 macOS 一样随天色自然变化。本文以项目官方 README 为骨架,结合仓库源码(主题加载、调度器、脚本引擎、配置体系等)逐层展开,读完你将掌握动态壁纸的完整工作原理、theme.json主题格式与校验规则、日出日落调度的三种位置模式与内部时间分段算法,以及如何用 PowerShell 脚本扩展程序行为、如何编辑settings.json配置文件。
项目定位:从 macOS Mojave 移植到 Windows 的 Dynamic Desktop
在 macOS Mojave 中,Apple 首次引入了"动态桌面"特性:系统根据一天中时间的变化自动更换桌面壁纸,呈现从清晨、白天、黄昏到夜晚的连续视觉效果。WinDynamicDesktop 正是该特性的 Windows 移植版,其 README 明确写道:
Port of macOS Mojave Dynamic Desktop feature to Windows 10 and 11. Available on GitHub and the Microsoft Store.
程序核心逻辑由 C# 编写,目标框架为net10.0-windows10.0.19041.0,同时产出win-x86、win-x64、win-arm64三种运行时架构(见 WinDynamicDesktop.csproj)。项目同时提供桌面版(WinExe)与 UWP 打包版(uwp/ 目录中的Package.appxmanifest与WinDynamicDesktop.Package.wapproj),通过 UwpDesktop.cs 中的GetHelper()在两种运行形态之间自动选择底层实现:桌面版调用DesktopHelper,UWP 版调用UwpHelper。
获取与安装方式
根据 README 与仓库配套脚本,项目提供以下分发渠道:
| 渠道 | 说明 |
|---|---|
| GitHub Releases | 直接下载安装包,由 scripts/package.ps1 与 Inno Setup 脚本 scripts/installer.iss 构建 |
| Microsoft Store | UWP 版本,应用 ID9NM8N7DQ3Z5F,可访问 Windows 位置 API |
| Chocolatey | 包名windynamicdesktop,打包元数据见 scripts/windynamicdesktop.nuspec |
| WinGet | 包名t1m0thyj.WinDynamicDesktop |
若需从源码获取,可执行git clone https://gitcode.com/gh_mirrors/wi/WinDynamicDesktop后参照 WinDynamicDesktop.sln 使用 Visual Studio 打开解决方案构建。README 特别提示:项目主要面向 Windows 11 开发,但理论上支持 Windows 7 及以上版本;Windows Insider 预览版不作为官方支持对象。
从源码结构看,安装器在安装完成后会通过{app}\WinDynamicDesktop.pth文件记录用户数据目录(scripts/installer.iss),程序启动时(Program.cs 的FindCwd())会读取该文件并把当前工作目录切换到用户数据目录,从而保证themes、scripts、settings.json等数据与程序本体隔离,便于升级与卸载。
核心工作原理:壁纸如何"动态"起来
动态壁纸的本质是一个时间驱动的壁纸切换调度器。一次完整的工作循环由以下模块协作完成,调用链可以概括为:
位置 → 日出/日落与太阳时角计算 → 划分时间分段 → 计算当前图片与下次更新时间 → 切换壁纸调度中枢 EventScheduler
EventScheduler.cs 是整套机制的调度中枢。其Run()方法(EventScheduler.cs)在每次触发时执行:
- 检查位置与主题是否就绪(
LaunchSequence.IsLocationReady()/IsThemeReady()); - 调用
SunriseSunsetService.GetSolarData()获取当天太阳数据; - 逐个显示器计算当前应显示的壁纸与下次切换时刻;
- 调用
ScriptManager.RunScripts()把本次事件参数传给 PowerShell 脚本; - 用
System.Timers.Timer精准调度下一次切换。
调度器通过订阅多个 Windows 系统事件保证切换的及时性(EventScheduler.cs):
DisplaySettingsChanged:显示器数量/分辨率变化时重建显示列表;PowerModeChanged:从睡眠/休眠恢复后立即刷新壁纸;SessionSwitch:用户解锁会话时刷新;TimeChanged:系统时间被手动修改时重新计算。
此外还有一个每 60 秒触发一次的后台定时器作为兜底(EventScheduler.cs),当"主定时器错过触发点"时由它补上,这也是 5.7.0 版本修复"PC 从睡眠恢复时壁纸不刷新"问题的关键机制(见 CHANGELOG.md)。
时间分段模型:四个时段
在正常地区(非极昼/极夜),一天被划分为四个时间分段(枚举DaySegment,见 SolarScheduler.cs):
| 分段 | 起止时间点 | 使用的图片列表 |
|---|---|---|
| Sunrise(日出) | Dawn → GoldenHourEnd | sunriseImageList |
| Day(白天) | GoldenHourEnd → GoldenHour | dayImageList |
| Sunset(日落) | GoldenHour → Dusk | sunsetImageList |
| Night(夜晚) | Dusk → 次日 Dawn | nightImageList |
这些时间点由SunriseSunsetService基于天文计算得出(SunriseSunset.cs):日出/日落采用地平线下 -0.833 度的标准定义,民用曙暮光(civil twilight)为 -6 度,黄金时刻(golden hour)为地平线上 +6 度。GetAllImageTimes()会把每个分段的图片按时间均匀铺开(SolarScheduler.cs),例如 5 张白天图片就均匀分布在 GoldenHourEnd 到 GoldenHour 之间。
极昼极夜与民用极昼的边界处理
在高纬度地区会出现太阳不落(极昼)或不开(极夜)的情况。SunriseSunsetService通过枚举PolarPeriod(SunriseSunset.cs)区分五种状态:None、PolarDay、PolarNight、CivilPolarDay、CivilPolarNight,并用SunCalcNet.SunCalc.GetSunPosition计算正午太阳高度角来判断(SunriseSunset.cs)。极昼时程序改为只在白天分段内按正午(solarNoon)对称铺图,让正午显示最亮的图片;极夜时则只走夜晚分段。这套边界行为有专门测试覆盖,例如 test/SunCalcTests.cs 验证了北极斯瓦尔巴群岛的CivilPolarDay场景(日出 01:55、日没次日 00:35、正午 12:56)。
外观模式:Automatic / Light / Dark
托盘菜单提供三种外观模式(枚举AppearanceMode,SolarScheduler.cs),对应设置项appearanceMode:
- Automatic(自动):白天用
dayImageList,夜晚用nightImageList; - Light(浅色):始终显示白天图片;
- Dark(深色):始终显示夜晚图片。
该值由托盘菜单写入并通过SolarScheduler.SetAppearanceMode()(SolarScheduler.cs)立即触发调度器重跑,无需重启。
主题系统:从内置 macOS 主题到自定义主题
README 的 Themes 一节介绍了三种主题来源:内置 macOS 主题、在线主题库(windd.info/themes 收录数百个主题)、自制主题。主题选择界面截图如下:
主题清单的加载
ThemeManager.Initialize()(ThemeManager.cs)启动时扫描themes目录下所有theme.json,结合内置主题清单(DefaultThemes.GetDefaultThemes(),数据来自嵌入资源 Properties/Resources.resx 中的 YAML)与 Windows 11 系统自带壁纸(DefaultThemes.cs 的Windows_11主题,直接复用%SystemRoot%\Web\Wallpaper\Windows\img*.jpg),构建出可选择的主题列表。首次运行且未选主题时,程序会默认聚焦到内置的Mojave_Desert主题(ThemeDialog.cs)。
theme.json:主题的核心数据结构
自制主题的本质,是提供一个符合规范的主题目录,内含一张theme.json描述文件与若干壁纸图片。仓库中 ThemeLoader.cs 的ThemeConfig类完整定义了 JSON 字段结构:
| 字段 | 类型 | 说明 |
|---|---|---|
themeId | string | 主题唯一标识,同时也是themes下的目录名 |
displayName | string | 主题显示名;缺省时用themeId替换下划线展示(ThemeManager.cs) |
imageFilename | string | 图片文件名模板,用*通配图片编号,如img*.jpg |
imageCredits | string | 图片版权署名(非内置主题在界面中展示) |
dayHighlight/nightHighlight | int? | 白天/夜晚的高光图片编号(用于预览与高亮) |
sunriseImageList | int[] | 日出分段图片编号列表 |
dayImageList | int[] | 白天分段图片编号列表(必填) |
sunsetImageList | int[] | 日落分段图片编号列表 |
nightImageList | int[] | 夜晚分段图片编号列表(必填) |
校验规则见 ThemeJsonValidator.cs:ValidateQuick要求imageFilename、dayImageList、nightImageList三者非空;ValidateFull进一步检查目录中确实存在与模板匹配的图片,且四个分段引用的每一个图片编号都能解析出实际文件(把imageFilename中的*替换成编号后File.Exists)。官方还提供.ddw Theme Creator在线可视化编辑器辅助生成主题包。
主题的导入、下载与删除
Select Theme窗口支持三种导入途径:
- 文件导入:通过"Import"按钮或直接把
.ddw、.zip、.json文件拖入窗口(ThemeDialog.cs 与拖放事件 ThemeDialog.cs); - ZIP 解压:
ThemeLoader.ExtractTheme()(ThemeLoader.cs)从压缩包中提取唯一的 JSON 为theme.json,再解出其余图片,任一环节失败都会触发RollbackInstall回滚删除整个主题目录; - 本地目录复制:
ThemeLoader.CopyLocalTheme()(ThemeLoader.cs)将本地theme.json及其匹配图片复制进themes/<themeId>。
对于未下载的在线主题,DownloadDialog会按 YAML 中记录的多个备用镜像 URL 依次下载 ZIP(DownloadDialog.cs),下载后同样走ExtractTheme流程,并在任务栏进度条上同步显示进度。删除主题时,若主题正被某个显示器使用则会被拒绝(ThemeDialogUtils.cs);"永久删除"会在RemoveTheme时直接清掉主题目录(ThemeManager.cs)。
主题随机切换(Shuffle)
README 虽未单独成节,但源码展示了完整的主题洗牌能力:托盘菜单可开启"收藏主题随机"或"全部主题随机",随机周期支持每小时、每 12 小时、每天、每 2 天、每周、每月六档(枚举ShufflePeriod,ThemeShuffler.cs)。ThemeShuffler.MaybeShuffleWallpaper()(ThemeShuffler.cs)在调度器每次运行时先判断"是否到洗牌时刻",再通过GetNextTheme从shuffleHistory历史记录中排除最近用过的主题以避免重复。该能力在 Windows 10/11 多显示器场景下分别作用于每块屏幕的主题。
调度系统:位置、日出日落与自定义时间
README 的 Schedule 一节说明"为 24 小时内的壁纸循环选择一套调度方案"。配置入口是Configure Schedule窗口(截图如下),其核心是位置模式选择:
三种位置模式
ScheduleDialog(ScheduleDialog.cs)会把选择结果写入settings.json的locationMode字段:
| locationMode | 模式 | 实现 |
|---|---|---|
0 | 手动输入城市名 | 调用 LocationIQ 搜索 API 将地名转换为经纬度(LocationManager.cs),转换成功后弹出确认框并显示推算出的日出日落时间 |
1 | Windows 位置服务 | 仅 UWP 版本可用,调用UwpLocation.UpdateGeoposition()获取系统定位;无权限时自动回退(LocationManager.cs) |
-1 | 手动指定日出/日落时间 | 用户直接填写sunriseTime、sunsetTime与sunriseSunsetDuration(日出/日落过渡分钟数) |
SunriseSunsetService.GetSolarData()(SunriseSunset.cs)会根据locationMode分流:手动模式直接构造太阳数据,其余模式用经纬度 +GeoTimeZone+TimeZoneConverter换算时区后,交给SunCalcNet做天文计算。
手动时间模式下的分段推导
当用户选择手动指定日出日落时,GetUserProvidedSolarData()(SunriseSunset.cs)会基于sunriseSunsetDuration推导出四个分段节点:设half = sunriseSunsetDuration * 30秒,则 Dawn = 日出 − half、GoldenHourEnd = 日出 + half、GoldenHour = 日落 − half、Dusk = 日落 + half。例如过渡时长设为 30 分钟、日出 6:00、日落 18:00,则日出分段为 5:30–6:30,日落分段为 17:30–18:30。
调度结果在源码中的体现
SolarScheduler.CalcNextUpdateTime()(SolarScheduler.cs)负责把"当前时刻"映射为"当前图片编号 + 下次更新时间":它先由GetDaySegmentData判断当前处于哪个分段,再把该分段的时长均分给对应图片列表,最后返回图片编号与下一次切换时刻。EventScheduler.HandleDisplayEvent(EventScheduler.cs)拿到编号后把imageFilename模板中的*替换为编号,拼出完整路径调用UwpDesktop.GetHelper().SetWallpaper()或SetLockScreen()。
脚本扩展:用 PowerShell 改变程序行为
README 的 Scripts 一节指出"用 PowerShell 脚本扩展 WinDynamicDesktop 行为"。这是项目的另一大特色:原本内置的"更改系统/应用主题色、自动亮度"等功能被移出核心后,全部以脚本形式提供(见 ConfigMigrator.cs 中 4.0 版本的迁移说明),用户也可以在社区脚本仓库分享自定义脚本。
脚本的发现与执行
ScriptManager.Initialize()(ScriptManager.cs)启动时创建scripts目录;执行阶段,RunScripts()(ScriptManager.cs)枚举该目录下所有*.ps1文件,逐个以隐藏窗口方式调用pwsh.exe(若存在)或powershell.exe(ScriptManager.cs),命令行为:
pwsh.exe -NoProfile -ExecutionPolicy Bypass -File "<脚本名>"脚本入参格式
每次调度器运行时,程序会把本次事件参数序列化为 JSON 写入脚本的标准输入(stdin)。ScriptArgs(ScriptManager.cs)定义了 JSON 字段:
{ "daySegment2": 0, "daySegment4": 3, "themeMode": 0, "imagePaths": ["C:/path/to/themes/Mojave_Desert/img1.jpg"] }| 字段 | 类型 | 含义 |
|---|---|---|
daySegment2 | int | 0 = 白天,1 = 夜晚(二分法分段) |
daySegment4 | int | 四分段编号:0 日出 / 1 白天 / 2 日落 / 3 夜晚 |
themeMode | int | 外观模式:0 自动 / 1 浅色 / 2 深色 |
imagePaths | string[] | 本次各显示器实际设置的壁纸路径 |
脚本通过读取 stdin 拿到该 JSON 后即可实现自定义逻辑(如同步 Windows 深色模式、调整显示器亮度等)。需要说明的是:脚本仅在参数变化或强制刷新时触发(lastArgs去重,ScriptManager.cs);若脚本退出码非 0 或输出了错误信息,程序会弹出"Script Error"警告(ScriptManager.cs)。脚本开关位于托盘菜单"More Options → Enable PowerShell scripts"。
配置与数据文件:settings.json 与目录布局
所有用户设置持久化在settings.json中。JsonConfig(JsonConfig.cs)负责加载与保存:属性变更后触发 1 秒防抖自动保存,写入时先落盘为settings.json.tmp再原子替换,避免配置损坏;若 JSON 已损坏,程序会询问是否重置为默认设置(JsonConfig.cs)。配置文件损坏恢复、旧版本字段迁移(如settings.conf→settings.json、themeName→activeThemes)由 ConfigMigrator.cs 完成。
AppConfig(JsonConfig.cs)中的核心字段一览:
| 分类 | 字段 | 说明 |
|---|---|---|
| 调度 | locationMode | 位置模式(0 手动位置 / 1 Windows 位置 / -1 手动时间) |
| 调度 | location | 用户输入的城市名 |
| 调度 | latitude/longitude | 经纬度 |
| 调度 | sunriseTime/sunsetTime | 手动模式的日出/日落时刻(格式T) |
| 调度 | sunriseSunsetDuration | 日出日落过渡时长(分钟) |
| 主题 | activeThemes | 各显示器使用的主题 ID 数组;首元素为null时按显示器分别指派 |
| 主题 | appearanceMode | 0 自动 / 1 浅色 / 2 深色 |
| 主题 | themeShuffleMode | 十位为随机范围(0 关 / 1 收藏 / 2 全部),个位为随机周期 |
| 主题 | favoriteThemes | 收藏主题 ID 列表 |
| 主题 | lockScreenTheme/lockScreenDisplayIndex | 锁屏主题与"锁屏跟随显示器"的索引(-1表示不跟随) |
| 通用 | language | 界面语言代码 |
| 通用 | autoUpdateCheck | 每周自动检查更新(桌面版) |
| 通用 | hideTrayIcon | 隐藏托盘图标 |
| 通用 | fullScreenPause | 全屏应用运行时暂停切换 |
| 通用 | enableScripts | 启用 PowerShell 脚本 |
| 通用 | debugLogging | 详细日志开关 |
托盘菜单"More Options → Edit configuration file / Reload configuration file"可直接编辑并热重载该文件(TrayMenu.cs)。
运行期数据目录布局为:themes/<themeId>/theme.json + 图片、scripts/*.ps1、settings.json、WinDynamicDesktop.log。多语言方面,仓库内置 50 余种语言的.mo翻译文件(见 src/locale/),支持从 POEditor 平台获取在线翻译(poeditor:前缀语言代码,见 Localization.cs)。
已知问题与使用限制
README 的 Known Issues 与 Limitations 章节如实披露了当前版本的边界,撰写时一并列出以免误导:
- 壁纸适配在多显示器下可能不被记忆(Microsoft Store 版本):与系统壁纸拉伸/平铺等适配设置相关;
- 壁纸偶尔卡住不更新:多见于长时间睡眠/休眠后,5.7.0 已通过双定时器兜底缓解(CHANGELOG.md);
- 无法在多个虚拟桌面(Virtual Desktops)上分别显示不同图片:Windows 虚拟桌面属于系统级特性,壁纸 API 无法按虚拟桌面区分;
- 锁屏更换受 Windows Spotlight 影响:当系统开启 Windows Spotlight 时无法设置锁屏图,需在"设置 → 个性化 → 锁屏"中切换为图片模式(ThemeDialogUtils.cs);
- Windows Insider 构建未经官方测试。
附:资源与声明要点
README 同时列出以下周边资源与声明,供读者按需查阅:
- 官方 Wiki(Get Help)收录了常见问题与自定义主题创建指南;
- 翻译协作基于 POEditor 平台进行;
.ddw Theme Creator是社区提供的在线主题创作工具;- 免责声明要点:内置壁纸图片版权归属 Apple 公司;输入位置时使用 LocationIQ API 换算经纬度(UWP 版授权后使用 Windows 位置 API,位置数据匿名且不会未经同意保存——该承诺同时写入 Chocolatey 包描述 scripts/windynamicdesktop.nuspec);应用图标来自 Roundicons(CC 3.0 BY 许可)。
结语
从 README 出发可以看到,WinDynamicDesktop 的技术魅力不止于"换壁纸"这一表象:SolarScheduler的太阳时角计算、ThemeJsonValidator的主题包校验、ScriptManager的 stdin JSON 协议、JsonConfig的原子化配置持久化,共同构成了一套可扩展、可验证的动态壁纸工程实践。无论你想直接使用它获得 macOS 般的桌面体验,还是想借theme.json格式与 PowerShell 脚本协议构建自己的壁纸/桌面自动化生态,本文梳理的源码路径都可以作为你的第一份地图。
说明:文中所有功能描述均以当前仓库(版本 5.7.0,见 WinDynamicDesktop.csproj 与 CHANGELOG.md)为准;涉及界面截图的两张图片分别对应 Select Theme 与 Configure Timing 窗口,取自 images/ 目录。
- 桌面应用
【免费下载链接】WinDynamicDesktop
Port of macOS Mojave Dynamic Desktop feature to Windows
相关推荐
3步轻松实现Windows动态桌面:让壁纸随日出日落自动切换
3步轻松实现Windows动态桌面:让壁纸随日出日落自动切换 你是否羡慕过macOS上那个能随一天时间变化而自动切换的炫酷动态桌面?现在,通过WinDynami
桌面应用WinDynamicDesktop动态桌面:让Windows桌面随日出日落自然变幻 🌅
WinDynamicDesktop动态桌面:让Windows桌面随日出日落自然变幻 🌅 想要体验macOS Mojave那令人惊艳的动态桌面效果吗?WinDy
桌面应用Windows动态桌面完整使用指南:轻松体验macOS Mojave壁纸特效
Windows动态桌面完整使用指南:轻松体验macOS Mojave壁纸特效 想要在Windows系统上体验macOS Mojave的动态桌面功能吗?WinDy
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考