- 托盘:用 getlantern/systray 重写 internal/tray,支持显示/隐藏窗口与退出 - 图标:新增 pkg/icongen 工具,支持 png/jpg/gif/bmp/webp,输出 ico/png 多个尺寸 - 重命名:项目默认名改为「青梧映星」,wails.json/productname/companyname/copyright 同步更新 - 顶栏:新增顶部导航栏(主题切换、设置、用户),iconfont 自托管 fa-solid-900.woff2 - 主题:CSS 变量 + html[data-theme] 控制白昼/黑夜切换,同时调用 WindowSetDarkTheme/LightTheme - 底部:版权栏包含工作室、开发者与点击跳转客服链接 - 打包:wails build + exe 版本更新至 1.20 MB
126 lines
2.7 KiB
Go
126 lines
2.7 KiB
Go
// Package tray 系统托盘管理器,基于 getlantern/systray 跨平台实现。
|
||
// Windows 下图标需为 .ico 数据,macOS/Linux 下可为 .png/.jpg/.ico。
|
||
package tray
|
||
|
||
import (
|
||
"context"
|
||
"sync"
|
||
|
||
"github.com/getlantern/systray"
|
||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||
)
|
||
|
||
// Options 托盘初始化参数
|
||
type Options struct {
|
||
// Icon 托盘图标数据
|
||
Icon []byte
|
||
// Tooltip 悬停提示文本
|
||
Tooltip string
|
||
|
||
// OnShow 点击"显示窗口"时回调,为空时默认调用 runtime.WindowShow
|
||
OnShow func()
|
||
// OnHide 点击"隐藏窗口"时回调,为空时默认调用 runtime.WindowHide
|
||
OnHide func()
|
||
// OnQuit 点击"退出"时回调,为空时默认调用 runtime.Quit
|
||
OnQuit func()
|
||
}
|
||
|
||
// Manager 系统托盘管理器
|
||
type Manager struct {
|
||
mu sync.Mutex
|
||
opts Options
|
||
started bool
|
||
ready chan struct{}
|
||
quitItem *systray.MenuItem
|
||
}
|
||
|
||
// New 创建托盘管理器,Run 之前不会显示图标
|
||
func New(opts Options) *Manager {
|
||
return &Manager{
|
||
opts: opts,
|
||
ready: make(chan struct{}),
|
||
}
|
||
}
|
||
|
||
// Run 在后台 goroutine 中启动托盘事件循环(非阻塞)。
|
||
// ctx 用于窗口显示/隐藏/退出。
|
||
func (m *Manager) Run(ctx context.Context) {
|
||
m.mu.Lock()
|
||
if m.started {
|
||
m.mu.Unlock()
|
||
return
|
||
}
|
||
m.started = true
|
||
m.mu.Unlock()
|
||
|
||
go func() {
|
||
systray.Run(func() {
|
||
m.onReady(ctx)
|
||
close(m.ready)
|
||
}, func() {
|
||
m.mu.Lock()
|
||
m.started = false
|
||
m.mu.Unlock()
|
||
})
|
||
}()
|
||
}
|
||
|
||
// WaitReady 阻塞直到托盘初始化完成(可选)
|
||
func (m *Manager) WaitReady() {
|
||
<-m.ready
|
||
}
|
||
|
||
// Active 托盘是否已成功启动
|
||
func (m *Manager) Active() bool {
|
||
m.mu.Lock()
|
||
defer m.mu.Unlock()
|
||
return m.started
|
||
}
|
||
|
||
// Quit 移除托盘图标并停止托盘 goroutine
|
||
func (m *Manager) Quit() {
|
||
systray.Quit()
|
||
}
|
||
|
||
func (m *Manager) onReady(ctx context.Context) {
|
||
if len(m.opts.Icon) > 0 {
|
||
systray.SetIcon(m.opts.Icon)
|
||
}
|
||
if m.opts.Tooltip != "" {
|
||
systray.SetTooltip(m.opts.Tooltip)
|
||
}
|
||
|
||
show := systray.AddMenuItem("显示窗口", "Show the main window")
|
||
hide := systray.AddMenuItem("隐藏窗口", "Hide the main window")
|
||
systray.AddSeparator()
|
||
quitItem := systray.AddMenuItem("退出", "Quit the application")
|
||
m.quitItem = quitItem
|
||
|
||
m.handleMenuClicks(ctx, show, hide, quitItem)
|
||
}
|
||
|
||
func (m *Manager) handleMenuClicks(ctx context.Context, show, hide, quit *systray.MenuItem) {
|
||
for {
|
||
select {
|
||
case <-show.ClickedCh:
|
||
if m.opts.OnShow != nil {
|
||
m.opts.OnShow()
|
||
} else {
|
||
runtime.WindowShow(ctx)
|
||
}
|
||
case <-hide.ClickedCh:
|
||
if m.opts.OnHide != nil {
|
||
m.opts.OnHide()
|
||
} else {
|
||
runtime.WindowHide(ctx)
|
||
}
|
||
case <-quit.ClickedCh:
|
||
if m.opts.OnQuit != nil {
|
||
m.opts.OnQuit()
|
||
} else {
|
||
runtime.Quit(ctx)
|
||
}
|
||
}
|
||
}
|
||
}
|