feat(ui): 系统托盘 + 关闭最小化到托盘
- 原生 win32 实现的 TrayManager:Shell_NotifyIcon + 私有 message-only 窗口承载 popup 菜单,专用 OS 线程跑 GetMessage 泵,避免引入 cgo 依赖。 - WindowSubclass 通过 SetWindowLongPtrW 子类化 Gio 主窗口,拦截 WM_CLOSE:minimize_to_tray=true 时吞掉消息只隐藏窗口;exit 路径下 放行让 Gio 正常关闭事件循环。 - Preferences 新增"最小化到托盘"复选框,切换后立即重装/卸载钩子, 不需要重启程序。 - 托盘菜单提供 Show / Hide / Exit;左键单击图标等同 Show;右键弹菜单。 - 非 Windows 平台所有相关 API 退化为 ErrUnsupported / no-op stub。
This commit is contained in:
@@ -13,8 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// preferencesDialog edits the persistent UI prefs: UI language, theme,
|
||||
// and auto-lock timeout. Minimize-to-tray lives in its own bucket and
|
||||
// will appear here later.
|
||||
// auto-lock timeout, and minimize-to-tray behaviour.
|
||||
type preferencesDialog struct {
|
||||
lang string
|
||||
theme themeMode
|
||||
@@ -35,6 +34,10 @@ type preferencesDialog struct {
|
||||
// input on that, the store does.
|
||||
autoLockEd widget.Editor
|
||||
|
||||
// Minimize-to-tray: when on, the X button hides the window to the
|
||||
// system tray instead of exiting. Tray icon stays visible either way.
|
||||
minToTray widget.Bool
|
||||
|
||||
okBt widget.Clickable
|
||||
cancelBt widget.Clickable
|
||||
}
|
||||
@@ -46,6 +49,7 @@ type preferencesResult struct {
|
||||
language string
|
||||
theme themeMode
|
||||
autoLockMinutes int
|
||||
minimizeToTray bool
|
||||
}
|
||||
|
||||
// supportedLanguages is the closed set the prefs dialog exposes. Keep
|
||||
@@ -59,7 +63,7 @@ var supportedLanguages = []struct {
|
||||
{"de", "Deutsch"},
|
||||
}
|
||||
|
||||
func newPreferencesDialog(currentLang string, currentTheme themeMode, currentAutoLock int) *preferencesDialog {
|
||||
func newPreferencesDialog(currentLang string, currentTheme themeMode, currentAutoLock int, currentMinToTray bool) *preferencesDialog {
|
||||
if currentLang == "" {
|
||||
currentLang = "en"
|
||||
}
|
||||
@@ -69,6 +73,7 @@ func newPreferencesDialog(currentLang string, currentTheme themeMode, currentAut
|
||||
d := &preferencesDialog{lang: currentLang, theme: currentTheme}
|
||||
d.autoLockEd.SingleLine = true
|
||||
d.autoLockEd.SetText(strconv.Itoa(currentAutoLock))
|
||||
d.minToTray.Value = currentMinToTray
|
||||
return d
|
||||
}
|
||||
|
||||
@@ -88,7 +93,12 @@ func (d *preferencesDialog) Layout(
|
||||
if err != nil || mins < 0 {
|
||||
mins = 0
|
||||
}
|
||||
onDone(preferencesResult{language: d.lang, theme: d.theme, autoLockMinutes: mins})
|
||||
onDone(preferencesResult{
|
||||
language: d.lang,
|
||||
theme: d.theme,
|
||||
autoLockMinutes: mins,
|
||||
minimizeToTray: d.minToTray.Value,
|
||||
})
|
||||
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||
}
|
||||
|
||||
@@ -150,6 +160,10 @@ func (d *preferencesDialog) Layout(
|
||||
layout.Rigid(labeledEditor(th, i18n.T("label_auto_lock_minutes"), &d.autoLockEd, "")),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout),
|
||||
layout.Rigid(material.Caption(th, i18n.T("hint_auto_lock_disabled")).Layout),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout),
|
||||
layout.Rigid(material.CheckBox(th, &d.minToTray, i18n.T("label_minimize_to_tray")).Layout),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout),
|
||||
layout.Rigid(material.Caption(th, i18n.T("hint_minimize_to_tray")).Layout),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user