diff --git a/v2/internal/platform/menu/windows.go b/v2/internal/platform/menu/windows.go new file mode 100644 index 000000000..68ebbcb49 --- /dev/null +++ b/v2/internal/platform/menu/windows.go @@ -0,0 +1,9 @@ +//go:build windows + +package menu + +import "github.com/wailsapp/wails/v2/internal/platform/win32" + +type Menu struct { + menu win32.HMENU +} diff --git a/v2/internal/platform/systray.go b/v2/internal/platform/systray.go index 2f047249c..ed8efcac3 100644 --- a/v2/internal/platform/systray.go +++ b/v2/internal/platform/systray.go @@ -15,9 +15,7 @@ type SysTray interface { Hide() error Run() error Close() - AppendMenu(label string, callback menu.Callback) - AppendMenuItem(item *menu.MenuItem) - AppendSeparator() + SetMenu(menu *menu.Menu) error SetIcons(lightModeIcon, darkModeIcon *options.SystemTrayIcon) error } diff --git a/v2/internal/platform/systray/menu.go b/v2/internal/platform/systray/menu.go index 5bfa00da0..22b58f084 100644 --- a/v2/internal/platform/systray/menu.go +++ b/v2/internal/platform/systray/menu.go @@ -6,10 +6,15 @@ import ( "github.com/wailsapp/wails/v2/pkg/menu" ) -func displayMenu(hwnd win32.HWND, menuItems []*menu.MenuItem) error { - popupMenu := win32.CreatePopupMenu() +type PopupMenu struct { + menu win32.HMENU + parent win32.HWND + menuMapping map[int]*menu.MenuItem +} - for index, item := range menuItems { +func buildMenu(parentMenu win32.HMENU, inputMenu *menu.Menu) (map[int]*menu.MenuItem, error) { + menuMapping := make(map[int]*menu.MenuItem) + for index, item := range inputMenu.Items { var ret bool itemID := win32.MenuItemMsgID + index flags := win32.MF_STRING @@ -26,28 +31,52 @@ func displayMenu(hwnd win32.HWND, menuItems []*menu.MenuItem) error { flags = flags | win32.MF_SEPARATOR } - ret = win32.AppendMenu(popupMenu, uintptr(flags), uintptr(itemID), item.Label) + menuMapping[itemID] = item + ret = win32.AppendMenu(parentMenu, uintptr(flags), uintptr(itemID), item.Label) if ret == false { - return errors.New("AppendMenu failed") + return nil, errors.New("AppendMenu failed") } } + return menuMapping, nil +} +func NewPopupMenu(parent win32.HWND, inputMenu *menu.Menu) (*PopupMenu, error) { + popupMenu := win32.CreatePopupMenu() + mappings, err := buildMenu(popupMenu, inputMenu) + if err != nil { + return nil, err + } + return &PopupMenu{ + parent: parent, + menu: popupMenu, + menuMapping: mappings, + }, nil +} + +func (p *PopupMenu) ShowAtCursor() error { x, y, ok := win32.GetCursorPos() if ok == false { return errors.New("GetCursorPos failed") } - if win32.SetForegroundWindow(hwnd) == false { + if win32.SetForegroundWindow(p.parent) == false { return errors.New("SetForegroundWindow failed") } - if win32.TrackPopupMenu(popupMenu, win32.TPM_LEFTALIGN, x, y-5, hwnd) == false { + if win32.TrackPopupMenu(p.menu, win32.TPM_LEFTALIGN, x, y-5, p.parent) == false { return errors.New("TrackPopupMenu failed") } - if win32.PostMessage(hwnd, win32.WM_NULL, 0, 0) == 0 { + if win32.PostMessage(p.parent, win32.WM_NULL, 0, 0) == 0 { return errors.New("PostMessage failed") } return nil } + +func (p *PopupMenu) ProcessCommand(cmdMsgID int) { + item := p.menuMapping[cmdMsgID] + if item != nil { + item.Click(&menu.CallbackData{MenuItem: item}) + } +} diff --git a/v2/internal/platform/systray/windows.go b/v2/internal/platform/systray/windows.go index 33882339a..ecedccd23 100644 --- a/v2/internal/platform/systray/windows.go +++ b/v2/internal/platform/systray/windows.go @@ -36,7 +36,7 @@ type Systray struct { darkModeIcon win32.HICON currentIcon win32.HICON - Menu []*menu.MenuItem + menu *PopupMenu quit chan struct{} icon *options.SystemTrayIcon @@ -136,19 +136,9 @@ func (p *Systray) HWND() win32.HWND { return p.hwnd } -// AppendMenu add menu item. -func (p *Systray) AppendMenu(label string, onclick menu.Callback) { - p.Menu = append(p.Menu, &menu.MenuItem{Type: menu.TextType, Label: label, Click: onclick}) -} - -// AppendMenuItem add menu item. -func (p *Systray) AppendMenuItem(item *menu.MenuItem) { - p.Menu = append(p.Menu, item) -} - -// AppendSeparator to the menu. -func (p *Systray) AppendSeparator() { - p.Menu = append(p.Menu, menu.Separator()) +func (p *Systray) SetMenu(popupMenu *menu.Menu) (err error) { + p.menu, err = NewPopupMenu(p.hwnd, popupMenu) + return } func (p *Systray) Stop() error { @@ -273,16 +263,16 @@ func (p *Systray) WinProc(hwnd win32.HWND, msg uint32, wparam, lparam uintptr) u case win32.NotifyIconMessageId: if lparam == win32.WM_LBUTTONUP { p.lclick() - if len(p.Menu) > 0 { - err := displayMenu(p.hwnd, p.Menu) + if p.menu != nil { + err := p.menu.ShowAtCursor() if err != nil { return 0 } } } else if lparam == win32.WM_RBUTTONUP { p.rclick() - if len(p.Menu) > 0 { - err := displayMenu(p.hwnd, p.Menu) + if p.menu != nil { + err := p.menu.ShowAtCursor() if err != nil { return 0 } @@ -301,11 +291,7 @@ func (p *Systray) WinProc(hwnd win32.HWND, msg uint32, wparam, lparam uintptr) u cmdMsgID := int(wparam & 0xffff) switch cmdMsgID { default: - if cmdMsgID >= win32.MenuItemMsgID && cmdMsgID < (win32.MenuItemMsgID+len(p.Menu)) { - itemIndex := cmdMsgID - win32.MenuItemMsgID - menuItem := p.Menu[itemIndex] - menuItem.Click(nil) - } + p.menu.ProcessCommand(cmdMsgID) } } diff --git a/v2/pkg/application/systray.go b/v2/pkg/application/systray.go index 58cfdd34a..ed7bc906b 100644 --- a/v2/pkg/application/systray.go +++ b/v2/pkg/application/systray.go @@ -14,6 +14,7 @@ type SystemTray struct { darkModeIcon *options.SystemTrayIcon tooltip string startHidden bool + menu *menu.Menu // The platform specific implementation impl platform.SysTray @@ -27,6 +28,7 @@ func newSystemTray(options *options.SystemTray) *SystemTray { darkModeIcon: options.DarkModeIcon, tooltip: options.Tooltip, startHidden: options.StartHidden, + menu: options.Menu, } } @@ -37,6 +39,7 @@ func (t *SystemTray) run() { if !t.startHidden { t.impl.Show() } + t.impl.SetMenu(t.menu) t.impl.Run() } @@ -44,9 +47,6 @@ func (t *SystemTray) SetTitle(title string) { t.title = title t.impl.SetTitle(title) } -func (t *SystemTray) AppendMenu(label string, callback menu.Callback) { - t.impl.AppendMenu(label, callback) -} func (t *SystemTray) Run() error { t.run() @@ -56,11 +56,3 @@ func (t *SystemTray) Run() error { func (t *SystemTray) Close() { t.impl.Close() } - -func (t *SystemTray) AppendSeperator() { - t.impl.AppendSeparator() -} - -func (t *SystemTray) AppendMenuItem(item *menu.MenuItem) { - t.impl.AppendMenuItem(item) -} diff --git a/v2/pkg/options/systemtray.go b/v2/pkg/options/systemtray.go index 51463c534..14639040e 100644 --- a/v2/pkg/options/systemtray.go +++ b/v2/pkg/options/systemtray.go @@ -1,5 +1,7 @@ package options +import "github.com/wailsapp/wails/v2/pkg/menu" + // SystemTray contains options for the system tray type SystemTray struct { LightModeIcon *SystemTrayIcon @@ -7,6 +9,7 @@ type SystemTray struct { Title string Tooltip string StartHidden bool + Menu *menu.Menu } // SystemTrayIcon represents a system tray icon