mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 22:55:48 +01:00
Tray menu callbacks working
This commit is contained in:
parent
6fa2ebdd4f
commit
0802d0d57a
8 changed files with 211 additions and 8 deletions
|
|
@ -19,6 +19,7 @@ var messageParsers = map[byte]func(string) (*parsedMessage, error){
|
|||
'D': dialogMessageParser,
|
||||
'S': systemMessageParser,
|
||||
'M': menuMessageParser,
|
||||
'T': trayMessageParser,
|
||||
}
|
||||
|
||||
// Parse will attempt to parse the given message
|
||||
|
|
|
|||
43
v2/internal/messagedispatcher/message/tray.go
Normal file
43
v2/internal/messagedispatcher/message/tray.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package message
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// TrayOnMessage is used to emit listener registration requests
|
||||
// on the service bus
|
||||
type TrayOnMessage struct {
|
||||
// MenuID is the id of the menu item we are interested in
|
||||
MenuID string
|
||||
// Callback is called when the menu is clicked
|
||||
Callback func(*menu.MenuItem)
|
||||
}
|
||||
|
||||
// trayMessageParser does what it says on the tin!
|
||||
func trayMessageParser(message string) (*parsedMessage, error) {
|
||||
|
||||
// Sanity check: Menu messages must be at least 2 bytes
|
||||
if len(message) < 3 {
|
||||
return nil, fmt.Errorf("event message was an invalid length")
|
||||
}
|
||||
|
||||
var topic string
|
||||
var data interface{}
|
||||
|
||||
// Switch the message type
|
||||
switch message[1] {
|
||||
case 'C':
|
||||
callbackid := message[2:]
|
||||
topic = "tray:clicked"
|
||||
data = callbackid
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid menu message: %s", message)
|
||||
}
|
||||
|
||||
// Create a new parsed message struct
|
||||
parsedMessage := &parsedMessage{Topic: topic, Data: data}
|
||||
|
||||
return parsedMessage, nil
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ type Runtime struct {
|
|||
Dialog Dialog
|
||||
System System
|
||||
Menu Menu
|
||||
Tray Tray
|
||||
Store *StoreProvider
|
||||
Log Log
|
||||
bus *servicebus.ServiceBus
|
||||
|
|
@ -27,6 +28,7 @@ func New(serviceBus *servicebus.ServiceBus, menu *menu.Menu) *Runtime {
|
|||
Dialog: newDialog(serviceBus),
|
||||
System: newSystem(serviceBus),
|
||||
Menu: newMenu(serviceBus, menu),
|
||||
Tray: newTray(serviceBus, menu),
|
||||
Log: newLog(serviceBus),
|
||||
bus: serviceBus,
|
||||
}
|
||||
|
|
|
|||
48
v2/internal/runtime/tray.go
Normal file
48
v2/internal/runtime/tray.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// Tray defines all Tray related operations
|
||||
type Tray interface {
|
||||
On(menuID string, callback func(*menu.MenuItem))
|
||||
Update()
|
||||
GetByID(menuID string) *menu.MenuItem
|
||||
RemoveByID(id string) bool
|
||||
}
|
||||
|
||||
type trayRuntime struct {
|
||||
bus *servicebus.ServiceBus
|
||||
trayMenu *menu.Menu
|
||||
}
|
||||
|
||||
// newTray creates a new Menu struct
|
||||
func newTray(bus *servicebus.ServiceBus, menu *menu.Menu) Menu {
|
||||
return &trayRuntime{
|
||||
bus: bus,
|
||||
trayMenu: menu,
|
||||
}
|
||||
}
|
||||
|
||||
// On registers a listener for a particular event
|
||||
func (t *trayRuntime) On(menuID string, callback func(*menu.MenuItem)) {
|
||||
t.bus.Publish("tray:on", &message.TrayOnMessage{
|
||||
MenuID: menuID,
|
||||
Callback: callback,
|
||||
})
|
||||
}
|
||||
|
||||
func (t *trayRuntime) Update() {
|
||||
t.bus.Publish("tray:update", t.trayMenu)
|
||||
}
|
||||
|
||||
func (t *trayRuntime) GetByID(menuID string) *menu.MenuItem {
|
||||
return t.trayMenu.GetByID(menuID)
|
||||
}
|
||||
|
||||
func (t *trayRuntime) RemoveByID(id string) bool {
|
||||
return t.trayMenu.RemoveByID(id)
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ func (t *Tray) Start() error {
|
|||
t.logger.Error("Received clicked message with invalid topic format. Expected 2 sections in topic, got %s", splitTopic)
|
||||
continue
|
||||
}
|
||||
t.logger.Trace("Got Menu clicked Message: %s %+v", menuMessage.Topic(), menuMessage.Data())
|
||||
t.logger.Trace("Got Tray Menu clicked Message: %s %+v", menuMessage.Topic(), menuMessage.Data())
|
||||
menuid := menuMessage.Data().(string)
|
||||
|
||||
// Get the menu item
|
||||
|
|
@ -106,7 +106,7 @@ func (t *Tray) Start() error {
|
|||
// Notify listeners
|
||||
t.notifyListeners(menuid, menuItem)
|
||||
case "on":
|
||||
listenerDetails := menuMessage.Data().(*message.MenuOnMessage)
|
||||
listenerDetails := menuMessage.Data().(*message.TrayOnMessage)
|
||||
id := listenerDetails.MenuID
|
||||
t.listeners[id] = append(t.listeners[id], listenerDetails.Callback)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ func main() {
|
|||
app.Bind(&Dialog{})
|
||||
app.Bind(&Window{})
|
||||
app.Bind(&Menu{})
|
||||
app.Bind(&Tray{})
|
||||
|
||||
err = app.Run()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -213,12 +213,6 @@ func (m *Menu) insertAfterRandom(_ *menu.MenuItem) {
|
|||
m.runtime.Menu.Update()
|
||||
}
|
||||
|
||||
func createApplicationTray() *menu.Menu {
|
||||
trayMenu := &menu.Menu{}
|
||||
trayMenu.Append(menu.Text("Hello from the tray!", "hi"))
|
||||
return trayMenu
|
||||
}
|
||||
|
||||
func createApplicationMenu() *menu.Menu {
|
||||
|
||||
// Create menu
|
||||
|
|
|
|||
114
v2/test/kitchensink/tray.go
Normal file
114
v2/test/kitchensink/tray.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// Tray struct
|
||||
type Tray struct {
|
||||
runtime *wails.Runtime
|
||||
|
||||
dynamicMenuCounter int
|
||||
lock sync.Mutex
|
||||
dynamicMenuItems map[string]*menu.MenuItem
|
||||
anotherDynamicMenuCounter int
|
||||
}
|
||||
|
||||
// WailsInit is called at application startup
|
||||
func (t *Tray) WailsInit(runtime *wails.Runtime) error {
|
||||
// Perform your setup here
|
||||
t.runtime = runtime
|
||||
|
||||
// Setup Menu Listeners
|
||||
t.runtime.Tray.On("Show Window", func(mi *menu.MenuItem) {
|
||||
t.runtime.Window.Show()
|
||||
})
|
||||
t.runtime.Tray.On("Hide Window", func(mi *menu.MenuItem) {
|
||||
t.runtime.Window.Hide()
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tray) incrementcounter() int {
|
||||
t.dynamicMenuCounter++
|
||||
return t.dynamicMenuCounter
|
||||
}
|
||||
|
||||
func (t *Tray) decrementcounter() int {
|
||||
t.dynamicMenuCounter--
|
||||
return t.dynamicMenuCounter
|
||||
}
|
||||
|
||||
func (t *Tray) addMenu(mi *menu.MenuItem) {
|
||||
|
||||
// Lock because this method will be called in a gorouting
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// Get this menu's parent
|
||||
parent := mi.Parent()
|
||||
counter := t.incrementcounter()
|
||||
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
||||
parent.Append(menu.Text(menuText, menuText))
|
||||
// parent.Append(menu.TextWithAccelerator(menuText, menuText, menu.Accel("[")))
|
||||
|
||||
// If this is the first dynamic menu added, let's add a remove menu item
|
||||
if counter == 1 {
|
||||
removeMenu := menu.TextWithAccelerator("Remove "+menuText,
|
||||
"Remove Last Item", menu.CmdOrCtrlAccel("-"))
|
||||
parent.Prepend(removeMenu)
|
||||
t.runtime.Tray.On("Remove Last Item", t.removeMenu)
|
||||
} else {
|
||||
removeMenu := t.runtime.Tray.GetByID("Remove Last Item")
|
||||
// Test if the remove menu hasn't already been removed in another thread
|
||||
if removeMenu != nil {
|
||||
removeMenu.Label = "Remove " + menuText
|
||||
}
|
||||
}
|
||||
t.runtime.Tray.Update()
|
||||
}
|
||||
|
||||
func (t *Tray) removeMenu(_ *menu.MenuItem) {
|
||||
|
||||
// Lock because this method will be called in a goroutine
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// Get the id of the last dynamic menu
|
||||
menuID := "Dynamic Menu Item " + strconv.Itoa(t.dynamicMenuCounter)
|
||||
|
||||
// Remove the last menu item by ID
|
||||
t.runtime.Tray.RemoveByID(menuID)
|
||||
|
||||
// Update the counter
|
||||
counter := t.decrementcounter()
|
||||
|
||||
// If we deleted the last dynamic menu, remove the "Remove Last Item" menu
|
||||
if counter == 0 {
|
||||
t.runtime.Tray.RemoveByID("Remove Last Item")
|
||||
} else {
|
||||
// Update label
|
||||
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
||||
removeMenu := t.runtime.Tray.GetByID("Remove Last Item")
|
||||
// Test if the remove menu hasn't already been removed in another thread
|
||||
if removeMenu == nil {
|
||||
return
|
||||
}
|
||||
removeMenu.Label = "Remove " + menuText
|
||||
}
|
||||
|
||||
// parent.Append(menu.TextWithAccelerator(menuText, menuText, menu.Accel("[")))
|
||||
t.runtime.Tray.Update()
|
||||
}
|
||||
|
||||
func createApplicationTray() *menu.Menu {
|
||||
trayMenu := &menu.Menu{}
|
||||
trayMenu.Append(menu.Text("Show Window", "Show Window"))
|
||||
trayMenu.Append(menu.Text("Hide Window", "Hide Window"))
|
||||
return trayMenu
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue