diff --git a/v2/examples/systray/go.mod b/v2/examples/systray/go.mod index 83e7b2d26..0ba256649 100644 --- a/v2/examples/systray/go.mod +++ b/v2/examples/systray/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/uuid v1.1.2 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect - github.com/labstack/echo/v4 v4.7.2 // indirect + github.com/labstack/echo/v4 v4.9.0 // indirect github.com/labstack/gommon v0.3.1 // indirect github.com/leaanthony/go-ansi-parser v1.0.1 // indirect github.com/leaanthony/gosod v1.0.3 // indirect @@ -27,8 +27,8 @@ require ( golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect - golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect golang.org/x/text v0.3.7 // indirect ) diff --git a/v2/examples/systray/go.sum b/v2/examples/systray/go.sum index 96ea787e0..f37843098 100644 --- a/v2/examples/systray/go.sum +++ b/v2/examples/systray/go.sum @@ -11,8 +11,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= -github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= -github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= +github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= @@ -56,8 +56,8 @@ golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9 golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -66,8 +66,8 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/v2/examples/systray/main.go b/v2/examples/systray/main.go index 468d2be72..d675ec4d1 100644 --- a/v2/examples/systray/main.go +++ b/v2/examples/systray/main.go @@ -9,6 +9,7 @@ import ( "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/windows" "github.com/wailsapp/wails/v2/pkg/runtime" + "time" ) //go:embed all:frontend/dist @@ -44,7 +45,22 @@ func main() { // Create a systray for the application // Currently we only support PNG for icons - systray := mainApp.NewSystemTray(&options.SystemTray{ + var systray *application.SystemTray + var showWindow = func() { + // Show the window + // In a future version of this API, it will be possible to + // create windows programmatically and be able to show/hide + // them from the systray with something like: + // + // myWindow := mainApp.NewWindow(...) + // mainApp.NewSystemTray(&options.SystemTray{ + // OnLeftClick: func() { + // myWindow.SetVisibility(!myWindow.IsVisible()) + // } + // }) + runtime.Show(runtimeContext) + } + systray = mainApp.NewSystemTray(&options.SystemTray{ // This is the icon used when the system in using light mode LightModeIcon: &options.SystemTrayIcon{ Data: lightModeIcon, @@ -53,20 +69,21 @@ func main() { DarkModeIcon: &options.SystemTrayIcon{ Data: darkModeIcon, }, - Tooltip: "Systray Example", - OnLeftClick: func() { - // Show the window - // In a future version of this API, it will be possible to - // create windows programmatically and be able to show/hide - // them from the systray with something like: - // - // myWindow := mainApp.NewWindow(...) - // mainApp.NewSystemTray(&options.SystemTray{ - // OnLeftClick: func() { - // myWindow.SetVisibility(!myWindow.IsVisible()) - // } - // }) - runtime.Show(runtimeContext) + Tooltip: "Systray Example", + OnLeftClick: showWindow, + OnMenuClose: func() { + // Add the left click call after 500ms + // We do this because the left click fires right + // after the menu closes, and we don't want to show + // the window on menu close. + go func() { + time.Sleep(500 * time.Millisecond) + systray.OnLeftClick(showWindow) + }() + }, + OnMenuOpen: func() { + // Remove the left click callback + systray.OnLeftClick(func() {}) }, }) diff --git a/v2/internal/platform/systray.go b/v2/internal/platform/systray.go index 611d74c48..af79f427f 100644 --- a/v2/internal/platform/systray.go +++ b/v2/internal/platform/systray.go @@ -20,6 +20,10 @@ type SysTray interface { Update() error OnLeftClick(func()) OnRightClick(func()) + OnLeftDoubleClick(func()) + OnRightDoubleClick(func()) + OnMenuClose(func()) + OnMenuOpen(func()) } func NewSysTray() SysTray { diff --git a/v2/internal/platform/systray/menu.go b/v2/internal/platform/systray/menu.go index cb41002a0..7035e4f09 100644 --- a/v2/internal/platform/systray/menu.go +++ b/v2/internal/platform/systray/menu.go @@ -44,6 +44,8 @@ type PopupMenu struct { radioGroups map[*menu.MenuItem][]*RadioGroup menuData *menu.Menu currentMenuID int + onMenuClose func() + onMenuOpen func() } func (p *PopupMenu) buildMenu(parentMenu win32.PopupMenu, inputMenu *menu.Menu) error { @@ -153,10 +155,18 @@ func (p *PopupMenu) ShowAtCursor() error { return errors.New("SetForegroundWindow failed") } + if p.onMenuOpen != nil { + p.onMenuOpen() + } + if p.menu.Track(win32.TPM_LEFTALIGN, x, y-5, p.parent) == false { return errors.New("TrackPopupMenu failed") } + if p.onMenuClose != nil { + p.onMenuClose() + } + if win32.PostMessage(p.parent, win32.WM_NULL, 0, 0) == 0 { return errors.New("PostMessage failed") } @@ -200,3 +210,11 @@ func (p *PopupMenu) updateRadioGroup(item *menu.MenuItem) { p.menu.CheckRadio(startID, endID, thisMenuID) } } + +func (p *PopupMenu) OnMenuOpen(fn func()) { + p.onMenuOpen = fn +} + +func (p *PopupMenu) OnMenuClose(fn func()) { + p.onMenuClose = fn +} diff --git a/v2/internal/platform/systray/windows.go b/v2/internal/platform/systray/windows.go index 3e2a1a873..6ab738771 100644 --- a/v2/internal/platform/systray/windows.go +++ b/v2/internal/platform/systray/windows.go @@ -25,12 +25,16 @@ var ( ) type Systray struct { - id uint32 - mhwnd win32.HWND // main window handle - hwnd win32.HWND - hinst win32.HINSTANCE - lclick func() - rclick func() + id uint32 + mhwnd win32.HWND // main window handle + hwnd win32.HWND + hinst win32.HINSTANCE + lclick func() + rclick func() + ldblclick func() + rdblclick func() + onMenuClose func() + onMenuOpen func() appIcon win32.HICON lightModeIcon win32.HICON @@ -154,6 +158,8 @@ func (p *Systray) HWND() win32.HWND { func (p *Systray) SetMenu(popupMenu *menu.Menu) (err error) { p.menu, err = NewPopupMenu(p.hwnd, popupMenu) + p.menu.OnMenuClose(p.onMenuClose) + p.menu.OnMenuOpen(p.onMenuOpen) return } @@ -178,6 +184,30 @@ func (p *Systray) OnRightClick(fn func()) { } } +func (p *Systray) OnLeftDoubleClick(fn func()) { + if fn != nil { + p.ldblclick = fn + } +} + +func (p *Systray) OnRightDoubleClick(fn func()) { + if fn != nil { + p.rdblclick = fn + } +} + +func (p *Systray) OnMenuClose(fn func()) { + if fn != nil { + p.onMenuClose = fn + } +} + +func (p *Systray) OnMenuOpen(fn func()) { + if fn != nil { + p.onMenuOpen = fn + } +} + func (p *Systray) SetTooltip(tooltip string) error { nid := p.newNotifyIconData() nid.UFlags = win32.NIF_TIP @@ -277,14 +307,27 @@ func (p *Systray) setIcon(hicon win32.HICON) error { func (p *Systray) WinProc(hwnd win32.HWND, msg uint32, wparam, lparam uintptr) uintptr { switch msg { case win32.NotifyIconMessageId: - if lparam == win32.WM_LBUTTONUP { + switch lparam { + case win32.WM_LBUTTONUP: if p.lclick != nil { + println("left click") p.lclick() } - } else if lparam == win32.WM_RBUTTONUP { + case win32.WM_RBUTTONUP: if p.rclick != nil { + println("right click") p.rclick() } + case win32.WM_LBUTTONDBLCLK: + if p.ldblclick != nil { + p.ldblclick() + } + case win32.WM_RBUTTONDBLCLK: + if p.rdblclick != nil { + p.rdblclick() + } + default: + //println(win32.WMMessageToString(lparam)) } case win32.WM_SETTINGCHANGE: settingChanged := win32.UTF16PtrToString(lparam) @@ -301,7 +344,9 @@ func (p *Systray) WinProc(hwnd win32.HWND, msg uint32, wparam, lparam uintptr) u default: p.menu.ProcessCommand(cmdMsgID) } - + default: + //msg := int(wparam & 0xffff) + //println(win32.WMMessageToString(uintptr(msg))) } result, _, _ := DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam) diff --git a/v2/internal/platform/win32/consts.go b/v2/internal/platform/win32/consts.go index 33eac939f..295a9c8db 100644 --- a/v2/internal/platform/win32/consts.go +++ b/v2/internal/platform/win32/consts.go @@ -1,6 +1,7 @@ package win32 import ( + "fmt" "github.com/wailsapp/wails/v2/internal/system/operatingsystem" "golang.org/x/sys/windows" "syscall" @@ -120,19 +121,209 @@ type ATOM uint16 type MenuID uint16 const ( - WM_ACTIVATE = 0x0006 - WM_ACTIVATEAPP = 0x001C - WM_LBUTTONUP = 0x0202 - WM_LBUTTONDBLCLK = 0x0203 - WM_RBUTTONUP = 0x0205 - WM_USER = 0x0400 - WM_TRAYICON = WM_USER + 69 - WM_SETTINGCHANGE = 0x001A - WM_KEYDOWN = 256 - WM_KEYUP = 257 - WM_SYSKEYDOWN = 260 - WM_SYSKEYUP = 261 - WM_MENUCHAR = 288 + WM_APP = 32768 + WM_ACTIVATE = 6 + WM_ACTIVATEAPP = 28 + WM_AFXFIRST = 864 + WM_AFXLAST = 895 + WM_ASKCBFORMATNAME = 780 + WM_CANCELJOURNAL = 75 + WM_CANCELMODE = 31 + WM_CAPTURECHANGED = 533 + WM_CHANGECBCHAIN = 781 + WM_CHAR = 258 + WM_CHARTOITEM = 47 + WM_CHILDACTIVATE = 34 + WM_CLEAR = 771 + WM_CLOSE = 16 + WM_COMMAND = 273 + WM_COMMNOTIFY = 68 /* OBSOLETE */ + WM_COMPACTING = 65 + WM_COMPAREITEM = 57 + WM_CONTEXTMENU = 123 + WM_COPY = 769 + WM_COPYDATA = 74 + WM_CREATE = 1 + WM_CTLCOLORBTN = 309 + WM_CTLCOLORDLG = 310 + WM_CTLCOLOREDIT = 307 + WM_CTLCOLORLISTBOX = 308 + WM_CTLCOLORMSGBOX = 306 + WM_CTLCOLORSCROLLBAR = 311 + WM_CTLCOLORSTATIC = 312 + WM_CUT = 768 + WM_DEADCHAR = 259 + WM_DELETEITEM = 45 + WM_DESTROY = 2 + WM_DESTROYCLIPBOARD = 775 + WM_DEVICECHANGE = 537 + WM_DEVMODECHANGE = 27 + WM_DISPLAYCHANGE = 126 + WM_DRAWCLIPBOARD = 776 + WM_DRAWITEM = 43 + WM_DROPFILES = 563 + WM_ENABLE = 10 + WM_ENDSESSION = 22 + WM_ENTERIDLE = 289 + WM_ENTERMENULOOP = 529 + WM_ENTERSIZEMOVE = 561 + WM_ERASEBKGND = 20 + WM_EXITMENULOOP = 530 + WM_EXITSIZEMOVE = 562 + WM_FONTCHANGE = 29 + WM_GETDLGCODE = 135 + WM_GETFONT = 49 + WM_GETHOTKEY = 51 + WM_GETICON = 127 + WM_GETMINMAXINFO = 36 + WM_GETTEXT = 13 + WM_GETTEXTLENGTH = 14 + WM_HANDHELDFIRST = 856 + WM_HANDHELDLAST = 863 + WM_HELP = 83 + WM_HOTKEY = 786 + WM_HSCROLL = 276 + WM_HSCROLLCLIPBOARD = 782 + WM_ICONERASEBKGND = 39 + WM_INITDIALOG = 272 + WM_INITMENU = 278 + WM_INITMENUPOPUP = 279 + WM_INPUT = 0x00FF + WM_INPUTLANGCHANGE = 81 + WM_INPUTLANGCHANGEREQUEST = 80 + WM_KEYDOWN = 256 + WM_KEYUP = 257 + WM_KILLFOCUS = 8 + WM_MDIACTIVATE = 546 + WM_MDICASCADE = 551 + WM_MDICREATE = 544 + WM_MDIDESTROY = 545 + WM_MDIGETACTIVE = 553 + WM_MDIICONARRANGE = 552 + WM_MDIMAXIMIZE = 549 + WM_MDINEXT = 548 + WM_MDIREFRESHMENU = 564 + WM_MDIRESTORE = 547 + WM_MDISETMENU = 560 + WM_MDITILE = 550 + WM_MEASUREITEM = 44 + WM_GETOBJECT = 0x003D + WM_CHANGEUISTATE = 0x0127 + WM_UPDATEUISTATE = 0x0128 + WM_QUERYUISTATE = 0x0129 + WM_UNINITMENUPOPUP = 0x0125 + WM_MENURBUTTONUP = 290 + WM_MENUCOMMAND = 0x0126 + WM_MENUGETOBJECT = 0x0124 + WM_MENUDRAG = 0x0123 + WM_APPCOMMAND = 0x0319 + WM_MENUCHAR = 288 + WM_MENUSELECT = 287 + WM_MOVE = 3 + WM_MOVING = 534 + WM_NCACTIVATE = 134 + WM_NCCALCSIZE = 131 + WM_NCCREATE = 129 + WM_NCDESTROY = 130 + WM_NCHITTEST = 132 + WM_NCLBUTTONDBLCLK = 163 + WM_NCLBUTTONDOWN = 161 + WM_NCLBUTTONUP = 162 + WM_NCMBUTTONDBLCLK = 169 + WM_NCMBUTTONDOWN = 167 + WM_NCMBUTTONUP = 168 + WM_NCXBUTTONDOWN = 171 + WM_NCXBUTTONUP = 172 + WM_NCXBUTTONDBLCLK = 173 + WM_NCMOUSEHOVER = 0x02A0 + WM_NCMOUSELEAVE = 0x02A2 + WM_NCMOUSEMOVE = 160 + WM_NCPAINT = 133 + WM_NCRBUTTONDBLCLK = 166 + WM_NCRBUTTONDOWN = 164 + WM_NCRBUTTONUP = 165 + WM_NEXTDLGCTL = 40 + WM_NEXTMENU = 531 + WM_NOTIFY = 78 + WM_NOTIFYFORMAT = 85 + WM_NULL = 0 + WM_PAINT = 15 + WM_PAINTCLIPBOARD = 777 + WM_PAINTICON = 38 + WM_PALETTECHANGED = 785 + WM_PALETTEISCHANGING = 784 + WM_PARENTNOTIFY = 528 + WM_PASTE = 770 + WM_PENWINFIRST = 896 + WM_PENWINLAST = 911 + WM_POWER = 72 + WM_PRINT = 791 + WM_PRINTCLIENT = 792 + WM_QUERYDRAGICON = 55 + WM_QUERYENDSESSION = 17 + WM_QUERYNEWPALETTE = 783 + WM_QUERYOPEN = 19 + WM_QUEUESYNC = 35 + WM_QUIT = 18 + WM_RENDERALLFORMATS = 774 + WM_RENDERFORMAT = 773 + WM_SETCURSOR = 32 + WM_SETFOCUS = 7 + WM_SETFONT = 48 + WM_SETHOTKEY = 50 + WM_SETICON = 128 + WM_SETREDRAW = 11 + WM_SETTEXT = 12 + WM_SETTINGCHANGE = 26 + WM_SHOWWINDOW = 24 + WM_SIZE = 5 + WM_SIZECLIPBOARD = 779 + WM_SIZING = 532 + WM_SPOOLERSTATUS = 42 + WM_STYLECHANGED = 125 + WM_STYLECHANGING = 124 + WM_SYSCHAR = 262 + WM_SYSCOLORCHANGE = 21 + WM_SYSCOMMAND = 274 + WM_SYSDEADCHAR = 263 + WM_SYSKEYDOWN = 260 + WM_SYSKEYUP = 261 + WM_TCARD = 82 + WM_THEMECHANGED = 794 + WM_TIMECHANGE = 30 + WM_TIMER = 275 + WM_UNDO = 772 + WM_USER = 1024 + WM_USERCHANGED = 84 + WM_VKEYTOITEM = 46 + WM_VSCROLL = 277 + WM_VSCROLLCLIPBOARD = 778 + WM_WINDOWPOSCHANGED = 71 + WM_WINDOWPOSCHANGING = 70 + WM_WININICHANGE = 26 + WM_KEYFIRST = 256 + WM_KEYLAST = 264 + WM_SYNCPAINT = 136 + WM_MOUSEACTIVATE = 33 + WM_MOUSEMOVE = 512 + WM_LBUTTONDOWN = 513 + WM_LBUTTONUP = 514 + WM_LBUTTONDBLCLK = 515 + WM_RBUTTONDOWN = 516 + WM_RBUTTONUP = 517 + WM_RBUTTONDBLCLK = 518 + WM_MBUTTONDOWN = 519 + WM_MBUTTONUP = 520 + WM_MBUTTONDBLCLK = 521 + WM_MOUSEWHEEL = 522 + WM_MOUSEFIRST = 512 + WM_XBUTTONDOWN = 523 + WM_XBUTTONUP = 524 + WM_XBUTTONDBLCLK = 525 + WM_MOUSELAST = 525 + WM_MOUSEHOVER = 0x2A1 + WM_MOUSELEAVE = 0x2A3 + WM_CLIPBOARDUPDATE = 0x031D WS_EX_APPWINDOW = 0x00040000 WS_OVERLAPPEDWINDOW = 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000 @@ -179,9 +370,6 @@ const ( NOTIFYICON_VERSION = 4 IDI_APPLICATION = 32512 - WM_APP = 32768 - WM_COMMAND = 273 - WM_SYSCOMMAND = 274 MenuItemMsgID = WM_APP + 1024 NotifyIconMessageId = WM_APP + iota @@ -198,12 +386,417 @@ const ( MF_BYCOMMAND = 0x00000000 TPM_LEFTALIGN = 0x0000 - WM_NULL = 0 CS_VREDRAW = 0x0001 CS_HREDRAW = 0x0002 ) +func WMMessageToString(msg uintptr) string { + // Convert windows message to string + switch msg { + case WM_APP: + return "WM_APP" + case WM_ACTIVATE: + return "WM_ACTIVATE" + case WM_ACTIVATEAPP: + return "WM_ACTIVATEAPP" + case WM_AFXFIRST: + return "WM_AFXFIRST" + case WM_AFXLAST: + return "WM_AFXLAST" + case WM_ASKCBFORMATNAME: + return "WM_ASKCBFORMATNAME" + case WM_CANCELJOURNAL: + return "WM_CANCELJOURNAL" + case WM_CANCELMODE: + return "WM_CANCELMODE" + case WM_CAPTURECHANGED: + return "WM_CAPTURECHANGED" + case WM_CHANGECBCHAIN: + return "WM_CHANGECBCHAIN" + case WM_CHAR: + return "WM_CHAR" + case WM_CHARTOITEM: + return "WM_CHARTOITEM" + case WM_CHILDACTIVATE: + return "WM_CHILDACTIVATE" + case WM_CLEAR: + return "WM_CLEAR" + case WM_CLOSE: + return "WM_CLOSE" + case WM_COMMAND: + return "WM_COMMAND" + case WM_COMMNOTIFY /* OBSOLETE */ : + return "WM_COMMNOTIFY" + case WM_COMPACTING: + return "WM_COMPACTING" + case WM_COMPAREITEM: + return "WM_COMPAREITEM" + case WM_CONTEXTMENU: + return "WM_CONTEXTMENU" + case WM_COPY: + return "WM_COPY" + case WM_COPYDATA: + return "WM_COPYDATA" + case WM_CREATE: + return "WM_CREATE" + case WM_CTLCOLORBTN: + return "WM_CTLCOLORBTN" + case WM_CTLCOLORDLG: + return "WM_CTLCOLORDLG" + case WM_CTLCOLOREDIT: + return "WM_CTLCOLOREDIT" + case WM_CTLCOLORLISTBOX: + return "WM_CTLCOLORLISTBOX" + case WM_CTLCOLORMSGBOX: + return "WM_CTLCOLORMSGBOX" + case WM_CTLCOLORSCROLLBAR: + return "WM_CTLCOLORSCROLLBAR" + case WM_CTLCOLORSTATIC: + return "WM_CTLCOLORSTATIC" + case WM_CUT: + return "WM_CUT" + case WM_DEADCHAR: + return "WM_DEADCHAR" + case WM_DELETEITEM: + return "WM_DELETEITEM" + case WM_DESTROY: + return "WM_DESTROY" + case WM_DESTROYCLIPBOARD: + return "WM_DESTROYCLIPBOARD" + case WM_DEVICECHANGE: + return "WM_DEVICECHANGE" + case WM_DEVMODECHANGE: + return "WM_DEVMODECHANGE" + case WM_DISPLAYCHANGE: + return "WM_DISPLAYCHANGE" + case WM_DRAWCLIPBOARD: + return "WM_DRAWCLIPBOARD" + case WM_DRAWITEM: + return "WM_DRAWITEM" + case WM_DROPFILES: + return "WM_DROPFILES" + case WM_ENABLE: + return "WM_ENABLE" + case WM_ENDSESSION: + return "WM_ENDSESSION" + case WM_ENTERIDLE: + return "WM_ENTERIDLE" + case WM_ENTERMENULOOP: + return "WM_ENTERMENULOOP" + case WM_ENTERSIZEMOVE: + return "WM_ENTERSIZEMOVE" + case WM_ERASEBKGND: + return "WM_ERASEBKGND" + case WM_EXITMENULOOP: + return "WM_EXITMENULOOP" + case WM_EXITSIZEMOVE: + return "WM_EXITSIZEMOVE" + case WM_FONTCHANGE: + return "WM_FONTCHANGE" + case WM_GETDLGCODE: + return "WM_GETDLGCODE" + case WM_GETFONT: + return "WM_GETFONT" + case WM_GETHOTKEY: + return "WM_GETHOTKEY" + case WM_GETICON: + return "WM_GETICON" + case WM_GETMINMAXINFO: + return "WM_GETMINMAXINFO" + case WM_GETTEXT: + return "WM_GETTEXT" + case WM_GETTEXTLENGTH: + return "WM_GETTEXTLENGTH" + case WM_HANDHELDFIRST: + return "WM_HANDHELDFIRST" + case WM_HANDHELDLAST: + return "WM_HANDHELDLAST" + case WM_HELP: + return "WM_HELP" + case WM_HOTKEY: + return "WM_HOTKEY" + case WM_HSCROLL: + return "WM_HSCROLL" + case WM_HSCROLLCLIPBOARD: + return "WM_HSCROLLCLIPBOARD" + case WM_ICONERASEBKGND: + return "WM_ICONERASEBKGND" + case WM_INITDIALOG: + return "WM_INITDIALOG" + case WM_INITMENU: + return "WM_INITMENU" + case WM_INITMENUPOPUP: + return "WM_INITMENUPOPUP" + case WM_INPUT: + return "WM_INPUT" + case WM_INPUTLANGCHANGE: + return "WM_INPUTLANGCHANGE" + case WM_INPUTLANGCHANGEREQUEST: + return "WM_INPUTLANGCHANGEREQUEST" + case WM_KEYDOWN: + return "WM_KEYDOWN" + case WM_KEYUP: + return "WM_KEYUP" + case WM_KILLFOCUS: + return "WM_KILLFOCUS" + case WM_MDIACTIVATE: + return "WM_MDIACTIVATE" + case WM_MDICASCADE: + return "WM_MDICASCADE" + case WM_MDICREATE: + return "WM_MDICREATE" + case WM_MDIDESTROY: + return "WM_MDIDESTROY" + case WM_MDIGETACTIVE: + return "WM_MDIGETACTIVE" + case WM_MDIICONARRANGE: + return "WM_MDIICONARRANGE" + case WM_MDIMAXIMIZE: + return "WM_MDIMAXIMIZE" + case WM_MDINEXT: + return "WM_MDINEXT" + case WM_MDIREFRESHMENU: + return "WM_MDIREFRESHMENU" + case WM_MDIRESTORE: + return "WM_MDIRESTORE" + case WM_MDISETMENU: + return "WM_MDISETMENU" + case WM_MDITILE: + return "WM_MDITILE" + case WM_MEASUREITEM: + return "WM_MEASUREITEM" + case WM_GETOBJECT: + return "WM_GETOBJECT" + case WM_CHANGEUISTATE: + return "WM_CHANGEUISTATE" + case WM_UPDATEUISTATE: + return "WM_UPDATEUISTATE" + case WM_QUERYUISTATE: + return "WM_QUERYUISTATE" + case WM_UNINITMENUPOPUP: + return "WM_UNINITMENUPOPUP" + case WM_MENURBUTTONUP: + return "WM_MENURBUTTONUP" + case WM_MENUCOMMAND: + return "WM_MENUCOMMAND" + case WM_MENUGETOBJECT: + return "WM_MENUGETOBJECT" + case WM_MENUDRAG: + return "WM_MENUDRAG" + case WM_APPCOMMAND: + return "WM_APPCOMMAND" + case WM_MENUCHAR: + return "WM_MENUCHAR" + case WM_MENUSELECT: + return "WM_MENUSELECT" + case WM_MOVE: + return "WM_MOVE" + case WM_MOVING: + return "WM_MOVING" + case WM_NCACTIVATE: + return "WM_NCACTIVATE" + case WM_NCCALCSIZE: + return "WM_NCCALCSIZE" + case WM_NCCREATE: + return "WM_NCCREATE" + case WM_NCDESTROY: + return "WM_NCDESTROY" + case WM_NCHITTEST: + return "WM_NCHITTEST" + case WM_NCLBUTTONDBLCLK: + return "WM_NCLBUTTONDBLCLK" + case WM_NCLBUTTONDOWN: + return "WM_NCLBUTTONDOWN" + case WM_NCLBUTTONUP: + return "WM_NCLBUTTONUP" + case WM_NCMBUTTONDBLCLK: + return "WM_NCMBUTTONDBLCLK" + case WM_NCMBUTTONDOWN: + return "WM_NCMBUTTONDOWN" + case WM_NCMBUTTONUP: + return "WM_NCMBUTTONUP" + case WM_NCXBUTTONDOWN: + return "WM_NCXBUTTONDOWN" + case WM_NCXBUTTONUP: + return "WM_NCXBUTTONUP" + case WM_NCXBUTTONDBLCLK: + return "WM_NCXBUTTONDBLCLK" + case WM_NCMOUSEHOVER: + return "WM_NCMOUSEHOVER" + case WM_NCMOUSELEAVE: + return "WM_NCMOUSELEAVE" + case WM_NCMOUSEMOVE: + return "WM_NCMOUSEMOVE" + case WM_NCPAINT: + return "WM_NCPAINT" + case WM_NCRBUTTONDBLCLK: + return "WM_NCRBUTTONDBLCLK" + case WM_NCRBUTTONDOWN: + return "WM_NCRBUTTONDOWN" + case WM_NCRBUTTONUP: + return "WM_NCRBUTTONUP" + case WM_NEXTDLGCTL: + return "WM_NEXTDLGCTL" + case WM_NEXTMENU: + return "WM_NEXTMENU" + case WM_NOTIFY: + return "WM_NOTIFY" + case WM_NOTIFYFORMAT: + return "WM_NOTIFYFORMAT" + case WM_NULL: + return "WM_NULL" + case WM_PAINT: + return "WM_PAINT" + case WM_PAINTCLIPBOARD: + return "WM_PAINTCLIPBOARD" + case WM_PAINTICON: + return "WM_PAINTICON" + case WM_PALETTECHANGED: + return "WM_PALETTECHANGED" + case WM_PALETTEISCHANGING: + return "WM_PALETTEISCHANGING" + case WM_PARENTNOTIFY: + return "WM_PARENTNOTIFY" + case WM_PASTE: + return "WM_PASTE" + case WM_PENWINFIRST: + return "WM_PENWINFIRST" + case WM_PENWINLAST: + return "WM_PENWINLAST" + case WM_POWER: + return "WM_POWER" + case WM_PRINT: + return "WM_PRINT" + case WM_PRINTCLIENT: + return "WM_PRINTCLIENT" + case WM_QUERYDRAGICON: + return "WM_QUERYDRAGICON" + case WM_QUERYENDSESSION: + return "WM_QUERYENDSESSION" + case WM_QUERYNEWPALETTE: + return "WM_QUERYNEWPALETTE" + case WM_QUERYOPEN: + return "WM_QUERYOPEN" + case WM_QUEUESYNC: + return "WM_QUEUESYNC" + case WM_QUIT: + return "WM_QUIT" + case WM_RENDERALLFORMATS: + return "WM_RENDERALLFORMATS" + case WM_RENDERFORMAT: + return "WM_RENDERFORMAT" + case WM_SETCURSOR: + return "WM_SETCURSOR" + case WM_SETFOCUS: + return "WM_SETFOCUS" + case WM_SETFONT: + return "WM_SETFONT" + case WM_SETHOTKEY: + return "WM_SETHOTKEY" + case WM_SETICON: + return "WM_SETICON" + case WM_SETREDRAW: + return "WM_SETREDRAW" + case WM_SETTEXT: + return "WM_SETTEXT" + case WM_SETTINGCHANGE: + return "WM_SETTINGCHANGE" + case WM_SHOWWINDOW: + return "WM_SHOWWINDOW" + case WM_SIZE: + return "WM_SIZE" + case WM_SIZECLIPBOARD: + return "WM_SIZECLIPBOARD" + case WM_SIZING: + return "WM_SIZING" + case WM_SPOOLERSTATUS: + return "WM_SPOOLERSTATUS" + case WM_STYLECHANGED: + return "WM_STYLECHANGED" + case WM_STYLECHANGING: + return "WM_STYLECHANGING" + case WM_SYSCHAR: + return "WM_SYSCHAR" + case WM_SYSCOLORCHANGE: + return "WM_SYSCOLORCHANGE" + case WM_SYSCOMMAND: + return "WM_SYSCOMMAND" + case WM_SYSDEADCHAR: + return "WM_SYSDEADCHAR" + case WM_SYSKEYDOWN: + return "WM_SYSKEYDOWN" + case WM_SYSKEYUP: + return "WM_SYSKEYUP" + case WM_TCARD: + return "WM_TCARD" + case WM_THEMECHANGED: + return "WM_THEMECHANGED" + case WM_TIMECHANGE: + return "WM_TIMECHANGE" + case WM_TIMER: + return "WM_TIMER" + case WM_UNDO: + return "WM_UNDO" + case WM_USER: + return "WM_USER" + case WM_USERCHANGED: + return "WM_USERCHANGED" + case WM_VKEYTOITEM: + return "WM_VKEYTOITEM" + case WM_VSCROLL: + return "WM_VSCROLL" + case WM_VSCROLLCLIPBOARD: + return "WM_VSCROLLCLIPBOARD" + case WM_WINDOWPOSCHANGED: + return "WM_WINDOWPOSCHANGED" + case WM_WINDOWPOSCHANGING: + return "WM_WINDOWPOSCHANGING" + case WM_KEYLAST: + return "WM_KEYLAST" + case WM_SYNCPAINT: + return "WM_SYNCPAINT" + case WM_MOUSEACTIVATE: + return "WM_MOUSEACTIVATE" + case WM_MOUSEMOVE: + return "WM_MOUSEMOVE" + case WM_LBUTTONDOWN: + return "WM_LBUTTONDOWN" + case WM_LBUTTONUP: + return "WM_LBUTTONUP" + case WM_LBUTTONDBLCLK: + return "WM_LBUTTONDBLCLK" + case WM_RBUTTONDOWN: + return "WM_RBUTTONDOWN" + case WM_RBUTTONUP: + return "WM_RBUTTONUP" + case WM_RBUTTONDBLCLK: + return "WM_RBUTTONDBLCLK" + case WM_MBUTTONDOWN: + return "WM_MBUTTONDOWN" + case WM_MBUTTONUP: + return "WM_MBUTTONUP" + case WM_MBUTTONDBLCLK: + return "WM_MBUTTONDBLCLK" + case WM_MOUSEWHEEL: + return "WM_MOUSEWHEEL" + case WM_XBUTTONDOWN: + return "WM_XBUTTONDOWN" + case WM_XBUTTONUP: + return "WM_XBUTTONUP" + case WM_MOUSELAST: + return "WM_MOUSELAST" + case WM_MOUSEHOVER: + return "WM_MOUSEHOVER" + case WM_MOUSELEAVE: + return "WM_MOUSELEAVE" + case WM_CLIPBOARDUPDATE: + return "WM_CLIPBOARDUPDATE" + default: + return fmt.Sprintf("0x%08x", msg) + } +} + var windowsVersion, _ = operatingsystem.GetWindowsVersionInfo() func IsWindowsVersionAtLeast(major, minor, buildNumber int) bool { diff --git a/v2/pkg/application/systray.go b/v2/pkg/application/systray.go index 0447e27b9..9798ef5f3 100644 --- a/v2/pkg/application/systray.go +++ b/v2/pkg/application/systray.go @@ -8,15 +8,19 @@ import ( // SystemTray defines a system tray! type SystemTray struct { - title string - hidden bool - lightModeIcon *options.SystemTrayIcon - darkModeIcon *options.SystemTrayIcon - tooltip string - startHidden bool - menu *menu.Menu - onLeftClick func() - onRightClick func() + title string + hidden bool + lightModeIcon *options.SystemTrayIcon + darkModeIcon *options.SystemTrayIcon + tooltip string + startHidden bool + menu *menu.Menu + onLeftClick func() + onRightClick func() + onLeftDoubleClick func() + onRightDoubleClick func() + onMenuClose func() + onMenuOpen func() // The platform specific implementation impl platform.SysTray @@ -24,14 +28,18 @@ type SystemTray struct { func newSystemTray(options *options.SystemTray) *SystemTray { return &SystemTray{ - title: options.Title, - lightModeIcon: options.LightModeIcon, - darkModeIcon: options.DarkModeIcon, - tooltip: options.Tooltip, - startHidden: options.StartHidden, - menu: options.Menu, - onLeftClick: options.OnLeftClick, - onRightClick: options.OnRightClick, + title: options.Title, + lightModeIcon: options.LightModeIcon, + darkModeIcon: options.DarkModeIcon, + tooltip: options.Tooltip, + startHidden: options.StartHidden, + menu: options.Menu, + onLeftClick: options.OnLeftClick, + onRightClick: options.OnRightClick, + onLeftDoubleClick: options.OnLeftDoubleClick, + onRightDoubleClick: options.OnRightDoubleClick, + onMenuOpen: options.OnMenuOpen, + onMenuClose: options.OnMenuClose, } } @@ -42,6 +50,10 @@ func (t *SystemTray) run() { t.impl.SetTooltip(t.tooltip) t.impl.OnLeftClick(t.onLeftClick) t.impl.OnRightClick(t.onRightClick) + t.impl.OnLeftDoubleClick(t.onLeftDoubleClick) + t.impl.OnRightDoubleClick(t.onRightDoubleClick) + t.impl.OnMenuOpen(t.onMenuOpen) + t.impl.OnMenuClose(t.onMenuClose) if !t.startHidden { t.impl.Show() } @@ -101,3 +113,39 @@ func (t *SystemTray) SetIcons(lightModeIcon *options.SystemTrayIcon, darkModeIco } } + +func (t *SystemTray) OnLeftClick(fn func()) { + if t.impl != nil { + t.impl.OnLeftClick(fn) + } +} + +func (t *SystemTray) OnRightClick(fn func()) { + if t.impl != nil { + t.impl.OnRightClick(fn) + } +} + +func (t *SystemTray) OnLeftDoubleClick(fn func()) { + if t.impl != nil { + t.impl.OnLeftDoubleClick(fn) + } +} + +func (t *SystemTray) OnRightDoubleClick(fn func()) { + if t.impl != nil { + t.impl.OnRightDoubleClick(fn) + } +} + +func (t *SystemTray) OnMenuOpen(fn func()) { + if t.impl != nil { + t.impl.OnMenuOpen(fn) + } +} + +func (t *SystemTray) OnMenuClose(fn func()) { + if t.impl != nil { + t.impl.OnMenuClose(fn) + } +} diff --git a/v2/pkg/options/systemtray.go b/v2/pkg/options/systemtray.go index 3e694ce85..117abb4d6 100644 --- a/v2/pkg/options/systemtray.go +++ b/v2/pkg/options/systemtray.go @@ -6,14 +6,18 @@ import ( // SystemTray contains options for the system tray type SystemTray struct { - LightModeIcon *SystemTrayIcon - DarkModeIcon *SystemTrayIcon - Title string - Tooltip string - StartHidden bool - Menu *menu.Menu - OnLeftClick func() - OnRightClick func() + LightModeIcon *SystemTrayIcon + DarkModeIcon *SystemTrayIcon + Title string + Tooltip string + StartHidden bool + Menu *menu.Menu + OnLeftClick func() + OnRightClick func() + OnLeftDoubleClick func() + OnRightDoubleClick func() + OnMenuClose func() + OnMenuOpen func() } // SystemTrayIcon represents a system tray icon