feat(systray): wire tray window attachment
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run

This commit is contained in:
Virgil 2026-04-02 19:16:59 +00:00
parent 856bb89022
commit 3d7998a9ca
3 changed files with 93 additions and 12 deletions

View file

@ -15,7 +15,7 @@ func NewWailsPlatform(app *application.App) *WailsPlatform {
}
func (wp *WailsPlatform) NewTray() PlatformTray {
return &wailsTray{tray: wp.app.SystemTray.New(), app: wp.app}
return &wailsTray{tray: wp.app.SystemTray.New()}
}
func (wp *WailsPlatform) NewMenu() PlatformMenu {
@ -24,7 +24,6 @@ func (wp *WailsPlatform) NewMenu() PlatformMenu {
type wailsTray struct {
tray *application.SystemTray
app *application.App
}
func (wt *wailsTray) SetIcon(data []byte) { wt.tray.SetIcon(data) }
@ -39,8 +38,19 @@ func (wt *wailsTray) SetMenu(menu PlatformMenu) {
}
func (wt *wailsTray) AttachWindow(w WindowHandle) {
// Wails systray AttachWindow expects an application.Window interface.
// The caller must pass an appropriate wrapper.
if wt.tray == nil {
return
}
window, ok := w.(interface {
Show()
Hide()
Focus()
IsVisible() bool
})
if !ok {
return
}
wt.tray.AttachWindow(window)
}
// wailsTrayMenu wraps *application.Menu for the PlatformMenu interface.

34
pkg/systray/wails_test.go Normal file
View file

@ -0,0 +1,34 @@
package systray
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wailsapp/wails/v3/pkg/application"
)
func TestWailsTray_AttachWindow_Good(t *testing.T) {
app := application.NewApp()
platform := NewWailsPlatform(app)
tray, ok := platform.NewTray().(*wailsTray)
require.True(t, ok)
window := app.Window.NewWithOptions(application.WebviewWindowOptions{
Name: "panel",
Title: "Panel",
Hidden: true,
})
tray.AttachWindow(window)
assert.False(t, window.IsVisible())
tray.tray.Click()
assert.True(t, window.IsVisible())
assert.True(t, window.IsFocused())
tray.tray.Click()
assert.False(t, window.IsVisible())
}

View file

@ -258,11 +258,18 @@ func (mi *MenuItem) OnClick(fn func(ctx *Context)) *MenuItem {
// SystemTray models a tray icon.
type SystemTray struct {
icon []byte
templateIcon []byte
tooltip string
label string
menu *Menu
icon []byte
templateIcon []byte
tooltip string
label string
menu *Menu
attachedWindow interface {
Show()
Hide()
Focus()
IsVisible() bool
}
onClick func()
}
func (st *SystemTray) SetIcon(icon []byte) *SystemTray {
@ -288,9 +295,39 @@ func (st *SystemTray) SetMenu(menu *Menu) *SystemTray {
return st
}
func (st *SystemTray) Show() {}
func (st *SystemTray) Hide() {}
func (st *SystemTray) OnClick(callback func()) *SystemTray { return st }
func (st *SystemTray) Show() {}
func (st *SystemTray) Hide() {}
func (st *SystemTray) OnClick(callback func()) *SystemTray {
st.onClick = callback
return st
}
func (st *SystemTray) AttachWindow(window interface {
Show()
Hide()
Focus()
IsVisible() bool
}) *SystemTray {
st.attachedWindow = window
st.OnClick(func() {
if st.attachedWindow == nil {
return
}
if st.attachedWindow.IsVisible() {
st.attachedWindow.Hide()
return
}
st.attachedWindow.Show()
st.attachedWindow.Focus()
})
return st
}
func (st *SystemTray) Click() {
if st.onClick != nil {
st.onClick()
}
}
// SystemTrayManager creates trays.
type SystemTrayManager struct {