# libmonet 一个种子色生成一整套 Material 3 风格配色,并且知道**从桌面上去哪里取这个种子色和深浅色**。 纯 C++20 头文件库,没有第三方依赖。 给 [fcitx5-m3ui](https://git.oeo.one/justme/fcitx5-m3ui) 和 m3shot 共用,让它们的配色跟着桌面走, KDE Plasma 和 GNOME 都支持。 ## 用法 ```cpp #include monet::Scheme s = monet::fromDesktop(); // 种子色和深浅色都来自当前桌面 monet::Rgb surface = s.surfaceContainer; // 角色颜色: primary、onPrimary、surface、outline ... std::string css = monet::hex(s.primary); // "#00658F" bool dark = s.dark(); ``` 已经有种子色的话:`monet::generate(monet::Rgb{61, 174, 233}, monet::Mode::Dark)`。 ## 种子色和深浅色从哪来 探测由一串**来源(Source)**完成,按顺序问,每个值取第一个有答案的来源: | 来源 | 读什么 | 什么时候用 | |---|---|---| | `override` | 环境变量 `MONET_SEED=#RRGGBB`、`MONET_MODE=dark\|light` | 永远排第一,方便手动指定 | | `portal` | `org.freedesktop.portal.Settings`(用 `busctl` 或 `gdbus` 读) | 永远第二。**GNOME 47+ 和 KDE Plasma 6 都实现了它**,所以这是唯一跨桌面通用的来源 | | `kde` | `~/.config/kdeglobals` | 只在 KDE 桌面上 | | `gnome` | `gsettings` | 只在 GNOME 一类桌面上 | | `gtk` | `gtk-3.0/settings.ini`、`gtk-4.0/settings.ini` | 只能给出深浅色 | | `fallback` | 固定的粉色种子加深色 | **永远是最后一个,而且去不掉** | 两个细节: - 桌面专用来源只在对应桌面上才会被问。KDE 机器上残留的旧 `gsettings` 值不会盖过 KDE 自己的答案。 - **回退源永远存在**:来源列表为空、全部失败、没有桌面环境,结果都是合法的配色,不会返回空。 回退用的是两个工具在跟随桌面之前的老外观(粉色强调色加深色)。 程序有自己的 D-Bus 连接的话,可以加一个自己的来源放在最前面: ```cpp monet::Source mine{"mine", [](const monet::Context &) { monet::Appearance a; a.accent = monet::Rgb{...}; // 只填你知道的,其余留空,交给后面的来源 return a; }}; monet::Scheme s = monet::fromDesktop(monet::Context::system(), {mine}); ``` `monet::detect()` 的结果里带着 `accentSource` 和 `modeSource`,方便打日志,看颜色到底是谁给的。 `Context` 可以替换,测试里就是用假的 `Context` 模拟各种桌面。 ## 接入 CMake,固定到某个提交: ```cmake include(FetchContent) FetchContent_Declare(monet GIT_REPOSITORY https://git.oeo.one/justme/libmonet.git GIT_TAG <提交哈希>) FetchContent_MakeAvailable(monet) target_link_libraries(myapp PRIVATE monet::monet) ``` 不用 CMake 的话,把 `include/` 加进头文件搜索路径就行。 ## 配色是怎么算的 颜色在 OKLab/OKLCH 里处理,"色调(tone)"就是结果的 CIE L\*,和 Material 3 的 HCT 色调是同一个意思, 所以同一个色调不论什么色相,亮度和对比度都一样。角色和它们用的色调照搬 Material 3 的基线方案 (浅色 primary 40、深色 primary 80,容器 90/30,表面阶梯 100 到 90 等),三色相偏移 60°, 中性色几乎是灰色,错误色固定在红色。 **要说清楚的是**:这是 HCT 的轻量替代,没有实现 CAM16,所以**不是和 Material 官方库逐位一致**。 色相和色调是准的,色度的标度和官方不同。灰色种子会得到灰色方案,不会被硬染上颜色。 ## 测试 ``` cmake -S . -B build -G Ninja && ninja -C build && ./build/monet_tests ``` 测试不需要真实桌面,所有来源都用假的 `Context` 测。覆盖:颜色空间往返、色调精度和单调性、 300 个随机种子加深浅两种模式下每一对前景/背景的对比度(WCAG)、各种格式的解析(包括这台机器上 门户的真实输出和 `gdbus` 的输出格式)、各桌面下的来源顺序、回退、环境变量覆盖、外部程序的超时。 我还故意把代码改坏了 22 处来检查这些测试抓不抓得到,第一轮有几处漏掉的,补了测试。 **没有覆盖的**:GNOME 这条路只通过假环境测试过,没有在真实的 GNOME 机器上跑过。 ## 许可证 MIT