Skip to content

fix: 修正窗口图标显示为默认程序图标、深色模式标题栏按钮不可见 - #389

Closed
Z2549 wants to merge 2 commits into
std-microblock:masterfrom
Z2549:fix/native-window-icon-and-dark-titlebar
Closed

Z2549 wants to merge 2 commits into
std-microblock:masterfrom
Z2549:fix/native-window-icon-and-dark-titlebar

Conversation

@Z2549

@Z2549 Z2549 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

问题

有两处原生标题栏显示不正确,而且分属两条不同的代码路径:

  1. 注入器窗口 —— 运行 breeze.exe 后弹出的那个置顶窗口
    • 标题栏图标显示成 Windows 的通用程序图标
    • 深色主题下右上角最小化/最大化/关闭三个按钮是黑的,与背景几乎同色,看不清
  2. 配置页窗口 —— breeze_ui.window.create 打开的设置界面,同样这两个问题

根因

图标

breeze-glfw/src/win32_window.c 注册窗口类时是按名字去 exe 资源里取图标的:

wc.hIcon = LoadImageW(GetModuleHandleW(NULL), L"GLFW_ICON", IMAGE_ICON, 0, 0,
                      LR_DEFAULTSIZE | LR_SHARED);
if (!wc.hIcon) {
  // No user-provided icon found, load default icon
  wc.hIcon = LoadImageW(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0,
                        LR_DEFAULTSIZE | LR_SHARED);
}

但仓库里没有任何名为 GLFW_ICON 的资源:src/inject/inject.rc 用的是 IDI_APP_ICON
(这个标识符在 WinUser.h 里并没有定义,rc.exe 会把它当字符串名处理)。
解析产物资源表可以看到组名确实是字符串:

/3  (ICON)/1..6/1033
/14 (GROUP_ICON)/"IDI_APP_ICON"/1033

名字对不上 ⇒ 永远走 IDI_APPLICATION 这条 fallback。另外 GLFW 也没有设置 wc.hIconSm,
小图标尺寸是错的。

三个按钮发黑

GLFW 不会开启沉浸式深色标题栏,DWM 按浅色渲染标题栏,于是深色主题下
最小化/最大化/关闭按钮和标题文字都画成深色,跟深色背景糊在一起。

改动

文件 改动
src/shell/script/binding_types_breeze_ui.cc breeze_ui::window::create_ex 建好窗口后补图标与深色标题栏(配置页窗口)
src/inject/inject.cc 同样的处理加到 StartInjectUI() 和 ShowCrashDialog()(注入器窗口)
xmake.lua shell 目标补 dwmapi 与 ico 的 utils.bin2c 规则;inject 目标补 dwmapi

具体做法:

  • 图标:从 resources/injector.ico 取帧 —— shell 侧逐帧解析 ICONDIR / RT_ICON blob
    后用 CreateIconFromResourceEx 造 HICON;inject 侧用 LoadImageW 按资源真名取。
    再用 WM_SETICON 设 ICON_SMALL(16) / ICON_BIG(32);HICON 做成进程内共享、不 DestroyIcon。
  • 深色标题栏:DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, ...),
    失败回退到属性 19(Win10 20H1 之前),是否用深色跟随系统 AppsUseLightTheme。

没有改 inject.rc:把资源名改成 GLFW_ICON 也能让 GLFW 自己找到图标,但字符串名资源可能
影响资源管理器里 exe 图标的选取,风险不确定;用 WM_SETICON 覆盖窗口图标是零风险的。

验证

肉眼:启动 breeze.exe,置顶窗口左上角应是 breeze 图标、深色下三个按钮清晰;配置页窗口同样。

不依赖肉眼的 PE 层面自检(在构建产物上实测):

  • breeze.exe 里 FindResource(RT_GROUP_ICON, "IDI_APP_ICON") 非空,"GLFW_ICON" 为空;
    LoadImageW 在 16/32 两个尺寸上都能取到 HICON —— 同时证明「修复有效」和「根因成立」
  • 相对未打补丁的产物,导入表唯一新增符号是 advapi32.dll!RegGetValueW(深色判断用),无符号消失
  • 宽字符串 "IDI_APP_ICON" 出现在 .rdata(代码字面量)和 .rsrc(资源名)两处

备注:关于本仓库 master 的 CI

master 的 CI 自 2026-06-04 起一直是红的,与本 PR 无关。根因是依赖版本漂移:
breeze-ui 的 xmake.lua 里 add_requires("glad") 没有钉版本,xmake-repo 现在会解析到
glad v2.0.8,而 glad 2.x 只提供 <glad/gl.h>,代码 include 的是 0.1.x 布局的 <glad/glad.h>,
于是 install breeze-nanosvg 会失败在:

fatal error: 'glad/glad.h' file not found

本地是在 deps/breeze-ui.lua 里给 breeze-nanosvg / breeze-nanovg / breeze-ui
钉回 glad 0.1.36(通过 add_patches 改 breeze-ui 的 add_requires,再补 add_deps)之后
才构建出产物的。这个构建修复没有包含在本 PR 里,以免把无关改动掺进来;
如果需要,我可以单独开一个 PR 处理。

- 窗口创建后按 ICO 内嵌帧设置 WM_SETICON(16/32),不再使用默认程序图标
- 深色模式下用 DwmSetWindowAttribute(DWMWA_USE_IMMERSIVE_DARK_MODE) 让右上角按钮可见
- xmake: 链接 dwmapi,并通过 utils.bin2c 把 resources/injector.ico 编入只读数据
运行 breeze.exe 弹出的那个注入器窗口,标题栏图标仍是 Windows 通用程序图标,
深色主题下右上角最小化/最大化/关闭三个按钮是黑的、跟背景糊在一起。

两个原因:
- GLFW 注册窗口类时按名字去 exe 资源里找 "GLFW_ICON"
  (breeze-glfw/src/win32_window.c),找不到就退回 IDI_APPLICATION;
  而 src/inject/inject.rc 里图标组的名字实际是 "IDI_APP_ICON",两边对不上。
- GLFW 不会开启沉浸式深色标题栏,DWM 按浅色渲染标题栏,
  于是深色主题下按钮和文字是黑的。

修法与 shell 侧(binding_types_breeze_ui.cc)保持一致:窗口建好后用
WM_SETICON 补上大小图标、用 DwmSetWindowAttribute 开沉浸式深色标题栏
(属性 20,失败回退 19)。StartInjectUI 和 ShowCrashDialog 两个窗口都处理。
xmake.lua 给 inject 目标补上 dwmapi。

shell.dll 那边的配置页窗口走 breeze_ui::window::create_ex,上一版已修,本次不动。
@std-microblock

std-microblock commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

感谢 @Z2549 的详细排查!根因分析(GLFW_ICON 名字对不上、GLFW 不开沉浸式深色标题栏)都很准确。

不过这两个问题本质上是 breeze-ui 的
ender_target 层面的,放在 shell / inject 各自打补丁会重复两份,所以改在 breeze-ui 里统一修了:

  • std-microblock/breeze-ui@60648cb:decorated 的窗口在 init() 时自动设置沉浸式深色标题栏(20,失败回退 19),并从链接 breeze-ui 的那个模块自身(breeze.exe / shell.dll)枚举第一个 RT_GROUP_ICON,按 DPI 加载大小图标后 WM_SETICON;同时响应 ImmersiveColorSet 切换主题、WM_DPICHANGED 重新取图标
  • b79bc54:shell.dll 里也嵌入同一份 injector.ico,并把 breeze-ui 升到上面的提交

这个 PR 就先关掉了,再次感谢!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants