Compare commits

...

24 Commits

Author SHA1 Message Date
Lea Anthony
f71ce7913f v2.0.0-alpha.38 2021-02-24 21:50:39 +11:00
Lea Anthony
53db687a26 Support DeleteTrayMenuByID 2021-02-24 21:49:55 +11:00
Lea Anthony
13939d3d6b v2.0.0-alpha.37 2021-02-23 20:15:01 +11:00
Lea Anthony
552c6b8711 fix: modifiers 2021-02-23 18:57:59 +11:00
Lea Anthony
feee2b3db2 v2.0.0-alpha.36 2021-02-23 08:53:26 +11:00
Lea Anthony
9889c2bdbb Support Activation Policy 2021-02-23 08:52:56 +11:00
Lea Anthony
2432fccf71 v2.0.0-alpha.35 2021-02-22 20:17:22 +11:00
Lea Anthony
70510fd180 @wails/runtime v1.3.10 2021-02-22 20:16:14 +11:00
Lea Anthony
17c6201469 Menu off by default in dev. Toggle with backtick. 2021-02-22 20:14:44 +11:00
Lea Anthony
0f209c8900 v2.0.0-alpha.34 2021-02-22 19:39:07 +11:00
Lea Anthony
cbf043585c v2.0.0-alpha.33 2021-02-22 19:33:44 +11:00
Lea Anthony
5ae621ceaa Start signal handler a little later 2021-02-22 19:33:18 +11:00
Lea Anthony
1231b59443 better signal handling for shutdown 2021-02-22 17:39:33 +11:00
Lea Anthony
b18d4fbf41 v2.0.0-alpha.32 2021-02-22 09:00:47 +11:00
Lea Anthony
9ec5605e63 fix: loglevel duplication 2021-02-22 09:00:09 +11:00
Lea Anthony
98a4de8878 v2.0.0-alpha.31 2021-02-21 20:38:14 +11:00
Lea Anthony
5fe709f558 Trigger clean shutdown on Quit 2021-02-21 20:37:42 +11:00
Lea Anthony
5231a6893b v2.0.0-alpha.30 2021-02-21 19:28:07 +11:00
Lea Anthony
74f3ce990f Support loglevel flag in dev mode 2021-02-21 19:26:20 +11:00
Lea Anthony
998a913853 Hide dev warnings by default 2021-02-21 16:36:56 +11:00
Lea Anthony
964844835c Better Wails update messaging 2021-02-21 06:12:19 +11:00
Lea Anthony
4e152bb849 v2.0.0-alpha.29 2021-02-21 05:56:11 +11:00
Lea Anthony
51133d098c Slight refactor of backend module generation 2021-02-21 05:52:42 +11:00
Lea Anthony
d4191e7d1b Support parsing keyboard shortcuts 2021-02-20 21:32:32 +11:00
31 changed files with 453 additions and 195 deletions

View File

@@ -53,6 +53,13 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
extensions := "go"
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go,js,css,html", &extensions)
// extensions to trigger rebuilds
showWarnings := false
command.BoolFlag("w", "Show warnings", &showWarnings)
loglevel := ""
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &loglevel)
command.Action(func() error {
// Create logger
@@ -78,7 +85,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
// Do initial build
logger.Println("Building application for development...")
newProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess)
newProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess, loglevel)
if newProcess != nil {
debugBinaryProcess = newProcess
}
@@ -117,7 +124,9 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
}
if !rebuild {
LogDarkYellow("[File change] %s did not match extension list (%s)", event.Name, extensions)
if showWarnings {
LogDarkYellow("[File change] %s did not match extension list (%s)", event.Name, extensions)
}
return
}
@@ -126,7 +135,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
// Do a rebuild
// Try and build the app
newBinaryProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess)
newBinaryProcess, err := restartApp(logger, "dev", ldflags, compilerCommand, debugBinaryProcess, loglevel)
if err != nil {
fmt.Printf("Error during build: %s", err.Error())
return
@@ -215,7 +224,7 @@ exit:
}
}
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process) (*process.Process, error) {
func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string, compilerCommand string, debugBinaryProcess *process.Process, loglevel string) (*process.Process, error) {
appBinary, err := buildApp(logger, outputType, ldflags, compilerCommand)
println()
@@ -239,7 +248,7 @@ func restartApp(logger *clilogger.CLILogger, outputType string, ldflags string,
// TODO: Generate `backend.js`
// Start up new binary
newProcess := process.NewProcess(logger, appBinary)
newProcess := process.NewProcess(logger, appBinary, "-loglevel", loglevel)
err = newProcess.Start()
if err != nil {
// Remove binary

View File

@@ -18,14 +18,14 @@ import (
func AddSubcommand(app *clir.Cli, w io.Writer, currentVersion string) error {
command := app.NewSubCommand("update", "Update the Wails CLI")
command.LongDescription(`This command allows you to update your version of Wails.`)
command.LongDescription(`This command allows you to update your version of the Wails CLI.`)
// Setup flags
var prereleaseRequired bool
command.BoolFlag("pre", "Update to latest Prerelease", &prereleaseRequired)
command.BoolFlag("pre", "Update CLI to latest Prerelease", &prereleaseRequired)
var specificVersion string
command.StringFlag("version", "Install a specific version (Overrides other flags)", &specificVersion)
command.StringFlag("version", "Install a specific version (Overrides other flags) of the CLI", &specificVersion)
command.Action(func() error {
@@ -143,7 +143,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
}
fmt.Println()
logger.Print("Installing Wails " + desiredVersion + "...")
logger.Print("Installing Wails CLI " + desiredVersion + "...")
// Run command in non module directory
homeDir, err := os.UserHomeDir()
@@ -158,7 +158,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
return err
}
fmt.Println()
logger.Println("Wails updated to " + desiredVersion)
logger.Println("Wails CLI updated to " + desiredVersion)
return nil
}

View File

@@ -1,3 +1,3 @@
package main
var version = "v2.0.0-alpha.28"
var version = "v2.0.0-alpha.38"

View File

@@ -4,8 +4,9 @@ package app
import (
"flag"
"github.com/wailsapp/wails/v2/pkg/logger"
"strings"
"github.com/wailsapp/wails/v2/pkg/logger"
)
// Init initialises the application for a debug environment
@@ -19,10 +20,10 @@ func (a *App) Init() error {
}
// Set log levels
greeting := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
flag.Parse()
if len(*greeting) > 0 {
switch strings.ToLower(*greeting) {
if len(*loglevel) > 0 {
switch strings.ToLower(*loglevel) {
case "trace":
a.logger.SetLogLevel(logger.TRACE)
case "info":

View File

@@ -117,14 +117,6 @@ func (a *App) Run() error {
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
ctx, cancel := context.WithCancel(parentContext)
// Setup signal handler
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger, a.shutdownCallback)
if err != nil {
return err
}
a.signal = signalsubsystem
a.signal.Start()
// Start the service bus
a.servicebus.Debug()
err = a.servicebus.Start()
@@ -132,7 +124,7 @@ func (a *App) Run() error {
return err
}
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
if err != nil {
return err
}
@@ -207,6 +199,14 @@ func (a *App) Run() error {
return err
}
// Setup signal handler
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger)
if err != nil {
return err
}
a.signal = signalsubsystem
a.signal.Start()
err = a.window.Run(dispatcher, bindingDump, a.debug)
a.logger.Trace("Ffenestri.Run() exited")
if err != nil {
@@ -231,5 +231,10 @@ func (a *App) Run() error {
return err
}
// Shutdown callback
if a.shutdownCallback != nil {
a.shutdownCallback()
}
return nil
}

View File

@@ -66,7 +66,6 @@ func CreateApp(appoptions *options.App) (*App, error) {
// Set up logger
myLogger := logger.New(appoptions.Logger)
myLogger.SetLogLevel(appoptions.LogLevel)
// Create the menu manager
menuManager := menumanager.NewManager()
@@ -119,14 +118,6 @@ func (a *App) Run() error {
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
ctx, cancel := context.WithCancel(parentContext)
// Setup signal handler
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger, a.shutdownCallback)
if err != nil {
return err
}
a.signal = signalsubsystem
a.signal.Start()
// Start the service bus
a.servicebus.Debug()
err = a.servicebus.Start()
@@ -134,7 +125,7 @@ func (a *App) Run() error {
return err
}
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
if err != nil {
return err
}
@@ -212,6 +203,14 @@ func (a *App) Run() error {
// Generate backend.js
a.bindings.GenerateBackendJS()
// Setup signal handler
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger)
if err != nil {
return err
}
a.signal = signalsubsystem
a.signal.Start()
err = a.bridge.Run(dispatcher, a.menuManager, bindingDump, a.debug)
a.logger.Trace("Bridge.Run() exited")
if err != nil {
@@ -236,6 +235,10 @@ func (a *App) Run() error {
return err
}
// Shutdown callback
if a.shutdownCallback != nil {
a.shutdownCallback()
}
return nil
}

View File

@@ -58,7 +58,7 @@ const backend = {`)
sortedPackageNames.Add(packageName)
}
sortedPackageNames.Sort()
for _, packageName := range sortedPackageNames.AsSlice() {
sortedPackageNames.Each(func(packageName string) {
packages := store[packageName]
output.WriteString(fmt.Sprintf(" \"%s\": {", packageName))
output.WriteString("\n")
@@ -67,7 +67,8 @@ const backend = {`)
sortedStructNames.Add(structName)
}
sortedStructNames.Sort()
for _, structName := range sortedStructNames.AsSlice() {
sortedStructNames.Each(func(structName string) {
structs := packages[structName]
output.WriteString(fmt.Sprintf(" \"%s\": {", structName))
output.WriteString("\n")
@@ -78,7 +79,7 @@ const backend = {`)
}
sortedMethodNames.Sort()
for _, methodName := range sortedMethodNames.AsSlice() {
sortedMethodNames.Each(func(methodName string) {
methodDetails := structs[methodName]
output.WriteString(" /**\n")
output.WriteString(" * " + methodName + "\n")
@@ -109,13 +110,16 @@ const backend = {`)
output.WriteString("\n")
output.WriteString(fmt.Sprintf(" },"))
output.WriteString("\n")
}
})
output.WriteString(fmt.Sprintf(" }"))
output.WriteString("\n")
}
})
output.WriteString(fmt.Sprintf(" }\n"))
output.WriteString("\n")
}
})
output.WriteString(`};
export default backend;`)

View File

@@ -37,6 +37,7 @@ extern void DarkModeEnabled(struct Application*, char *callbackID);
extern void SetApplicationMenu(struct Application*, const char *);
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
extern void SetTrayMenu(struct Application*, const char *menuTrayJSON);
extern void DeleteTrayMenuByID(struct Application*, const char *id);
extern void UpdateTrayMenuLabel(struct Application*, const char* JSON);
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);

