mirror of
https://github.com/wavetermdev/wails.git
synced 2026-08-05 13:53:43 -07:00
Tray menu support
Bugfix move after tray use Refactored options to handle default tray/menu
This commit is contained in:
+13
-33
@@ -3,9 +3,6 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
goruntime "runtime"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
@@ -14,7 +11,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/internal/subsystem"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
@@ -48,16 +44,16 @@ type App struct {
|
||||
}
|
||||
|
||||
// Create App
|
||||
func CreateApp(options *options.App) (*App, error) {
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
|
||||
// Merge default options
|
||||
options.MergeDefaults()
|
||||
options.MergeDefaults(appoptions)
|
||||
|
||||
// Set up logger
|
||||
myLogger := logger.New(options.Logger)
|
||||
myLogger.SetLogLevel(options.LogLevel)
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
window := ffenestri.NewApplicationWithConfig(options, myLogger)
|
||||
window := ffenestri.NewApplicationWithConfig(appoptions, myLogger)
|
||||
|
||||
result := &App{
|
||||
window: window,
|
||||
@@ -66,7 +62,7 @@ func CreateApp(options *options.App) (*App, error) {
|
||||
bindings: binding.NewBindings(myLogger),
|
||||
}
|
||||
|
||||
result.options = options
|
||||
result.options = appoptions
|
||||
|
||||
// Initialise the app
|
||||
err := result.Init()
|
||||
@@ -96,8 +92,10 @@ func (a *App) Run() error {
|
||||
}
|
||||
|
||||
// Start the runtime
|
||||
runtimesubsystem, err := subsystem.NewRuntime(a.servicebus, a.logger,
|
||||
a.options.Mac.Menu)
|
||||
applicationMenu := options.GetApplicationMenu(a.options)
|
||||
trayMenu := options.GetTrayMenu(a.options)
|
||||
|
||||
runtimesubsystem, err := subsystem.NewRuntime(a.servicebus, a.logger, applicationMenu, trayMenu)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -112,8 +110,7 @@ func (a *App) Run() error {
|
||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||
|
||||
// Start the binding subsystem
|
||||
bindingsubsystem, err := subsystem.NewBinding(a.servicebus, a.logger,
|
||||
a.bindings, a.runtime.GoRuntime())
|
||||
bindingsubsystem, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -156,25 +153,9 @@ func (a *App) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start the menu subsystem
|
||||
var applicationMenu *menu.Menu
|
||||
var trayMenu *menu.Menu
|
||||
switch goruntime.GOOS {
|
||||
case "darwin":
|
||||
applicationMenu = a.options.Mac.Menu
|
||||
trayMenu = a.options.Mac.Tray
|
||||
// case "linux":
|
||||
// applicationMenu = a.options.Linux.Menu
|
||||
// case "windows":
|
||||
// applicationMenu = a.options.Windows.Menu
|
||||
default:
|
||||
return fmt.Errorf("unsupported OS: %s", goruntime.GOOS)
|
||||
}
|
||||
|
||||
// Optionally start the menu subsystem
|
||||
if applicationMenu != nil {
|
||||
menusubsystem, err := subsystem.NewMenu(applicationMenu, a.servicebus,
|
||||
a.logger)
|
||||
menusubsystem, err := subsystem.NewMenu(applicationMenu, a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -187,8 +168,7 @@ func (a *App) Run() error {
|
||||
|
||||
// Optionally start the tray subsystem
|
||||
if trayMenu != nil {
|
||||
traysubsystem, err := subsystem.NewTray(trayMenu, a.servicebus,
|
||||
a.logger)
|
||||
traysubsystem, err := subsystem.NewTray(trayMenu, a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -33,4 +33,5 @@ extern void OpenDialog(void *appPointer, char *callbackID, char *title, char *fi
|
||||
extern void SaveDialog(void *appPointer, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories);
|
||||
extern void DarkModeEnabled(void *appPointer, char *callbackID);
|
||||
extern void UpdateMenu(void *app, char *menuAsJSON);
|
||||
extern void UpdateTray(void *app, char *menuAsJSON);
|
||||
#endif
|
||||
|
||||
@@ -172,3 +172,19 @@ func (c *Client) UpdateMenu(menu *menu.Menu) {
|
||||
}
|
||||
C.UpdateMenu(c.app.app, c.app.string2CString(string(menuJSON)))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateTray(menu *menu.Menu) {
|
||||
|
||||
// Guard against nil menus
|
||||
if menu == nil {
|
||||
return
|
||||
}
|
||||
// Process the menu
|
||||
processedMenu := NewProcessedMenu(menu)
|
||||
trayMenuJSON, err := json.Marshal(processedMenu)
|
||||
if err != nil {
|
||||
c.app.logger.Error("Error processing updated Tray: %s", err.Error())
|
||||
return
|
||||
}
|
||||
C.UpdateTray(c.app.app, c.app.string2CString(string(trayMenuJSON)))
|
||||
}
|
||||
|
||||
@@ -71,6 +71,10 @@ extern const unsigned char *assets[];
|
||||
extern const unsigned char runtime;
|
||||
extern const char *icon[];
|
||||
|
||||
// Tray icon
|
||||
extern const unsigned int trayIconLength;
|
||||
extern const unsigned char *trayIcon[];
|
||||
|
||||
// MAIN DEBUG FLAG
|
||||
int debug;
|
||||
|
||||
@@ -176,7 +180,6 @@ struct Application {
|
||||
int webviewIsTranparent;
|
||||
const char *appearance;
|
||||
int decorations;
|
||||
bool dragging;
|
||||
int logLevel;
|
||||
|
||||
// Features
|
||||
@@ -200,6 +203,7 @@ struct Application {
|
||||
// Tray
|
||||
const char *trayMenuAsJSON;
|
||||
JsonNode *processedTrayMenu;
|
||||
id statusItem;
|
||||
|
||||
// User Data
|
||||
char *HTML;
|
||||
@@ -334,7 +338,6 @@ void messageHandler(id self, SEL cmd, id contentController, id message) {
|
||||
// Guard against null events
|
||||
if( app->mouseEvent != NULL ) {
|
||||
HideMouse();
|
||||
app->dragging = true;
|
||||
ON_MAIN_THREAD(
|
||||
msg(app->mainWindow, s("performWindowDragWithEvent:"), app->mouseEvent);
|
||||
);
|
||||
@@ -569,8 +572,6 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
||||
result->mouseDownMonitor = NULL;
|
||||
result->mouseUpMonitor = NULL;
|
||||
|
||||
result->dragging = false;
|
||||
|
||||
// Features
|
||||
result->frame = 1;
|
||||
result->hideTitle = 0;
|
||||
@@ -591,6 +592,7 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
||||
// Tray
|
||||
result->trayMenuAsJSON = NULL;
|
||||
result->processedTrayMenu = NULL;
|
||||
result->statusItem = NULL;
|
||||
|
||||
// Window Appearance
|
||||
result->vibrancyLayer = NULL;
|
||||
@@ -1917,22 +1919,30 @@ void UpdateMenu(struct Application *app, const char *menuAsJSON) {
|
||||
|
||||
void parseTrayData(struct Application *app) {
|
||||
|
||||
// msg(statusBarButton, s("setImage:"),
|
||||
// msg(c("NSImage"), s("imageNamed:"),
|
||||
// msg(c("NSString"), s("stringWithUTF8String:"), tray->icon)));
|
||||
|
||||
|
||||
// Allocate the hashmaps we need
|
||||
allocateTrayHashMaps(app);
|
||||
|
||||
// Create a new menu
|
||||
id traymenu = createMenu(str(""));
|
||||
|
||||
// Create a new menu bar
|
||||
id statusBar = msg( c("NSStatusBar"), s("systemStatusBar") );
|
||||
id statusItem = msg(statusBar, s("statusItemWithLength:"), -1.0);
|
||||
msg(statusItem, s("retain"));
|
||||
id statusBarButton = msg(statusItem, s("button"));
|
||||
id statusItem = app->statusItem;
|
||||
|
||||
// Create a new menu bar if we need to
|
||||
if ( statusItem == NULL ) {
|
||||
id statusBar = msg( c("NSStatusBar"), s("systemStatusBar") );
|
||||
statusItem = msg(statusBar, s("statusItemWithLength:"), -1.0);
|
||||
app->statusItem = statusItem;
|
||||
msg(statusItem, s("retain"));
|
||||
id statusBarButton = msg(statusItem, s("button"));
|
||||
|
||||
// If we have a tray icon
|
||||
if ( trayIconLength > 0 ) {
|
||||
id imageData = msg(c("NSData"), s("dataWithBytes:length:"), trayIcon, trayIconLength);
|
||||
id trayImage = ALLOC("NSImage");
|
||||
msg(trayImage, s("initWithData:"), imageData);
|
||||
msg(statusBarButton, s("setImage:"), trayImage);
|
||||
}
|
||||
}
|
||||
|
||||
Debug(app, ">>>>>>>>>>> TRAY MENU: %s", app->trayMenuAsJSON);
|
||||
|
||||
@@ -1973,8 +1983,29 @@ void parseTrayData(struct Application *app) {
|
||||
processRadioGroup(radioGroup, &menuItemMapForTrayMenu, &radioGroupMapForTrayMenu);
|
||||
}
|
||||
|
||||
|
||||
// msg(statusBarButton, s("setImage:"),
|
||||
// msg(c("NSImage"), s("imageNamed:"),
|
||||
// msg(c("NSString"), s("stringWithUTF8String:"), tray->icon)));
|
||||
|
||||
|
||||
msg(statusItem, s("setMenu:"), traymenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// UpdateTray replaces the current tray menu with the given one
|
||||
void UpdateTray(struct Application *app, const char *trayMenuAsJSON) {
|
||||
Debug(app, "tray is now: %s", trayMenuAsJSON);
|
||||
ON_MAIN_THREAD (
|
||||
|
||||
// Free up memory
|
||||
destroyTray(app);
|
||||
|
||||
// Set the menu JSON
|
||||
app->trayMenuAsJSON = trayMenuAsJSON;
|
||||
parseTrayData(app);
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void Run(struct Application *app, int argc, char **argv) {
|
||||
@@ -2039,15 +2070,16 @@ void Run(struct Application *app, int argc, char **argv) {
|
||||
msg(manager, s("addScriptMessageHandler:name:"), app->delegate, str("windowDrag"));
|
||||
// Add mouse event hooks
|
||||
app->mouseDownMonitor = msg(c("NSEvent"), u("addLocalMonitorForEventsMatchingMask:handler:"), NSEventMaskLeftMouseDown, ^(id incomingEvent) {
|
||||
app->mouseEvent = incomingEvent;
|
||||
// Make sure the mouse click was in the window, not the tray
|
||||
id window = msg(incomingEvent, s("window"));
|
||||
if (window == app->mainWindow) {
|
||||
app->mouseEvent = incomingEvent;
|
||||
}
|
||||
return incomingEvent;
|
||||
});
|
||||
app->mouseUpMonitor = msg(c("NSEvent"), u("addLocalMonitorForEventsMatchingMask:handler:"), NSEventMaskLeftMouseUp, ^(id incomingEvent) {
|
||||
app->mouseEvent = NULL;
|
||||
if ( app->dragging ) {
|
||||
ShowMouse();
|
||||
app->dragging = false;
|
||||
}
|
||||
ShowMouse();
|
||||
return incomingEvent;
|
||||
});
|
||||
|
||||
@@ -2143,13 +2175,9 @@ void Run(struct Application *app, int argc, char **argv) {
|
||||
}
|
||||
|
||||
// If we have a tray menu, process it
|
||||
printf
|
||||
("\n\n\n*****************************************************************************************************************************************************************************************************************\n\n\n");
|
||||
if( app->trayMenuAsJSON != NULL ) {
|
||||
parseTrayData(app);
|
||||
}
|
||||
printf
|
||||
("\n\n\n*****************************************************************************************************************************************************************************************************************\n\n\n");
|
||||
|
||||
// Finally call run
|
||||
Debug(app, "Run called");
|
||||
|
||||
@@ -20,6 +20,7 @@ extern void SetTray(void *, const char *);
|
||||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
func (a *Application) processPlatformSettings() error {
|
||||
@@ -71,7 +72,8 @@ func (a *Application) processPlatformSettings() error {
|
||||
}
|
||||
|
||||
// Process menu
|
||||
if mac.Menu != nil {
|
||||
applicationMenu := options.GetApplicationMenu(a.config)
|
||||
if applicationMenu != nil {
|
||||
|
||||
/*
|
||||
As radio groups need to be manually managed on OSX,
|
||||
@@ -81,7 +83,7 @@ func (a *Application) processPlatformSettings() error {
|
||||
a list of all members of the group and the number of members
|
||||
in the group (this last one is for optimisation at the C layer).
|
||||
*/
|
||||
processedMenu := NewProcessedMenu(mac.Menu)
|
||||
processedMenu := NewProcessedMenu(applicationMenu)
|
||||
applicationMenuJSON, err := json.Marshal(processedMenu)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,7 +92,8 @@ func (a *Application) processPlatformSettings() error {
|
||||
}
|
||||
|
||||
// Process tray
|
||||
if mac.Tray != nil {
|
||||
tray := options.GetTrayMenu(a.config)
|
||||
if tray != nil {
|
||||
|
||||
/*
|
||||
As radio groups need to be manually managed on OSX,
|
||||
@@ -100,13 +103,12 @@ func (a *Application) processPlatformSettings() error {
|
||||
a list of all members of the group and the number of members
|
||||
in the group (this last one is for optimisation at the C layer).
|
||||
*/
|
||||
processedMenu := NewProcessedMenu(mac.Tray)
|
||||
processedMenu := NewProcessedMenu(tray)
|
||||
trayMenuJSON, err := json.Marshal(processedMenu)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
C.SetTray(a.app, a.string2CString(string(trayMenuJSON)))
|
||||
println("******************** SET TRAY!!!!! &&&&&&&&&&&&&&&&&&&&&&&&&&")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -32,6 +32,7 @@ type Client interface {
|
||||
WindowSetColour(colour int)
|
||||
DarkModeEnabled(callbackID string)
|
||||
UpdateMenu(menu *menu.Menu)
|
||||
UpdateTray(menu *menu.Menu)
|
||||
}
|
||||
|
||||
// DispatchClient is what the frontends use to interface with the
|
||||
|
||||
@@ -24,6 +24,7 @@ type Dispatcher struct {
|
||||
dialogChannel <-chan *servicebus.Message
|
||||
systemChannel <-chan *servicebus.Message
|
||||
menuChannel <-chan *servicebus.Message
|
||||
trayChannel <-chan *servicebus.Message
|
||||
running bool
|
||||
|
||||
servicebus *servicebus.ServiceBus
|
||||
@@ -76,6 +77,11 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
trayChannel, err := servicebus.Subscribe("trayfrontend:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &Dispatcher{
|
||||
servicebus: servicebus,
|
||||
eventChannel: eventChannel,
|
||||
@@ -87,6 +93,7 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
||||
dialogChannel: dialogChannel,
|
||||
systemChannel: systemChannel,
|
||||
menuChannel: menuChannel,
|
||||
trayChannel: trayChannel,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@@ -118,6 +125,8 @@ func (d *Dispatcher) Start() error {
|
||||
d.processSystemMessage(systemMessage)
|
||||
case menuMessage := <-d.menuChannel:
|
||||
d.processMenuMessage(menuMessage)
|
||||
case trayMessage := <-d.trayChannel:
|
||||
d.processTrayMessage(trayMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,3 +446,32 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processTrayMessage(result *servicebus.Message) {
|
||||
splitTopic := strings.Split(result.Topic(), ":")
|
||||
if len(splitTopic) < 2 {
|
||||
d.logger.Error("Invalid tray message : %#v", result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
command := splitTopic[1]
|
||||
switch command {
|
||||
case "update":
|
||||
|
||||
updatedMenu, ok := result.Data().(*menu.Menu)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'trayfrontend:update' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Work out what we mean in a multi window environment...
|
||||
// For now we will just pick the first one
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateTray(updatedMenu)
|
||||
}
|
||||
|
||||
default:
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type Runtime struct {
|
||||
}
|
||||
|
||||
// New creates a new runtime
|
||||
func New(serviceBus *servicebus.ServiceBus, menu *menu.Menu) *Runtime {
|
||||
func New(serviceBus *servicebus.ServiceBus, menu *menu.Menu, trayMenu *menu.Menu) *Runtime {
|
||||
result := &Runtime{
|
||||
Browser: newBrowser(),
|
||||
Events: newEvents(serviceBus),
|
||||
@@ -28,7 +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),
|
||||
Tray: newTray(serviceBus, trayMenu),
|
||||
Log: newLog(serviceBus),
|
||||
bus: serviceBus,
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type Runtime struct {
|
||||
}
|
||||
|
||||
// NewRuntime creates a new runtime subsystem
|
||||
func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger, menu *menu.Menu) (*Runtime, error) {
|
||||
func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger, menu *menu.Menu, trayMenu *menu.Menu) (*Runtime, error) {
|
||||
|
||||
// Register quit channel
|
||||
quitChannel, err := bus.Subscribe("quit")
|
||||
@@ -42,7 +42,7 @@ func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger, menu *menu.Me
|
||||
quitChannel: quitChannel,
|
||||
runtimeChannel: runtimeChannel,
|
||||
logger: logger.CustomLogger("Runtime Subsystem"),
|
||||
runtime: runtime.New(bus, menu),
|
||||
runtime: runtime.New(bus, menu, trayMenu),
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/internal/html"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
)
|
||||
|
||||
// DesktopBuilder builds applications for the desktop
|
||||
@@ -32,7 +31,7 @@ func (d *DesktopBuilder) BuildAssets(options *Options) error {
|
||||
}
|
||||
|
||||
// Build base assets (HTML/JS/CSS/etc)
|
||||
err = d.BuildBaseAssets(assets, options.Logger)
|
||||
err = d.BuildBaseAssets(assets, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -47,9 +46,10 @@ func (d *DesktopBuilder) BuildAssets(options *Options) error {
|
||||
}
|
||||
|
||||
// BuildBaseAssets builds the assets for the desktop application
|
||||
func (d *DesktopBuilder) BuildBaseAssets(assets *html.AssetBundle, outputLogger *clilogger.CLILogger) error {
|
||||
func (d *DesktopBuilder) BuildBaseAssets(assets *html.AssetBundle, options *Options) error {
|
||||
var err error
|
||||
|
||||
outputLogger := options.Logger
|
||||
outputLogger.Print(" - Embedding Assets...")
|
||||
|
||||
// Get target asset directory
|
||||
@@ -63,7 +63,13 @@ func (d *DesktopBuilder) BuildBaseAssets(assets *html.AssetBundle, outputLogger
|
||||
d.addFileToDelete(assetsFile)
|
||||
|
||||
// Process Icon
|
||||
err = d.processIcon(assetDir)
|
||||
err = d.processApplicationIcon(assetDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Process Tray Icons
|
||||
err = d.processTrayIcons(assetDir, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -73,9 +79,9 @@ func (d *DesktopBuilder) BuildBaseAssets(assets *html.AssetBundle, outputLogger
|
||||
return nil
|
||||
}
|
||||
|
||||
// processIcon will copy a default icon if one doesn't exist, then, if
|
||||
// processApplicationIcon will copy a default icon if one doesn't exist, then, if
|
||||
// needed, will compile the icon
|
||||
func (d *DesktopBuilder) processIcon(assetDir string) error {
|
||||
func (d *DesktopBuilder) processApplicationIcon(assetDir string) error {
|
||||
|
||||
// Copy default icon if one doesn't exist
|
||||
iconFile := filepath.Join(d.projectData.Path, "icon.png")
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// +build darwin
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// desktop_linux.go will compile the tray icon found at <projectdir>/trayicon.png into the application
|
||||
func (d *DesktopBuilder) processTrayIcons(assetDir string, options *Options) error {
|
||||
|
||||
// Determine icon file
|
||||
iconFile := filepath.Join(options.ProjectData.Path, "trayicon.png")
|
||||
|
||||
var err error
|
||||
|
||||
// Setup target
|
||||
targetFilename := "trayicon"
|
||||
targetFile := filepath.Join(assetDir, targetFilename+".c")
|
||||
//d.addFileToDelete(targetFile)
|
||||
|
||||
var dataBytes []byte
|
||||
|
||||
// If the icon file exists, load it up
|
||||
if fs.FileExists(iconFile) {
|
||||
// Load the tray icon
|
||||
dataBytes, err = ioutil.ReadFile(iconFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Use a strings builder
|
||||
var cdata strings.Builder
|
||||
|
||||
// Write header
|
||||
header := `// trayicon.c
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL.
|
||||
// This file was auto-generated. DO NOT MODIFY.
|
||||
|
||||
`
|
||||
cdata.WriteString(header)
|
||||
cdata.WriteString(fmt.Sprintf("const unsigned int trayIconLength = %d;\n", len(dataBytes)))
|
||||
cdata.WriteString("const unsigned char trayIcon[] = { ")
|
||||
|
||||
// Convert each byte to hex
|
||||
for _, b := range dataBytes {
|
||||
cdata.WriteString(fmt.Sprintf("0x%x, ", b))
|
||||
}
|
||||
|
||||
cdata.WriteString("0x00 };\n")
|
||||
|
||||
err = ioutil.WriteFile(targetFile, []byte(cdata.String()), 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func (b *HybridBuilder) BuildBaseAssets(options *Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.desktop.BuildBaseAssets(assets, options.Logger)
|
||||
err = b.desktop.BuildBaseAssets(assets, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -24,10 +24,15 @@ func packageApplication(options *Options) error {
|
||||
|
||||
contentsDirectory := filepath.Join(options.BuildDirectory, bundlename, "/Contents")
|
||||
exeDir := filepath.Join(contentsDirectory, "/MacOS")
|
||||
fs.MkDirs(exeDir, 0755)
|
||||
err = fs.MkDirs(exeDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceDir := filepath.Join(contentsDirectory, "/Resources")
|
||||
fs.MkDirs(resourceDir, 0755)
|
||||
|
||||
err = fs.MkDirs(resourceDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy binary
|
||||
packedBinaryPath := filepath.Join(exeDir, options.ProjectData.Name)
|
||||
err = fs.MoveFile(options.CompiledBinary, packedBinaryPath)
|
||||
@@ -42,7 +47,7 @@ func packageApplication(options *Options) error {
|
||||
}
|
||||
|
||||
// Generate Icons
|
||||
err = processIcon(resourceDir)
|
||||
err = processApplicationIcon(resourceDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -84,8 +89,10 @@ func generateDefaultPlist(options *Options, targetPlistFile string) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Cannot open plist template")
|
||||
}
|
||||
tmpl.Parse(string(infoPlist))
|
||||
|
||||
_, err = tmpl.Parse(string(infoPlist))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Write the template to a buffer
|
||||
var tpl bytes.Buffer
|
||||
err = tmpl.Execute(&tpl, plistData)
|
||||
@@ -122,7 +129,7 @@ func newPlistData(title, exe, packageID, version, author string) *plistData {
|
||||
}
|
||||
}
|
||||
|
||||
func processIcon(resourceDir string) error {
|
||||
func processApplicationIcon(resourceDir string) error {
|
||||
|
||||
appIcon, err := fs.RelativeToCwd("appicon.png")
|
||||
if err != nil {
|
||||
|
||||
@@ -2,7 +2,6 @@ package options
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
)
|
||||
|
||||
@@ -18,7 +17,7 @@ var Default = &App{
|
||||
Appearance: mac.DefaultAppearance,
|
||||
WebviewIsTransparent: false,
|
||||
WindowBackgroundIsTranslucent: false,
|
||||
Menu: menu.DefaultMacMenu(),
|
||||
//Menu: menu.DefaultMacMenu(),
|
||||
},
|
||||
Logger: logger.NewDefaultLogger(),
|
||||
LogLevel: logger.INFO,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
@@ -22,15 +24,74 @@ type App struct {
|
||||
StartHidden bool
|
||||
DevTools bool
|
||||
RGBA int
|
||||
Tray *menu.Menu
|
||||
Menu *menu.Menu
|
||||
Mac *mac.Options
|
||||
Logger logger.Logger `json:"-"`
|
||||
LogLevel logger.LogLevel
|
||||
}
|
||||
|
||||
// MergeDefaults will set the minimum default values for an application
|
||||
func (a *App) MergeDefaults() {
|
||||
err := mergo.Merge(a, Default)
|
||||
func MergeDefaults(appoptions *App) {
|
||||
err := mergo.Merge(appoptions, Default)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// We need to ensure there's a default menu on Mac
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if GetApplicationMenu(appoptions) == nil {
|
||||
appoptions.Menu = menu.NewMenuFromItems(menu.AppMenu())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetTrayMenu(appoptions *App) *menu.Menu {
|
||||
var result *menu.Menu
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if appoptions.Mac != nil {
|
||||
result = appoptions.Mac.Tray
|
||||
}
|
||||
//case "linux":
|
||||
// if appoptions.Linux != nil {
|
||||
// result = appoptions.Linux.Tray
|
||||
// }
|
||||
//case "windows":
|
||||
// if appoptions.Windows != nil {
|
||||
// result = appoptions.Windows.Tray
|
||||
// }
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
result = appoptions.Tray
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func GetApplicationMenu(appoptions *App) *menu.Menu {
|
||||
var result *menu.Menu
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if appoptions.Mac != nil {
|
||||
result = appoptions.Mac.Menu
|
||||
}
|
||||
//case "linux":
|
||||
// if appoptions.Linux != nil {
|
||||
// result = appoptions.Linux.Tray
|
||||
// }
|
||||
//case "windows":
|
||||
// if appoptions.Windows != nil {
|
||||
// result = appoptions.Windows.Tray
|
||||
// }
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
result = appoptions.Menu
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ func main() {
|
||||
Height: 768,
|
||||
MinWidth: 800,
|
||||
MinHeight: 600,
|
||||
//Tray: menu.NewMenuFromItems(menu.AppMenu()),
|
||||
//Menu: menu.NewMenuFromItems(menu.AppMenu()),
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
|
||||
@@ -145,6 +145,10 @@ func (m *Menu) createDynamicMenuTwo() {
|
||||
|
||||
// Insert this menu after Dynamic Menu Item 1
|
||||
dm1 := m.runtime.Menu.GetByID("Dynamic Menus 1")
|
||||
if dm1 == nil {
|
||||
return
|
||||
}
|
||||
|
||||
dm1.InsertAfter(dm2)
|
||||
m.runtime.Menu.Update()
|
||||
}
|
||||
@@ -172,6 +176,9 @@ func (m *Menu) insertBeforeRandom(_ *menu.MenuItem) {
|
||||
m.dynamicMenuItems[text] = newItem
|
||||
|
||||
item := m.runtime.Menu.GetByID(randomItemID)
|
||||
if item == nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.runtime.Log.Info(fmt.Sprintf(
|
||||
"Inserting menu item '%s' before menu item '%s'", newItem.Label,
|
||||
|
||||
@@ -26,9 +26,20 @@ func (t *Tray) WailsInit(runtime *wails.Runtime) error {
|
||||
// Setup Menu Listeners
|
||||
t.runtime.Tray.On("Show Window", func(mi *menu.MenuItem) {
|
||||
t.runtime.Window.Show()
|
||||
showWindow := t.runtime.Tray.GetByID("Show Window")
|
||||
hideWindow := t.runtime.Tray.GetByID("Hide Window")
|
||||
showWindow.Hidden = true
|
||||
hideWindow.Hidden = false
|
||||
t.runtime.Tray.Update()
|
||||
})
|
||||
t.runtime.Tray.On("Hide Window", func(mi *menu.MenuItem) {
|
||||
t.runtime.Window.Hide()
|
||||
showWindow := t.runtime.Tray.GetByID("Show Window")
|
||||
hideWindow := t.runtime.Tray.GetByID("Hide Window")
|
||||
showWindow.Hidden = false
|
||||
hideWindow.Hidden = true
|
||||
t.runtime.Tray.Update()
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
@@ -108,7 +119,12 @@ func (t *Tray) removeMenu(_ *menu.MenuItem) {
|
||||
|
||||
func createApplicationTray() *menu.Menu {
|
||||
trayMenu := &menu.Menu{}
|
||||
trayMenu.Append(menu.Text("Show Window", "Show Window"))
|
||||
trayMenu.Append(&menu.MenuItem{
|
||||
ID: "Show Window",
|
||||
Label: "Show Window",
|
||||
Type: menu.TextType,
|
||||
Hidden: true,
|
||||
})
|
||||
trayMenu.Append(menu.Text("Hide Window", "Hide Window"))
|
||||
return trayMenu
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Reference in New Issue
Block a user