feat(ui): 首次启动加密引导 + 真窗口图标 (.syso)

首次启动:
- 配置文件不存在时弹欢迎对话框:选「启用密码保护」或「稍后再说」
- 选启用直接进 setPasswordDialog,OK 时 store.SetPassword 触发首次保存
- io/fs.ErrNotExist 检测新分支
- modalCard 抽出 modalShell 内核以便 welcomeDialog 自定义 footer

真窗口图标:
- tools/gen_ico 从 PNG 生成多分辨率 .ico(7 尺寸:16~256)
- 提交 rsrc_windows.syso(rsrc 通过 goproxy.cn 生成),go build 自动链入
- tray_windows.go 改用嵌入资源 ID=1,失败 fallback IDI_APPLICATION
- README 更新完整的图标生成流程
This commit is contained in:
2026-06-12 10:07:13 +08:00
parent 727be3557a
commit 133091a32e
9 changed files with 317 additions and 35 deletions
+27 -20
View File
@@ -88,22 +88,26 @@ func (m *TrayManager) Stop() {
}
const (
wmUser uint32 = 0x0400
wmTrayCallback = wmUser + 1
wmTrayQuit = wmUser + 2
cmdQuitSentinel uint32 = 0xFFFF
nimAdd uint32 = 0x00000000
nimDelete uint32 = 0x00000002
nifMessage uint32 = 0x00000001
nifIcon uint32 = 0x00000002
nifTip uint32 = 0x00000004
wmCommand uint32 = 0x0111
wmRButtonUp uint32 = 0x0205
wmLButtonUp uint32 = 0x0202
mfString uint32 = 0x00000000
tpmLeftAlign uint32 = 0x0000
tpmRightButton uint32 = 0x0002
idiApplication uintptr = 32512
wmUser uint32 = 0x0400
wmTrayCallback = wmUser + 1
wmTrayQuit = wmUser + 2
cmdQuitSentinel uint32 = 0xFFFF
nimAdd uint32 = 0x00000000
nimDelete uint32 = 0x00000002
nifMessage uint32 = 0x00000001
nifIcon uint32 = 0x00000002
nifTip uint32 = 0x00000004
wmCommand uint32 = 0x0111
wmRButtonUp uint32 = 0x0205
wmLButtonUp uint32 = 0x0202
mfString uint32 = 0x00000000
tpmLeftAlign uint32 = 0x0000
tpmRightButton uint32 = 0x0002
// idiApplication is the stock placeholder; only used if loading
// our embedded icon resource fails. Our resource (assigned by
// `akavel/rsrc`) lives at id 1.
idiApplication uintptr = 32512
appIconID uintptr = 1
)
// trayClassName is unique enough to avoid clashing if another component
@@ -182,10 +186,13 @@ func (m *TrayManager) run(initErr chan<- error) {
m.menu = menu
m.mu.Unlock()
// Load a stock icon as the placeholder. Real apps ship an .ico
// resource and load it via LoadImageW; doing so requires a build-time
// .syso embed which is documented in internal/ui/assets/README.md.
hIcon, _, _ := procLoadIconW.Call(0, idiApplication)
// Load the application icon embedded in rsrc_windows.syso. Falls
// back to the stock application icon if the resource is missing
// (e.g. cross-compile that omitted the .syso).
hIcon, _, _ := procLoadIconW.Call(hinst, appIconID)
if hIcon == 0 {
hIcon, _, _ = procLoadIconW.Call(0, idiApplication)
}
nid := notifyIconData{
cbSize: uint32(unsafe.Sizeof(notifyIconData{})),