View File

@@ -208,3 +208,7 @@ func (c *Client) UpdateTrayMenuLabel(JSON string) {
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
}
func (c *Client) DeleteTrayMenuByID(id string) {
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
}

View File

@@ -79,6 +79,7 @@ struct Application {
id mouseEvent;
id mouseDownMonitor;
id mouseUpMonitor;
int activationPolicy;
// Window Data
const char *title;
@@ -253,7 +254,7 @@ void Hide(struct Application *app) {
if( app->shuttingDown ) return;
ON_MAIN_THREAD(
msg(app->application, s("hide:"))
msg(app->application, s("hide:"));
);
}
@@ -498,31 +499,6 @@ void DestroyApplication(struct Application *app) {
Debug(app, "Finished Destroying Application");
}
// Quit will stop the cocoa application and free up all the memory
// used by the application
void Quit(struct Application *app) {
Debug(app, "Quit Called");
ON_MAIN_THREAD (
// Terminate app
msg(app->application, s("stop:"), NULL);
id fakeevent = msg(c("NSEvent"),
s("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
15, // Type
msg(c("CGPoint"), s("init:x:y:"), 0, 0), // location
0, // flags
0, // timestamp
0, // window
NULL, // context
0, // subtype
0, // data1
0 // data2
);
msg(c("NSApp"), s("postEvent:atStart:"), fakeevent, true);
// msg(c(app->mainWindow), s("performClose:"))
);
}
// SetTitle sets the main window title to the given string
void SetTitle(struct Application *app, const char *title) {
// Guard against calling during shutdown
@@ -1071,6 +1047,12 @@ void SetTrayMenu(struct Application *app, const char* trayMenuJSON) {
);
}
void DeleteTrayMenuByID(struct Application *app, const char *id) {
ON_MAIN_THREAD(
DeleteTrayMenuInStore(app->trayMenuStore, id);
);
}
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
// Guard against calling during shutdown
if( app->shuttingDown ) return;
@@ -1137,7 +1119,7 @@ void processDecorations(struct Application *app) {
void createApplication(struct Application *app) {
id application = msg(c("NSApplication"), s("sharedApplication"));
app->application = application;
msg(application, s("setActivationPolicy:"), 0);
msg(application, s("setActivationPolicy:"), app->activationPolicy);
}
void DarkModeEnabled(struct Application *app, const char *callbackID) {
@@ -1837,6 +1819,19 @@ void Run(struct Application *app, int argc, char **argv) {
MEMFREE(internalCode);
}
void SetActivationPolicy(struct Application* app, int policy) {
app->activationPolicy = policy;
}
// Quit will stop the cocoa application and free up all the memory
// used by the application
void Quit(struct Application *app) {
Debug(app, "Quit Called");
msg(app->application, s("stop:"), NULL);
SetSize(app, 0, 0);
Show(app);
Hide(app);
}
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) {
@@ -1899,6 +1894,8 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
result->shuttingDown = false;
result->activationPolicy = NSApplicationActivationPolicyRegular;
return (void*) result;
}

View File

@@ -48,6 +48,9 @@ func (a *Application) processPlatformSettings() error {
C.SetAppearance(a.app, a.string2CString(string(mac.Appearance)))
}
// Set activation policy
C.SetActivationPolicy(a.app, C.int(mac.ActivationPolicy))
// Check if the webview should be transparent
if mac.WebviewIsTransparent {
C.WebviewIsTransparent(a.app)

View File

@@ -66,6 +66,10 @@
#define NSControlStateValueOff 0
#define NSControlStateValueOn 1
#define NSApplicationActivationPolicyRegular 0
#define NSApplicationActivationPolicyAccessory 1
#define NSApplicationActivationPolicyProhibited 2
// Unbelievably, if the user swaps their button preference
// then right buttons are reported as left buttons
#define NSEventMaskLeftMouseDown 1 << 1
@@ -110,6 +114,8 @@ void SetTray(struct Application* app, const char *, const char *, const char *);
//void SetContextMenus(struct Application* app, const char *);
void AddTrayMenu(struct Application* app, const char *);
void SetActivationPolicy(struct Application* app, int policy);
void* lookupStringConstant(id constantName);
#endif

View File

@@ -180,151 +180,151 @@ id processAcceleratorKey(const char *key) {
return str("");
}
if( STREQ(key, "Backspace") ) {
if( STREQ(key, "backspace") ) {
return strunicode(0x0008);
}
if( STREQ(key, "Tab") ) {
if( STREQ(key, "tab") ) {
return strunicode(0x0009);
}
if( STREQ(key, "Return") ) {
if( STREQ(key, "return") ) {
return strunicode(0x000d);
}
if( STREQ(key, "Escape") ) {
if( STREQ(key, "escape") ) {
return strunicode(0x001b);
}
if( STREQ(key, "Left") ) {
if( STREQ(key, "left") ) {
return strunicode(0x001c);
}
if( STREQ(key, "Right") ) {
if( STREQ(key, "right") ) {
return strunicode(0x001d);
}
if( STREQ(key, "Up") ) {
if( STREQ(key, "up") ) {
return strunicode(0x001e);
}
if( STREQ(key, "Down") ) {
if( STREQ(key, "down") ) {
return strunicode(0x001f);
}
if( STREQ(key, "Space") ) {
if( STREQ(key, "space") ) {
return strunicode(0x0020);
}
if( STREQ(key, "Delete") ) {
if( STREQ(key, "delete") ) {
return strunicode(0x007f);
}
if( STREQ(key, "Home") ) {
if( STREQ(key, "home") ) {
return strunicode(0x2196);
}
if( STREQ(key, "End") ) {
if( STREQ(key, "end") ) {
return strunicode(0x2198);
}
if( STREQ(key, "Page Up") ) {
if( STREQ(key, "page up") ) {
return strunicode(0x21de);
}
if( STREQ(key, "Page Down") ) {
if( STREQ(key, "page down") ) {
return strunicode(0x21df);
}
if( STREQ(key, "F1") ) {
if( STREQ(key, "f1") ) {
return strunicode(0xf704);
}
if( STREQ(key, "F2") ) {
if( STREQ(key, "f2") ) {
return strunicode(0xf705);
}
if( STREQ(key, "F3") ) {
if( STREQ(key, "f3") ) {
return strunicode(0xf706);
}
if( STREQ(key, "F4") ) {
if( STREQ(key, "f4") ) {
return strunicode(0xf707);
}
if( STREQ(key, "F5") ) {
if( STREQ(key, "f5") ) {
return strunicode(0xf708);
}
if( STREQ(key, "F6") ) {
if( STREQ(key, "f6") ) {
return strunicode(0xf709);
}
if( STREQ(key, "F7") ) {
if( STREQ(key, "f7") ) {
return strunicode(0xf70a);
}
if( STREQ(key, "F8") ) {
if( STREQ(key, "f8") ) {
return strunicode(0xf70b);
}
if( STREQ(key, "F9") ) {
if( STREQ(key, "f9") ) {
return strunicode(0xf70c);
}
if( STREQ(key, "F10") ) {
if( STREQ(key, "f10") ) {
return strunicode(0xf70d);
}
if( STREQ(key, "F11") ) {
if( STREQ(key, "f11") ) {
return strunicode(0xf70e);
}
if( STREQ(key, "F12") ) {
if( STREQ(key, "f12") ) {
return strunicode(0xf70f);
}
if( STREQ(key, "F13") ) {
if( STREQ(key, "f13") ) {
return strunicode(0xf710);
}
if( STREQ(key, "F14") ) {
if( STREQ(key, "f14") ) {
return strunicode(0xf711);
}
if( STREQ(key, "F15") ) {
if( STREQ(key, "f15") ) {
return strunicode(0xf712);
}
if( STREQ(key, "F16") ) {
if( STREQ(key, "f16") ) {
return strunicode(0xf713);
}
if( STREQ(key, "F17") ) {
if( STREQ(key, "f17") ) {
return strunicode(0xf714);
}
if( STREQ(key, "F18") ) {
if( STREQ(key, "f18") ) {
return strunicode(0xf715);
}
if( STREQ(key, "F19") ) {
if( STREQ(key, "f19") ) {
return strunicode(0xf716);
}
if( STREQ(key, "F20") ) {
if( STREQ(key, "f20") ) {
return strunicode(0xf717);
}
if( STREQ(key, "F21") ) {
if( STREQ(key, "f21") ) {
return strunicode(0xf718);
}
if( STREQ(key, "F22") ) {
if( STREQ(key, "f22") ) {
return strunicode(0xf719);
}
if( STREQ(key, "F23") ) {
if( STREQ(key, "f23") ) {
return strunicode(0xf71a);
}
if( STREQ(key, "F24") ) {
if( STREQ(key, "f24") ) {
return strunicode(0xf71b);
}
if( STREQ(key, "F25") ) {
if( STREQ(key, "f25") ) {
return strunicode(0xf71c);
}
if( STREQ(key, "F26") ) {
if( STREQ(key, "f26") ) {
return strunicode(0xf71d);
}
if( STREQ(key, "F27") ) {
if( STREQ(key, "f27") ) {
return strunicode(0xf71e);
}
if( STREQ(key, "F28") ) {
if( STREQ(key, "f28") ) {
return strunicode(0xf71f);
}
if( STREQ(key, "F29") ) {
if( STREQ(key, "f29") ) {
return strunicode(0xf720);
}
if( STREQ(key, "F30") ) {
if( STREQ(key, "f30") ) {
return strunicode(0xf721);
}
if( STREQ(key, "F31") ) {
if( STREQ(key, "f31") ) {
return strunicode(0xf722);
}
if( STREQ(key, "F32") ) {
if( STREQ(key, "f32") ) {
return strunicode(0xf723);
}
if( STREQ(key, "F33") ) {
if( STREQ(key, "f33") ) {
return strunicode(0xf724);
}
if( STREQ(key, "F34") ) {
if( STREQ(key, "f34") ) {
return strunicode(0xf725);
}
if( STREQ(key, "F35") ) {
if( STREQ(key, "f35") ) {
return strunicode(0xf726);
}
// if( STREQ(key, "Insert") ) {
@@ -336,7 +336,7 @@ id processAcceleratorKey(const char *key) {
// if( STREQ(key, "ScrollLock") ) {
// return strunicode(0xf72f);
// }
if( STREQ(key, "NumLock") ) {
if( STREQ(key, "numLock") ) {
return strunicode(0xf739);
}
@@ -508,20 +508,21 @@ unsigned long parseModifiers(const char **modifiers) {
const char *thisModifier = modifiers[0];
int count = 0;
while( thisModifier != NULL ) {
// Determine flags
if( STREQ(thisModifier, "CmdOrCtrl") ) {
if( STREQ(thisModifier, "cmdorctrl") ) {
result |= NSEventModifierFlagCommand;
}
if( STREQ(thisModifier, "OptionOrAlt") ) {
if( STREQ(thisModifier, "optionoralt") ) {
result |= NSEventModifierFlagOption;
}
if( STREQ(thisModifier, "Shift") ) {
if( STREQ(thisModifier, "shift") ) {
result |= NSEventModifierFlagShift;
}
if( STREQ(thisModifier, "Super") ) {
if( STREQ(thisModifier, "super") ) {
result |= NSEventModifierFlagCommand;
}
if( STREQ(thisModifier, "Control") ) {
if( STREQ(thisModifier, "ctrl") ) {
result |= NSEventModifierFlagControl;
}
count++;

View File

@@ -48,7 +48,6 @@ void ShowTrayMenusInStore(TrayMenuStore* store) {
}
}
int freeTrayMenu(void *const context, struct hashmap_element_s *const e) {
DeleteTrayMenu(e->data);
return -1;
@@ -81,6 +80,12 @@ TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
return result;
}
void DeleteTrayMenuInStore(TrayMenuStore* store, const char* ID) {
TrayMenu *menu = MustGetTrayMenuFromStore(store, ID);
hashmap_remove(&store->trayMenuMap, ID, strlen(ID));
DeleteTrayMenu(menu);
}
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) {
// Parse the JSON
JsonNode *parsedUpdate = mustParseJSON(JSON);

View File

@@ -23,5 +23,6 @@ void ShowTrayMenusInStore(TrayMenuStore* store);
void DeleteTrayMenuStore(TrayMenuStore* store);
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON);
void DeleteTrayMenuInStore(TrayMenuStore* store, const char* id);
#endif //TRAYMENUSTORE_DARWIN_H

View File

@@ -3,9 +3,10 @@ package menumanager
import (
"encoding/json"
"fmt"
"sync"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/pkg/menu"
"sync"
)
var trayMenuID int
@@ -65,6 +66,14 @@ func (m *Manager) AddTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
return newTrayMenu.AsJSON()
}
func (m *Manager) GetTrayID(trayMenu *menu.TrayMenu) (string, error) {
trayID, exists := m.trayMenuPointers[trayMenu]
if !exists {
return "", fmt.Errorf("Unable to find menu ID for tray menu!")
}
return trayID, nil
}
// SetTrayMenu updates or creates a menu
func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]

View File

@@ -37,6 +37,7 @@ type Client interface {
SetTrayMenu(trayMenuJSON string)
UpdateTrayMenuLabel(JSON string)
UpdateContextMenu(contextMenuJSON string)
DeleteTrayMenuByID(id string)
}
// DispatchClient is what the frontends use to interface with the

View File

@@ -527,6 +527,17 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
for _, client := range d.clients {
client.frontend.UpdateTrayMenuLabel(updatedTrayMenuLabel)
}
case "deletetraymenu":
traymenuid, ok := result.Data().(string)
if !ok {
d.logger.Error("Invalid data for 'menufrontend:updatetraymenulabel' : %#v",
result.Data())
return
}
for _, client := range d.clients {
client.frontend.DeleteTrayMenuByID(traymenuid)
}
default:
d.logger.Error("Unknown menufrontend command: %s", command)

View File

@@ -620,7 +620,7 @@
}
/** Menubar **/
const menuVisible = writable(true);
const menuVisible = writable(false);
/** Trays **/
@@ -1220,11 +1220,11 @@
function get_each_context$1(ctx, list, i) {
const child_ctx = ctx.slice();
child_ctx[8] = list[i];
child_ctx[9] = list[i];
return child_ctx;
}
// (29:0) {#if $menuVisible }
// (38:0) {#if $menuVisible }
function create_if_block$3(ctx) {
let div;
let span1;
@@ -1336,11 +1336,11 @@
};
}
// (32:4) {#each $trays as tray}
// (41:4) {#each $trays as tray}
function create_each_block$1(ctx) {
let traymenu;
let current;
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[8] } });
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[9] } });
return {
c() {
@@ -1352,7 +1352,7 @@
},
p(ctx, dirty) {
const traymenu_changes = {};
if (dirty & /*$trays*/ 4) traymenu_changes.tray = /*tray*/ ctx[8];
if (dirty & /*$trays*/ 4) traymenu_changes.tray = /*tray*/ ctx[9];
traymenu.$set(traymenu_changes);
},
i(local) {
@@ -1373,6 +1373,8 @@
function create_fragment$3(ctx) {
let if_block_anchor;
let current;
let mounted;
let dispose;
let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx);
return {
@@ -1384,6 +1386,11 @@
if (if_block) if_block.m(target, anchor);
insert(target, if_block_anchor, anchor);
current = true;
if (!mounted) {
dispose = listen(window, "keydown", /*handleKeydown*/ ctx[3]);
mounted = true;
}
},
p(ctx, [dirty]) {
if (/*$menuVisible*/ ctx[1]) {
@@ -1421,6 +1428,8 @@
d(detaching) {
if (if_block) if_block.d(detaching);
if (detaching) detach(if_block_anchor);
mounted = false;
dispose();
}
};
}
@@ -1440,7 +1449,7 @@
onMount(() => {
const interval = setInterval(
() => {
$$invalidate(3, time = new Date());
$$invalidate(4, time = new Date());
},
1000
);
@@ -1450,33 +1459,52 @@
};
});
function handleKeydown(e) {
// Backtick toggle
if (e.keyCode == 192) {
menuVisible.update(current => {
return !current;
});
}
}
$$self.$$.update = () => {
if ($$self.$$.dirty & /*time*/ 8) {
$$invalidate(4, day = time.toLocaleString("default", { weekday: "short" }));
if ($$self.$$.dirty & /*time*/ 16) {
$$invalidate(5, day = time.toLocaleString("default", { weekday: "short" }));
}
if ($$self.$$.dirty & /*time*/ 8) {
$$invalidate(5, dom = time.getDate());
if ($$self.$$.dirty & /*time*/ 16) {
$$invalidate(6, dom = time.getDate());
}
if ($$self.$$.dirty & /*time*/ 8) {
$$invalidate(6, mon = time.toLocaleString("default", { month: "short" }));
if ($$self.$$.dirty & /*time*/ 16) {
$$invalidate(7, mon = time.toLocaleString("default", { month: "short" }));
}
if ($$self.$$.dirty & /*time*/ 8) {
$$invalidate(7, currentTime = time.toLocaleString("en-US", {
if ($$self.$$.dirty & /*time*/ 16) {
$$invalidate(8, currentTime = time.toLocaleString("en-US", {
hour: "numeric",
minute: "numeric",
hour12: true
}).toLowerCase());
}
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 240) {
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 480) {
$$invalidate(0, dateTimeString = `${day} ${dom} ${mon} ${currentTime}`);
}
};
return [dateTimeString, $menuVisible, $trays, time, day, dom, mon, currentTime];
return [
dateTimeString,
$menuVisible,
$trays,
handleKeydown,
time,
day,
dom,
mon,
currentTime
];
}
class Menubar extends SvelteComponent {

View File

@@ -1,6 +1,6 @@
{
"name": "@wails/runtime",
"version": "1.3.9",
"version": "1.3.10",
"description": "Wails V2 Javascript runtime library",
"main": "main.js",
"types": "runtime.d.ts",

View File

@@ -24,6 +24,15 @@
};
});
function handleKeydown(e) {
// Backtick toggle
if( e.keyCode == 192 ) {
menuVisible.update( (current) => {
return !current;
});
}
}
</script>
{#if $menuVisible }
@@ -37,6 +46,8 @@
</div>
{/if}
<svelte:window on:keydown={handleKeydown}/>
<style>
.tray-menus {

View File

@@ -13,7 +13,7 @@ export function hideOverlay() {
}
/** Menubar **/
export const menuVisible = writable(true);
export const menuVisible = writable(false);
export function showMenuBar() {
menuVisible.set(true);

View File

@@ -10,6 +10,7 @@ type Menu interface {
UpdateApplicationMenu()
UpdateContextMenu(contextMenu *menu.ContextMenu)
SetTrayMenu(trayMenu *menu.TrayMenu)
DeleteTrayMenu(trayMenu *menu.TrayMenu)
UpdateTrayMenuLabel(trayMenu *menu.TrayMenu)
}
@@ -39,3 +40,7 @@ func (m *menuRuntime) SetTrayMenu(trayMenu *menu.TrayMenu) {
func (m *menuRuntime) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) {
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
}
func (m *menuRuntime) DeleteTrayMenu(trayMenu *menu.TrayMenu) {
m.bus.Publish("menu:deletetraymenu", trayMenu)
}

View File

@@ -6,20 +6,19 @@ import (
// Runtime is a means for the user to interact with the application at runtime
type Runtime struct {
Browser Browser
Events Events
Window Window
Dialog Dialog
System System
Menu Menu
Store *StoreProvider
Log Log
bus *servicebus.ServiceBus
shutdownCallback func()
Browser Browser
Events Events
Window Window
Dialog Dialog
System System
Menu Menu
Store *StoreProvider
Log Log
bus *servicebus.ServiceBus
}
// New creates a new runtime
func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
func New(serviceBus *servicebus.ServiceBus) *Runtime {
result := &Runtime{
Browser: newBrowser(),
Events: newEvents(serviceBus),
@@ -36,11 +35,6 @@ func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
// Quit the application
func (r *Runtime) Quit() {
// Call back to user's shutdown method if defined
if r.shutdownCallback != nil {
r.shutdownCallback()
}
// Start shutdown of Wails
r.bus.Publish("quit", "runtime.Quit()")
}

View File

@@ -26,25 +26,20 @@ type Manager struct {
ctx context.Context
cancel context.CancelFunc
// The shutdown callback to notify the user's app that a shutdown
// has started
shutdownCallback func()
// Parent waitgroup
wg *sync.WaitGroup
}
// NewManager creates a new signal manager
func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.ServiceBus, logger *logger.Logger, shutdownCallback func()) (*Manager, error) {
func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.ServiceBus, logger *logger.Logger) (*Manager, error) {
result := &Manager{
bus: bus,
logger: logger.CustomLogger("Event Manager"),
signalchannel: make(chan os.Signal, 2),
ctx: ctx,
cancel: cancel,
shutdownCallback: shutdownCallback,
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
bus: bus,
logger: logger.CustomLogger("Event Manager"),
signalchannel: make(chan os.Signal, 2),
ctx: ctx,
cancel: cancel,
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
}
return result, nil
@@ -67,11 +62,6 @@ func (m *Manager) Start() {
m.logger.Trace("Ctrl+C detected. Shutting down...")
m.bus.Publish("quit", "ctrl-c pressed")
// Shutdown app first
if m.shutdownCallback != nil {
m.shutdownCallback()
}
// Start shutdown of Wails
m.cancel()

View File

@@ -137,6 +137,17 @@ func (m *Menu) Start() error {
// Notify frontend of menu change
m.bus.Publish("menufrontend:settraymenu", updatedMenu)
case "deletetraymenu":
trayMenu := menuMessage.Data().(*menu.TrayMenu)
trayID, err := m.menuManager.GetTrayID(trayMenu)
if err != nil {
m.logger.Trace("%s", err.Error())
return
}
// Notify frontend of menu change
m.bus.Publish("menufrontend:deletetraymenu", trayID)
case "updatetraymenulabel":
trayMenu := menuMessage.Data().(*menu.TrayMenu)
updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu)

View File

@@ -37,7 +37,7 @@ type Runtime struct {
}
// NewRuntime creates a new runtime subsystem
func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, startupCallback func(*runtime.Runtime), shutdownCallback func()) (*Runtime, error) {
func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, startupCallback func(*runtime.Runtime)) (*Runtime, error) {
// Subscribe to log messages
runtimeChannel, err := bus.Subscribe("runtime:")
@@ -52,13 +52,12 @@ func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.
}
result := &Runtime{
runtimeChannel: runtimeChannel,
hooksChannel: hooksChannel,
logger: logger.CustomLogger("Runtime Subsystem"),
runtime: runtime.New(bus, shutdownCallback),
startupCallback: startupCallback,
shutdownCallback: shutdownCallback,
ctx: ctx,
runtimeChannel: runtimeChannel,
hooksChannel: hooksChannel,
logger: logger.CustomLogger("Runtime Subsystem"),
runtime: runtime.New(bus),
startupCallback: startupCallback,
ctx: ctx,
}
return result, nil

View File

@@ -1,21 +1,43 @@
package keys
import (
"fmt"
"strings"
)
// Modifier is actually a string
type Modifier string
const (
// CmdOrCtrlKey represents Command on Mac and Control on other platforms
CmdOrCtrlKey Modifier = "CmdOrCtrl"
CmdOrCtrlKey Modifier = "cmdorctrl"
// OptionOrAltKey represents Option on Mac and Alt on other platforms
OptionOrAltKey Modifier = "OptionOrAlt"
OptionOrAltKey Modifier = "optionoralt"
// ShiftKey represents the shift key on all systems
ShiftKey Modifier = "Shift"
ShiftKey Modifier = "shift"
// SuperKey represents Command on Mac and the Windows key on the other platforms
SuperKey Modifier = "Super"
SuperKey Modifier = "super"
// ControlKey represents the control key on all systems
ControlKey Modifier = "Control"
ControlKey Modifier = "ctrl"
)
var modifierMap = map[string]Modifier{
"cmdorctrl": CmdOrCtrlKey,
"optionoralt": OptionOrAltKey,
"shift": ShiftKey,
"super": SuperKey,
"ctrl": ControlKey,
}
func parseModifier(text string) (*Modifier, error) {
result, valid := modifierMap[text]
if !valid {
return nil, fmt.Errorf("'%s' is not a valid modifier", text)
}
return &result, nil
}
// Accelerator holds the keyboard shortcut for a menu item
type Accelerator struct {
Key string
@@ -25,14 +47,14 @@ type Accelerator struct {
// Key creates a standard key Accelerator
func Key(key string) *Accelerator {
return &Accelerator{
Key: key,
Key: strings.ToLower(key),
}
}
// CmdOrCtrl creates a 'CmdOrCtrl' Accelerator
func CmdOrCtrl(key string) *Accelerator {
return &Accelerator{
Key: key,
Key: strings.ToLower(key),
Modifiers: []Modifier{CmdOrCtrlKey},
}
}
@@ -40,7 +62,7 @@ func CmdOrCtrl(key string) *Accelerator {
// OptionOrAlt creates a 'OptionOrAlt' Accelerator
func OptionOrAlt(key string) *Accelerator {
return &Accelerator{
Key: key,
Key: strings.ToLower(key),
Modifiers: []Modifier{OptionOrAltKey},
}
}
@@ -48,7 +70,7 @@ func OptionOrAlt(key string) *Accelerator {
// Shift creates a 'Shift' Accelerator
func Shift(key string) *Accelerator {
return &Accelerator{
Key: key,
Key: strings.ToLower(key),
Modifiers: []Modifier{ShiftKey},
}
}
@@ -56,7 +78,7 @@ func Shift(key string) *Accelerator {
// Control creates a 'Control' Accelerator
func Control(key string) *Accelerator {
return &Accelerator{
Key: key,
Key: strings.ToLower(key),
Modifiers: []Modifier{ControlKey},
}
}
@@ -64,7 +86,7 @@ func Control(key string) *Accelerator {
// Super creates a 'Super' Accelerator
func Super(key string) *Accelerator {
return &Accelerator{
Key: key,
Key: strings.ToLower(key),
Modifiers: []Modifier{SuperKey},
}
}

View File

@@ -0,0 +1,90 @@
package keys
import (
"fmt"
"strconv"
"strings"
"github.com/leaanthony/slicer"
)
var namedKeys = slicer.String([]string{"backspace", "tab", "return", "escape", "left", "right", "up", "down", "space", "delete", "home", "end", "page up", "page down", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", "f33", "f34", "f35", "numlock"})
func parseKey(key string) (string, bool) {
// Lowercase!
key = strings.ToLower(key)
// Check special case
if key == "plus" {
return "+", true
}
// Handle named keys
if namedKeys.Contains(key) {
return key, true
}
// Check we only have a single character
if len(key) != 1 {
return "", false
}
runeKey := rune(key[0])
// This may be too inclusive
if strconv.IsPrint(runeKey) {
return key, true
}
return "", false
}
func Parse(shortcut string) (*Accelerator, error) {
var result Accelerator
// Split the shortcut by +
components := strings.Split(shortcut, "+")
// If we only have one it should be a key
// We require components
if len(components) == 0 {
return nil, fmt.Errorf("no components given to validateComponents")
}
// Keep track of modifiers we have processed
var modifiersProcessed slicer.StringSlicer
// Check components
for index, component := range components {
// If last component
if index == len(components)-1 {
processedkey, validKey := parseKey(component)
if !validKey {
return nil, fmt.Errorf("'%s' is not a valid key", component)
}
result.Key = processedkey
continue
}
// Not last component - needs to be modifier
lowercaseComponent := strings.ToLower(component)
thisModifier, valid := modifierMap[lowercaseComponent]
if !valid {
return nil, fmt.Errorf("'%s' is not a valid modifier", component)
}
// Needs to be unique
if modifiersProcessed.Contains(lowercaseComponent) {
return nil, fmt.Errorf("Modifier '%s' is defined twice for shortcut: %s", component, shortcut)
}
// Save this data
result.Modifiers = append(result.Modifiers, thisModifier)
modifiersProcessed.Add(lowercaseComponent)
}
return &result, nil
}

View File

@@ -0,0 +1,38 @@
package keys
import (
"testing"
"github.com/matryer/is"
)
func TestParse(t *testing.T) {
i := is.New(t)
type args struct {
Input string
Expected *Accelerator
}
gooddata := []args{
{"CmdOrCtrl+A", CmdOrCtrl("A")},
{"SHIFT+.", Shift(".")},
{"CTRL+plus", Control("+")},
{"CTRL+SHIFT+escApe", Combo("escape", ControlKey, ShiftKey)},
{";", Key(";")},
{"Super+Tab", Super("tab")},
{"OptionOrAlt+Page Down", OptionOrAlt("Page Down")},
}
for _, tt := range gooddata {
result, err := Parse(tt.Input)
i.NoErr(err)
i.Equal(result, tt.Expected)
}
baddata := []string{"CmdOrCrl+A", "SHIT+.", "CTL+plus", "CTRL+SHIF+esApe", "escap", "Sper+Tab", "OptionOrAlt"}
for _, d := range baddata {
result, err := Parse(d)
i.True(err != nil)
i.Equal(result, "")
}
}

View File

@@ -2,6 +2,14 @@ package mac
import "github.com/wailsapp/wails/v2/pkg/menu"
type ActivationPolicy int
const (
NSApplicationActivationPolicyRegular ActivationPolicy = 0
NSApplicationActivationPolicyAccessory ActivationPolicy = 1
NSApplicationActivationPolicyProhibited ActivationPolicy = 2
)
// Options are options specific to Mac
type Options struct {
TitleBar *TitleBar
@@ -11,4 +19,5 @@ type Options struct {
Menu *menu.Menu
TrayMenus []*menu.TrayMenu
ContextMenus []*menu.ContextMenu
ActivationPolicy ActivationPolicy
}