mirror of
https://github.com/taigrr/wails.git
synced 2026-04-17 04:05:12 -07:00
Compare commits
33 Commits
v2.0.0-alp
...
v2.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9003462457 | ||
|
|
e124f0a220 | ||
|
|
c6d3f57712 | ||
|
|
b4c669ff86 | ||
|
|
2d1b2c0947 | ||
|
|
4a0c5aa785 | ||
|
|
f48d7f8f60 | ||
|
|
651f24f641 | ||
|
|
8fd77148ca | ||
|
|
0dc0762fdf | ||
|
|
1a92550709 | ||
|
|
bffc15bc14 | ||
|
|
198d206c46 | ||
|
|
bb8e848ef6 | ||
|
|
bac3e9e5c1 | ||
|
|
bc5eddeb66 | ||
|
|
8e7258d812 | ||
|
|
7118762cec | ||
|
|
6af92cf0a4 | ||
|
|
1bb91634f7 | ||
|
|
f71ce7913f | ||
|
|
53db687a26 | ||
|
|
13939d3d6b | ||
|
|
552c6b8711 | ||
|
|
feee2b3db2 | ||
|
|
9889c2bdbb | ||
|
|
2432fccf71 | ||
|
|
70510fd180 | ||
|
|
17c6201469 | ||
|
|
0f209c8900 | ||
|
|
cbf043585c | ||
|
|
5ae621ceaa | ||
|
|
1231b59443 |
@@ -57,6 +57,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
keepAssets := false
|
keepAssets := false
|
||||||
command.BoolFlag("k", "Keep generated assets", &keepAssets)
|
command.BoolFlag("k", "Keep generated assets", &keepAssets)
|
||||||
|
|
||||||
|
appleIdentity := ""
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
command.StringFlag("sign", "Signs your app with the given identity.", &appleIdentity)
|
||||||
|
}
|
||||||
|
|
||||||
command.Action(func() error {
|
command.Action(func() error {
|
||||||
|
|
||||||
// Create logger
|
// Create logger
|
||||||
@@ -72,6 +77,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
app.PrintBanner()
|
app.PrintBanner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure package is used with apple identity
|
||||||
|
if appleIdentity != "" && pack == false {
|
||||||
|
return fmt.Errorf("must use `-package` flag when using `-sign`")
|
||||||
|
}
|
||||||
|
|
||||||
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
task := fmt.Sprintf("Building %s Application", strings.Title(outputType))
|
||||||
logger.Println(task)
|
logger.Println(task)
|
||||||
logger.Println(strings.Repeat("-", len(task)))
|
logger.Println(strings.Repeat("-", len(task)))
|
||||||
@@ -84,14 +94,15 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
|||||||
|
|
||||||
// Create BuildOptions
|
// Create BuildOptions
|
||||||
buildOptions := &build.Options{
|
buildOptions := &build.Options{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
OutputType: outputType,
|
OutputType: outputType,
|
||||||
Mode: mode,
|
Mode: mode,
|
||||||
Pack: pack,
|
Pack: pack,
|
||||||
Platform: platform,
|
Platform: platform,
|
||||||
LDFlags: ldflags,
|
LDFlags: ldflags,
|
||||||
Compiler: compilerCommand,
|
Compiler: compilerCommand,
|
||||||
KeepAssets: keepAssets,
|
KeepAssets: keepAssets,
|
||||||
|
AppleIdentity: appleIdentity,
|
||||||
}
|
}
|
||||||
|
|
||||||
return doBuild(buildOptions)
|
return doBuild(buildOptions)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
var version = "v2.0.0-alpha.32"
|
var version = "v2.0.0-alpha.43"
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type App struct {
|
|||||||
//binding *subsystem.Binding
|
//binding *subsystem.Binding
|
||||||
call *subsystem.Call
|
call *subsystem.Call
|
||||||
menu *subsystem.Menu
|
menu *subsystem.Menu
|
||||||
|
url *subsystem.URL
|
||||||
dispatcher *messagedispatcher.Dispatcher
|
dispatcher *messagedispatcher.Dispatcher
|
||||||
|
|
||||||
menuManager *menumanager.Manager
|
menuManager *menumanager.Manager
|
||||||
@@ -117,14 +118,6 @@ func (a *App) Run() error {
|
|||||||
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||||
ctx, cancel := context.WithCancel(parentContext)
|
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
|
// Start the service bus
|
||||||
a.servicebus.Debug()
|
a.servicebus.Debug()
|
||||||
err = a.servicebus.Start()
|
err = a.servicebus.Start()
|
||||||
@@ -132,7 +125,7 @@ func (a *App) Run() error {
|
|||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -168,6 +161,19 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.options.Mac.URLHandlers != nil {
|
||||||
|
// Start the url handler subsystem
|
||||||
|
url, err := subsystem.NewURL(a.servicebus, a.logger, a.options.Mac.URLHandlers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.url = url
|
||||||
|
err = a.url.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the eventing subsystem
|
// Start the eventing subsystem
|
||||||
eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger)
|
eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -207,6 +213,14 @@ func (a *App) Run() error {
|
|||||||
return err
|
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)
|
err = a.window.Run(dispatcher, bindingDump, a.debug)
|
||||||
a.logger.Trace("Ffenestri.Run() exited")
|
a.logger.Trace("Ffenestri.Run() exited")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -231,5 +245,10 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown callback
|
||||||
|
if a.shutdownCallback != nil {
|
||||||
|
a.shutdownCallback()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,14 +118,6 @@ func (a *App) Run() error {
|
|||||||
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||||
ctx, cancel := context.WithCancel(parentContext)
|
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
|
// Start the service bus
|
||||||
a.servicebus.Debug()
|
a.servicebus.Debug()
|
||||||
err = a.servicebus.Start()
|
err = a.servicebus.Start()
|
||||||
@@ -133,7 +125,7 @@ func (a *App) Run() error {
|
|||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -211,6 +203,14 @@ func (a *App) Run() error {
|
|||||||
// Generate backend.js
|
// Generate backend.js
|
||||||
a.bindings.GenerateBackendJS()
|
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)
|
err = a.bridge.Run(dispatcher, a.menuManager, bindingDump, a.debug)
|
||||||
a.logger.Trace("Bridge.Run() exited")
|
a.logger.Trace("Bridge.Run() exited")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -235,6 +235,10 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown callback
|
||||||
|
if a.shutdownCallback != nil {
|
||||||
|
a.shutdownCallback()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ type BridgeClient struct {
|
|||||||
messageCache chan string
|
messageCache chan string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b BridgeClient) DeleteTrayMenuByID(id string) {
|
||||||
|
b.session.sendMessage("TD" + id)
|
||||||
|
}
|
||||||
|
|
||||||
func NewBridgeClient() *BridgeClient {
|
func NewBridgeClient() *BridgeClient {
|
||||||
return &BridgeClient{
|
return &BridgeClient{
|
||||||
messageCache: make(chan string, 100),
|
messageCache: make(chan string, 100),
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ type DialogClient struct {
|
|||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DialogClient) DeleteTrayMenuByID(id string) {
|
||||||
|
}
|
||||||
|
|
||||||
func NewDialogClient(log *logger.Logger) *DialogClient {
|
func NewDialogClient(log *logger.Logger) *DialogClient {
|
||||||
return &DialogClient{
|
return &DialogClient{
|
||||||
log: log,
|
log: log,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ extern void DarkModeEnabled(struct Application*, char *callbackID);
|
|||||||
extern void SetApplicationMenu(struct Application*, const char *);
|
extern void SetApplicationMenu(struct Application*, const char *);
|
||||||
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||||
extern void SetTrayMenu(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 UpdateTrayMenuLabel(struct Application*, const char* JSON);
|
||||||
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
||||||
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
||||||
|
|||||||
@@ -208,3 +208,7 @@ func (c *Client) UpdateTrayMenuLabel(JSON string) {
|
|||||||
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
||||||
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) DeleteTrayMenuByID(id string) {
|
||||||
|
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ int hashmap_log(void *const context, struct hashmap_element_s *const e) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void filelog(const char *message) {
|
||||||
|
FILE *fp = fopen("/tmp/wailslog.txt", "ab");
|
||||||
|
if (fp != NULL)
|
||||||
|
{
|
||||||
|
fputs(message, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utility function to visualise a hashmap
|
// Utility function to visualise a hashmap
|
||||||
void dumpHashmap(const char *name, struct hashmap_s *hashmap) {
|
void dumpHashmap(const char *name, struct hashmap_s *hashmap) {
|
||||||
printf("%s = { ", name);
|
printf("%s = { ", name);
|
||||||
@@ -79,6 +88,7 @@ struct Application {
|
|||||||
id mouseEvent;
|
id mouseEvent;
|
||||||
id mouseDownMonitor;
|
id mouseDownMonitor;
|
||||||
id mouseUpMonitor;
|
id mouseUpMonitor;
|
||||||
|
int activationPolicy;
|
||||||
|
|
||||||
// Window Data
|
// Window Data
|
||||||
const char *title;
|
const char *title;
|
||||||
@@ -112,6 +122,7 @@ struct Application {
|
|||||||
int useToolBar;
|
int useToolBar;
|
||||||
int hideToolbarSeparator;
|
int hideToolbarSeparator;
|
||||||
int windowBackgroundIsTranslucent;
|
int windowBackgroundIsTranslucent;
|
||||||
|
int hasURLHandlers;
|
||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
Menu *applicationMenu;
|
Menu *applicationMenu;
|
||||||
@@ -253,7 +264,7 @@ void Hide(struct Application *app) {
|
|||||||
if( app->shuttingDown ) return;
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
msg(app->application, s("hide:"))
|
msg(app->application, s("hide:"));
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1046,6 +1057,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) {
|
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
|
||||||
// Guard against calling during shutdown
|
// Guard against calling during shutdown
|
||||||
if( app->shuttingDown ) return;
|
if( app->shuttingDown ) return;
|
||||||
@@ -1112,7 +1129,7 @@ void processDecorations(struct Application *app) {
|
|||||||
void createApplication(struct Application *app) {
|
void createApplication(struct Application *app) {
|
||||||
id application = msg(c("NSApplication"), s("sharedApplication"));
|
id application = msg(c("NSApplication"), s("sharedApplication"));
|
||||||
app->application = application;
|
app->application = application;
|
||||||
msg(application, s("setActivationPolicy:"), 0);
|
msg(application, s("setActivationPolicy:"), app->activationPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
||||||
@@ -1136,17 +1153,31 @@ void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getURL(id self, SEL selector, id event, id replyEvent) {
|
||||||
|
id desc = msg(event, s("paramDescriptorForKeyword:"), keyDirectObject);
|
||||||
|
id url = msg(desc, s("stringValue"));
|
||||||
|
const char* curl = cstr(url);
|
||||||
|
const char* message = concat("UC", curl);
|
||||||
|
messageFromWindowCallback(message);
|
||||||
|
MEMFREE(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void createDelegate(struct Application *app) {
|
void createDelegate(struct Application *app) {
|
||||||
// Define delegate
|
// Define delegate
|
||||||
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "AppDelegate", 0);
|
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "AppDelegate", 0);
|
||||||
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSApplicationDelegate"));
|
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSApplicationDelegate"));
|
||||||
class_addMethod(delegateClass, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) no, "c@:@");
|
class_addMethod(delegateClass, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) no, "c@:@");
|
||||||
// class_addMethod(delegateClass, s("applicationWillTerminate:"), (IMP) closeWindow, "v@:@");
|
|
||||||
class_addMethod(delegateClass, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "v@:@");
|
class_addMethod(delegateClass, s("applicationWillFinishLaunching:"), (IMP) willFinishLaunching, "v@:@");
|
||||||
|
|
||||||
// All Menu Items use a common callback
|
// All Menu Items use a common callback
|
||||||
class_addMethod(delegateClass, s("menuItemCallback:"), (IMP)menuItemCallback, "v@:@");
|
class_addMethod(delegateClass, s("menuItemCallback:"), (IMP)menuItemCallback, "v@:@");
|
||||||
|
|
||||||
|
// If there are URL Handlers, register the callback method
|
||||||
|
if( app->hasURLHandlers ) {
|
||||||
|
class_addMethod(delegateClass, s("getUrl:withReplyEvent:"), (IMP) getURL, "i@:@@");
|
||||||
|
}
|
||||||
|
|
||||||
// Script handler
|
// Script handler
|
||||||
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@");
|
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@");
|
||||||
objc_registerClassPair(delegateClass);
|
objc_registerClassPair(delegateClass);
|
||||||
@@ -1155,6 +1186,12 @@ void createDelegate(struct Application *app) {
|
|||||||
id delegate = msg((id)delegateClass, s("new"));
|
id delegate = msg((id)delegateClass, s("new"));
|
||||||
objc_setAssociatedObject(delegate, "application", (id)app, OBJC_ASSOCIATION_ASSIGN);
|
objc_setAssociatedObject(delegate, "application", (id)app, OBJC_ASSOCIATION_ASSIGN);
|
||||||
|
|
||||||
|
// If there are URL Handlers, register a listener for them
|
||||||
|
if( app->hasURLHandlers ) {
|
||||||
|
id eventManager = msg(c("NSAppleEventManager"), s("sharedAppleEventManager"));
|
||||||
|
msg(eventManager, s("setEventHandler:andSelector:forEventClass:andEventID:"), delegate, s("getUrl:withReplyEvent:"), kInternetEventClass, kAEGetURL);
|
||||||
|
}
|
||||||
|
|
||||||
// Theme change listener
|
// Theme change listener
|
||||||
class_addMethod(delegateClass, s("themeChanged:"), (IMP) themeChanged, "v@:@@");
|
class_addMethod(delegateClass, s("themeChanged:"), (IMP) themeChanged, "v@:@@");
|
||||||
|
|
||||||
@@ -1170,13 +1207,19 @@ void createDelegate(struct Application *app) {
|
|||||||
bool windowShouldClose(id self, SEL cmd, id sender) {
|
bool windowShouldClose(id self, SEL cmd, id sender) {
|
||||||
msg(sender, s("orderBack:"));
|
msg(sender, s("orderBack:"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool windowShouldExit(id self, SEL cmd, id sender) {
|
||||||
|
msg(sender, s("orderBack:"));
|
||||||
|
messageFromWindowCallback("WC");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void createMainWindow(struct Application *app) {
|
void createMainWindow(struct Application *app) {
|
||||||
// Create main window
|
// Create main window
|
||||||
id mainWindow = ALLOC("NSWindow");
|
id mainWindow = ALLOC("NSWindow");
|
||||||
mainWindow = msg(mainWindow, s("initWithContentRect:styleMask:backing:defer:"),
|
mainWindow = msg(mainWindow, s("initWithContentRect:styleMask:backing:defer:"),
|
||||||
CGRectMake(0, 0, app->width, app->height), app->decorations, NSBackingStoreBuffered, NO);
|
CGRectMake(0, 0, app->width, app->height), app->decorations, NSBackingStoreBuffered, NO);
|
||||||
msg(mainWindow, s("autorelease"));
|
msg(mainWindow, s("autorelease"));
|
||||||
|
|
||||||
// Set Appearance
|
// Set Appearance
|
||||||
@@ -1190,14 +1233,16 @@ void createMainWindow(struct Application *app) {
|
|||||||
msg(mainWindow, s("setTitlebarAppearsTransparent:"), app->titlebarAppearsTransparent ? YES : NO);
|
msg(mainWindow, s("setTitlebarAppearsTransparent:"), app->titlebarAppearsTransparent ? YES : NO);
|
||||||
msg(mainWindow, s("setTitleVisibility:"), app->hideTitle);
|
msg(mainWindow, s("setTitleVisibility:"), app->hideTitle);
|
||||||
|
|
||||||
if( app->hideWindowOnClose ) {
|
// Create window delegate to override windowShouldClose
|
||||||
// Create window delegate to override windowShouldClose
|
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "WindowDelegate", 0);
|
||||||
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "WindowDelegate", 0);
|
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSWindowDelegate"));
|
||||||
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSWindowDelegate"));
|
if( app->hideWindowOnClose ) {
|
||||||
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldClose, "v@:@");
|
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldClose, "v@:@");
|
||||||
app->windowDelegate = msg((id)delegateClass, s("new"));
|
} else {
|
||||||
msg(mainWindow, s("setDelegate:"), app->windowDelegate);
|
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldExit, "v@:@");
|
||||||
}
|
}
|
||||||
|
app->windowDelegate = msg((id)delegateClass, s("new"));
|
||||||
|
msg(mainWindow, s("setDelegate:"), app->windowDelegate);
|
||||||
|
|
||||||
app->mainWindow = mainWindow;
|
app->mainWindow = mainWindow;
|
||||||
}
|
}
|
||||||
@@ -1812,15 +1857,22 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
MEMFREE(internalCode);
|
MEMFREE(internalCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetActivationPolicy(struct Application* app, int policy) {
|
||||||
|
app->activationPolicy = policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HasURLHandlers(struct Application* app) {
|
||||||
|
app->hasURLHandlers = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Quit will stop the cocoa application and free up all the memory
|
// Quit will stop the cocoa application and free up all the memory
|
||||||
// used by the application
|
// used by the application
|
||||||
void Quit(struct Application *app) {
|
void Quit(struct Application *app) {
|
||||||
Debug(app, "Quit Called");
|
Debug(app, "Quit Called");
|
||||||
msg(app->application, s("stop:"), NULL);
|
msg(app->application, s("stop:"), NULL);
|
||||||
ON_MAIN_THREAD (
|
SetSize(app, 0, 0);
|
||||||
// Terminate app by triggering a UI event
|
Show(app);
|
||||||
SetSize(app, 0, 0);
|
Hide(app);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) {
|
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) {
|
||||||
@@ -1884,6 +1936,10 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
|||||||
|
|
||||||
result->shuttingDown = false;
|
result->shuttingDown = false;
|
||||||
|
|
||||||
|
result->activationPolicy = NSApplicationActivationPolicyRegular;
|
||||||
|
|
||||||
|
result->hasURLHandlers = 0;
|
||||||
|
|
||||||
return (void*) result;
|
return (void*) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ func (a *Application) processPlatformSettings() error {
|
|||||||
C.SetAppearance(a.app, a.string2CString(string(mac.Appearance)))
|
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
|
// Check if the webview should be transparent
|
||||||
if mac.WebviewIsTransparent {
|
if mac.WebviewIsTransparent {
|
||||||
C.WebviewIsTransparent(a.app)
|
C.WebviewIsTransparent(a.app)
|
||||||
@@ -87,5 +90,10 @@ func (a *Application) processPlatformSettings() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process URL Handlers
|
||||||
|
if a.config.Mac.URLHandlers != nil {
|
||||||
|
C.HasURLHandlers(a.app)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
// Macros to make it slightly more sane
|
// Macros to make it slightly more sane
|
||||||
#define msg objc_msgSend
|
#define msg objc_msgSend
|
||||||
|
|
||||||
|
#define kInternetEventClass 'GURL'
|
||||||
|
#define kAEGetURL 'GURL'
|
||||||
|
#define keyDirectObject '----'
|
||||||
|
|
||||||
#define c(str) (id)objc_getClass(str)
|
#define c(str) (id)objc_getClass(str)
|
||||||
#define s(str) sel_registerName(str)
|
#define s(str) sel_registerName(str)
|
||||||
#define u(str) sel_getUid(str)
|
#define u(str) sel_getUid(str)
|
||||||
@@ -66,6 +70,10 @@
|
|||||||
#define NSControlStateValueOff 0
|
#define NSControlStateValueOff 0
|
||||||
#define NSControlStateValueOn 1
|
#define NSControlStateValueOn 1
|
||||||
|
|
||||||
|
#define NSApplicationActivationPolicyRegular 0
|
||||||
|
#define NSApplicationActivationPolicyAccessory 1
|
||||||
|
#define NSApplicationActivationPolicyProhibited 2
|
||||||
|
|
||||||
// Unbelievably, if the user swaps their button preference
|
// Unbelievably, if the user swaps their button preference
|
||||||
// then right buttons are reported as left buttons
|
// then right buttons are reported as left buttons
|
||||||
#define NSEventMaskLeftMouseDown 1 << 1
|
#define NSEventMaskLeftMouseDown 1 << 1
|
||||||
@@ -110,6 +118,10 @@ void SetTray(struct Application* app, const char *, const char *, const char *);
|
|||||||
//void SetContextMenus(struct Application* app, const char *);
|
//void SetContextMenus(struct Application* app, const char *);
|
||||||
void AddTrayMenu(struct Application* app, const char *);
|
void AddTrayMenu(struct Application* app, const char *);
|
||||||
|
|
||||||
|
void SetActivationPolicy(struct Application* app, int policy);
|
||||||
|
|
||||||
void* lookupStringConstant(id constantName);
|
void* lookupStringConstant(id constantName);
|
||||||
|
|
||||||
|
void HasURLHandlers(struct Application* app);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -508,6 +508,7 @@ unsigned long parseModifiers(const char **modifiers) {
|
|||||||
const char *thisModifier = modifiers[0];
|
const char *thisModifier = modifiers[0];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while( thisModifier != NULL ) {
|
while( thisModifier != NULL ) {
|
||||||
|
|
||||||
// Determine flags
|
// Determine flags
|
||||||
if( STREQ(thisModifier, "cmdorctrl") ) {
|
if( STREQ(thisModifier, "cmdorctrl") ) {
|
||||||
result |= NSEventModifierFlagCommand;
|
result |= NSEventModifierFlagCommand;
|
||||||
@@ -521,7 +522,7 @@ unsigned long parseModifiers(const char **modifiers) {
|
|||||||
if( STREQ(thisModifier, "super") ) {
|
if( STREQ(thisModifier, "super") ) {
|
||||||
result |= NSEventModifierFlagCommand;
|
result |= NSEventModifierFlagCommand;
|
||||||
}
|
}
|
||||||
if( STREQ(thisModifier, "control") ) {
|
if( STREQ(thisModifier, "ctrl") ) {
|
||||||
result |= NSEventModifierFlagControl;
|
result |= NSEventModifierFlagControl;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
@@ -575,7 +576,7 @@ id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const c
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage) {
|
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage, bool alternate) {
|
||||||
id item = ALLOC("NSMenuItem");
|
id item = ALLOC("NSMenuItem");
|
||||||
|
|
||||||
// Create a MenuItemCallbackData
|
// Create a MenuItemCallbackData
|
||||||
@@ -584,9 +585,15 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char
|
|||||||
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), callback);
|
id wrappedId = msg(c("NSValue"), s("valueWithPointer:"), callback);
|
||||||
msg(item, s("setRepresentedObject:"), wrappedId);
|
msg(item, s("setRepresentedObject:"), wrappedId);
|
||||||
|
|
||||||
id key = processAcceleratorKey(acceleratorkey);
|
if( !alternate ) {
|
||||||
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title),
|
id key = processAcceleratorKey(acceleratorkey);
|
||||||
s("menuItemCallback:"), key);
|
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title),
|
||||||
|
s("menuItemCallback:"), key);
|
||||||
|
printf("Menuitem title: %s\n", title);
|
||||||
|
} else {
|
||||||
|
msg(item, s("initWithTitle:action:keyEquivalent:"), str(title), s("menuItemCallback:"), str(""));
|
||||||
|
printf("ALT Menuitem title: %s\n", title);
|
||||||
|
}
|
||||||
|
|
||||||
if( tooltip != NULL ) {
|
if( tooltip != NULL ) {
|
||||||
msg(item, s("setToolTip:"), str(tooltip));
|
msg(item, s("setToolTip:"), str(tooltip));
|
||||||
@@ -662,10 +669,16 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char
|
|||||||
msg(item, s("autorelease"));
|
msg(item, s("autorelease"));
|
||||||
|
|
||||||
// Process modifiers
|
// Process modifiers
|
||||||
if( modifiers != NULL ) {
|
if( modifiers != NULL && !alternate) {
|
||||||
unsigned long modifierFlags = parseModifiers(modifiers);
|
unsigned long modifierFlags = parseModifiers(modifiers);
|
||||||
msg(item, s("setKeyEquivalentModifierMask:"), modifierFlags);
|
msg(item, s("setKeyEquivalentModifierMask:"), modifierFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alternate
|
||||||
|
if( alternate ) {
|
||||||
|
msg(item, s("setAlternate:"), true);
|
||||||
|
msg(item, s("setKeyEquivalentModifierMask:"), NSEventModifierFlagOption);
|
||||||
|
}
|
||||||
msg(parentMenu, s("addItem:"), item);
|
msg(parentMenu, s("addItem:"), item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -726,6 +739,11 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
|||||||
label = "(empty)";
|
label = "(empty)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Is this an alternate menu item?
|
||||||
|
bool alternate = false;
|
||||||
|
getJSONBool(item, "MacAlternate", &alternate);
|
||||||
|
|
||||||
const char *menuid = getJSONString(item, "ID");
|
const char *menuid = getJSONString(item, "ID");
|
||||||
if ( menuid == NULL) {
|
if ( menuid == NULL) {
|
||||||
menuid = "";
|
menuid = "";
|
||||||
@@ -781,7 +799,7 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
|||||||
if( type != NULL ) {
|
if( type != NULL ) {
|
||||||
|
|
||||||
if( STREQ(type->string_, "Text")) {
|
if( STREQ(type->string_, "Text")) {
|
||||||
processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA, templateImage);
|
processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA, templateImage, alternate);
|
||||||
}
|
}
|
||||||
else if ( STREQ(type->string_, "Separator")) {
|
else if ( STREQ(type->string_, "Separator")) {
|
||||||
addSeparator(parentMenu);
|
addSeparator(parentMenu);
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char
|
|||||||
|
|
||||||
id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key);
|
id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key);
|
||||||
|
|
||||||
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage);
|
id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA, bool templateImage, bool alternate);
|
||||||
void processMenuItem(Menu *menu, id parentMenu, JsonNode *item);
|
void processMenuItem(Menu *menu, id parentMenu, JsonNode *item);
|
||||||
void processMenuData(Menu *menu, JsonNode *menuData);
|
void processMenuData(Menu *menu, JsonNode *menuData);
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ TrayMenuStore* NewTrayMenuStore() {
|
|||||||
ABORT("[NewTrayMenuStore] Not enough memory to allocate trayMenuMap!");
|
ABORT("[NewTrayMenuStore] Not enough memory to allocate trayMenuMap!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pthread_mutex_init(&result->lock, NULL) != 0) {
|
||||||
|
printf("\n mutex init has failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,15 +30,19 @@ int dumpTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DumpTrayMenuStore(TrayMenuStore* store) {
|
void DumpTrayMenuStore(TrayMenuStore* store) {
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_iterate_pairs(&store->trayMenuMap, dumpTrayMenu, NULL);
|
hashmap_iterate_pairs(&store->trayMenuMap, dumpTrayMenu, NULL);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) {
|
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) {
|
||||||
|
|
||||||
TrayMenu* newMenu = NewTrayMenu(menuJSON);
|
TrayMenu* newMenu = NewTrayMenu(menuJSON);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
//TODO: check if there is already an entry for this menu
|
//TODO: check if there is already an entry for this menu
|
||||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
||||||
@@ -43,12 +52,13 @@ int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ShowTrayMenusInStore(TrayMenuStore* store) {
|
void ShowTrayMenusInStore(TrayMenuStore* store) {
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
if( hashmap_num_entries(&store->trayMenuMap) > 0 ) {
|
if( hashmap_num_entries(&store->trayMenuMap) > 0 ) {
|
||||||
hashmap_iterate_pairs(&store->trayMenuMap, showTrayMenu, NULL);
|
hashmap_iterate_pairs(&store->trayMenuMap, showTrayMenu, NULL);
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int freeTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
int freeTrayMenu(void *const context, struct hashmap_element_s *const e) {
|
||||||
DeleteTrayMenu(e->data);
|
DeleteTrayMenu(e->data);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -65,22 +75,39 @@ void DeleteTrayMenuStore(TrayMenuStore *store) {
|
|||||||
|
|
||||||
// Destroy tray menu map
|
// Destroy tray menu map
|
||||||
hashmap_destroy(&store->trayMenuMap);
|
hashmap_destroy(&store->trayMenuMap);
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&store->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrayMenu* GetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
TrayMenu* GetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
||||||
// Get the current menu
|
// Get the current menu
|
||||||
return hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
pthread_mutex_lock(&store->lock);
|
||||||
|
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
TrayMenu* MustGetTrayMenuFromStore(TrayMenuStore* store, const char* menuID) {
|
||||||
// Get the current menu
|
// Get the current menu
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
TrayMenu* result = hashmap_get(&store->trayMenuMap, menuID, strlen(menuID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
if (result == NULL ) {
|
if (result == NULL ) {
|
||||||
ABORT("Unable to find TrayMenu with ID '%s' in the TrayMenuStore!", menuID);
|
ABORT("Unable to find TrayMenu with ID '%s' in the TrayMenuStore!", menuID);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeleteTrayMenuInStore(TrayMenuStore* store, const char* ID) {
|
||||||
|
|
||||||
|
TrayMenu *menu = MustGetTrayMenuFromStore(store, ID);
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
|
hashmap_remove(&store->trayMenuMap, ID, strlen(ID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
DeleteTrayMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) {
|
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) {
|
||||||
// Parse the JSON
|
// Parse the JSON
|
||||||
JsonNode *parsedUpdate = mustParseJSON(JSON);
|
JsonNode *parsedUpdate = mustParseJSON(JSON);
|
||||||
@@ -105,7 +132,9 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
|||||||
// If we don't have a menu, we create one
|
// If we don't have a menu, we create one
|
||||||
if ( currentMenu == NULL ) {
|
if ( currentMenu == NULL ) {
|
||||||
// Store the new menu
|
// Store the new menu
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
// Show it
|
// Show it
|
||||||
ShowTrayMenu(newMenu);
|
ShowTrayMenu(newMenu);
|
||||||
@@ -116,7 +145,9 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
|||||||
// Save the status bar reference
|
// Save the status bar reference
|
||||||
newMenu->statusbaritem = currentMenu->statusbaritem;
|
newMenu->statusbaritem = currentMenu->statusbaritem;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_remove(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID));
|
hashmap_remove(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID));
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
// Delete the current menu
|
// Delete the current menu
|
||||||
DeleteMenu(currentMenu->menu);
|
DeleteMenu(currentMenu->menu);
|
||||||
@@ -125,9 +156,10 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) {
|
|||||||
// Free the tray menu memory
|
// Free the tray menu memory
|
||||||
MEMFREE(currentMenu);
|
MEMFREE(currentMenu);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&store->lock);
|
||||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||||
|
pthread_mutex_unlock(&store->lock);
|
||||||
|
|
||||||
// Show the updated menu
|
// Show the updated menu
|
||||||
ShowTrayMenu(newMenu);
|
ShowTrayMenu(newMenu);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#ifndef TRAYMENUSTORE_DARWIN_H
|
#ifndef TRAYMENUSTORE_DARWIN_H
|
||||||
#define TRAYMENUSTORE_DARWIN_H
|
#define TRAYMENUSTORE_DARWIN_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
int dummy;
|
int dummy;
|
||||||
@@ -13,6 +15,8 @@ typedef struct {
|
|||||||
// It maps tray IDs to TrayMenu*
|
// It maps tray IDs to TrayMenu*
|
||||||
struct hashmap_s trayMenuMap;
|
struct hashmap_s trayMenuMap;
|
||||||
|
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
|
||||||
} TrayMenuStore;
|
} TrayMenuStore;
|
||||||
|
|
||||||
TrayMenuStore* NewTrayMenuStore();
|
TrayMenuStore* NewTrayMenuStore();
|
||||||
@@ -23,5 +27,6 @@ void ShowTrayMenusInStore(TrayMenuStore* store);
|
|||||||
void DeleteTrayMenuStore(TrayMenuStore* store);
|
void DeleteTrayMenuStore(TrayMenuStore* store);
|
||||||
|
|
||||||
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON);
|
void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON);
|
||||||
|
void DeleteTrayMenuInStore(TrayMenuStore* store, const char* id);
|
||||||
|
|
||||||
#endif //TRAYMENUSTORE_DARWIN_H
|
#endif //TRAYMENUSTORE_DARWIN_H
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func Mkdir(dirname string) error {
|
|||||||
// Returns error on failure
|
// Returns error on failure
|
||||||
func MkDirs(fullPath string, mode ...os.FileMode) error {
|
func MkDirs(fullPath string, mode ...os.FileMode) error {
|
||||||
var perms os.FileMode
|
var perms os.FileMode
|
||||||
perms = 0700
|
perms = 0755
|
||||||
if len(mode) == 1 {
|
if len(mode) == 1 {
|
||||||
perms = mode[0]
|
perms = mode[0]
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ func CopyDir(src string, dst string) (err error) {
|
|||||||
return fmt.Errorf("destination already exists")
|
return fmt.Errorf("destination already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(dst, si.Mode())
|
err = MkDirs(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type ProcessedMenuItem struct {
|
|||||||
// Image - base64 image data
|
// Image - base64 image data
|
||||||
Image string `json:",omitempty"`
|
Image string `json:",omitempty"`
|
||||||
MacTemplateImage bool `json:", omitempty"`
|
MacTemplateImage bool `json:", omitempty"`
|
||||||
|
MacAlternate bool `json:", omitempty"`
|
||||||
|
|
||||||
// Tooltip
|
// Tooltip
|
||||||
Tooltip string `json:",omitempty"`
|
Tooltip string `json:",omitempty"`
|
||||||
@@ -60,6 +61,7 @@ func NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *Pr
|
|||||||
FontName: menuItem.FontName,
|
FontName: menuItem.FontName,
|
||||||
Image: menuItem.Image,
|
Image: menuItem.Image,
|
||||||
MacTemplateImage: menuItem.MacTemplateImage,
|
MacTemplateImage: menuItem.MacTemplateImage,
|
||||||
|
MacAlternate: menuItem.MacAlternate,
|
||||||
Tooltip: menuItem.Tooltip,
|
Tooltip: menuItem.Tooltip,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,20 +3,23 @@ package menumanager
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var trayMenuID int
|
var trayMenuID int
|
||||||
var trayMenuIDMutex sync.Mutex
|
var trayMenuIDMutex sync.Mutex
|
||||||
|
|
||||||
func generateTrayID() string {
|
func generateTrayID() string {
|
||||||
|
var idStr string
|
||||||
trayMenuIDMutex.Lock()
|
trayMenuIDMutex.Lock()
|
||||||
result := fmt.Sprintf("%d", trayMenuID)
|
idStr = strconv.Itoa(trayMenuID)
|
||||||
trayMenuID++
|
trayMenuID++
|
||||||
trayMenuIDMutex.Unlock()
|
trayMenuIDMutex.Unlock()
|
||||||
return result
|
return idStr
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrayMenu struct {
|
type TrayMenu struct {
|
||||||
@@ -65,6 +68,14 @@ func (m *Manager) AddTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
|||||||
return newTrayMenu.AsJSON()
|
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
|
// SetTrayMenu updates or creates a menu
|
||||||
func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
func (m *Manager) SetTrayMenu(trayMenu *menu.TrayMenu) (string, error) {
|
||||||
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
trayID, trayMenuKnown := m.trayMenuPointers[trayMenu]
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type Client interface {
|
|||||||
SetTrayMenu(trayMenuJSON string)
|
SetTrayMenu(trayMenuJSON string)
|
||||||
UpdateTrayMenuLabel(JSON string)
|
UpdateTrayMenuLabel(JSON string)
|
||||||
UpdateContextMenu(contextMenuJSON string)
|
UpdateContextMenu(contextMenuJSON string)
|
||||||
|
DeleteTrayMenuByID(id string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DispatchClient is what the frontends use to interface with the
|
// DispatchClient is what the frontends use to interface with the
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ var messageParsers = map[byte]func(string) (*parsedMessage, error){
|
|||||||
'M': menuMessageParser,
|
'M': menuMessageParser,
|
||||||
'T': trayMessageParser,
|
'T': trayMessageParser,
|
||||||
'X': contextMenusMessageParser,
|
'X': contextMenusMessageParser,
|
||||||
|
'U': urlMessageParser,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse will attempt to parse the given message
|
// Parse will attempt to parse the given message
|
||||||
func Parse(message string) (*parsedMessage, error) {
|
func Parse(message string) (*parsedMessage, error) {
|
||||||
|
|
||||||
if len(message) == 0 {
|
if len(message) == 0 {
|
||||||
return nil, fmt.Errorf("MessageParser received blank message");
|
return nil, fmt.Errorf("MessageParser received blank message")
|
||||||
}
|
}
|
||||||
|
|
||||||
parseMethod := messageParsers[message[0]]
|
parseMethod := messageParsers[message[0]]
|
||||||
|
|||||||
20
v2/internal/messagedispatcher/message/url.go
Normal file
20
v2/internal/messagedispatcher/message/url.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package message
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// urlMessageParser does what it says on the tin!
|
||||||
|
func urlMessageParser(message string) (*parsedMessage, error) {
|
||||||
|
|
||||||
|
// Sanity check: URL messages must be at least 2 bytes
|
||||||
|
if len(message) < 2 {
|
||||||
|
return nil, fmt.Errorf("log message was an invalid length")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch on the log type
|
||||||
|
switch message[1] {
|
||||||
|
case 'C':
|
||||||
|
return &parsedMessage{Topic: "url:handler", Data: message[2:]}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("url message type '%c' invalid", message[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -527,6 +527,17 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
|||||||
for _, client := range d.clients {
|
for _, client := range d.clients {
|
||||||
client.frontend.UpdateTrayMenuLabel(updatedTrayMenuLabel)
|
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:
|
default:
|
||||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||||
|
|||||||
@@ -620,7 +620,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Menubar **/
|
/** Menubar **/
|
||||||
const menuVisible = writable(true);
|
const menuVisible = writable(false);
|
||||||
|
|
||||||
/** Trays **/
|
/** Trays **/
|
||||||
|
|
||||||
@@ -649,6 +649,18 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteTrayMenu(id) {
|
||||||
|
trays.update((current) => {
|
||||||
|
// Remove existing if it exists, else add
|
||||||
|
const index = current.findIndex(item => item.ID === id);
|
||||||
|
if ( index === -1 ) {
|
||||||
|
return log("ERROR: Attempted to delete tray index ")
|
||||||
|
}
|
||||||
|
current.splice(index, 1);
|
||||||
|
return current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let selectedMenu = writable(null);
|
let selectedMenu = writable(null);
|
||||||
|
|
||||||
function fade(node, { delay = 0, duration = 400, easing = identity } = {}) {
|
function fade(node, { delay = 0, duration = 400, easing = identity } = {}) {
|
||||||
@@ -1220,11 +1232,11 @@
|
|||||||
|
|
||||||
function get_each_context$1(ctx, list, i) {
|
function get_each_context$1(ctx, list, i) {
|
||||||
const child_ctx = ctx.slice();
|
const child_ctx = ctx.slice();
|
||||||
child_ctx[8] = list[i];
|
child_ctx[9] = list[i];
|
||||||
return child_ctx;
|
return child_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (29:0) {#if $menuVisible }
|
// (38:0) {#if $menuVisible }
|
||||||
function create_if_block$3(ctx) {
|
function create_if_block$3(ctx) {
|
||||||
let div;
|
let div;
|
||||||
let span1;
|
let span1;
|
||||||
@@ -1336,11 +1348,11 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// (32:4) {#each $trays as tray}
|
// (41:4) {#each $trays as tray}
|
||||||
function create_each_block$1(ctx) {
|
function create_each_block$1(ctx) {
|
||||||
let traymenu;
|
let traymenu;
|
||||||
let current;
|
let current;
|
||||||
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[8] } });
|
traymenu = new TrayMenu({ props: { tray: /*tray*/ ctx[9] } });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
c() {
|
c() {
|
||||||
@@ -1352,7 +1364,7 @@
|
|||||||
},
|
},
|
||||||
p(ctx, dirty) {
|
p(ctx, dirty) {
|
||||||
const traymenu_changes = {};
|
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);
|
traymenu.$set(traymenu_changes);
|
||||||
},
|
},
|
||||||
i(local) {
|
i(local) {
|
||||||
@@ -1373,6 +1385,8 @@
|
|||||||
function create_fragment$3(ctx) {
|
function create_fragment$3(ctx) {
|
||||||
let if_block_anchor;
|
let if_block_anchor;
|
||||||
let current;
|
let current;
|
||||||
|
let mounted;
|
||||||
|
let dispose;
|
||||||
let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx);
|
let if_block = /*$menuVisible*/ ctx[1] && create_if_block$3(ctx);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -1384,6 +1398,11 @@
|
|||||||
if (if_block) if_block.m(target, anchor);
|
if (if_block) if_block.m(target, anchor);
|
||||||
insert(target, if_block_anchor, anchor);
|
insert(target, if_block_anchor, anchor);
|
||||||
current = true;
|
current = true;
|
||||||
|
|
||||||
|
if (!mounted) {
|
||||||
|
dispose = listen(window, "keydown", /*handleKeydown*/ ctx[3]);
|
||||||
|
mounted = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
p(ctx, [dirty]) {
|
p(ctx, [dirty]) {
|
||||||
if (/*$menuVisible*/ ctx[1]) {
|
if (/*$menuVisible*/ ctx[1]) {
|
||||||
@@ -1421,6 +1440,8 @@
|
|||||||
d(detaching) {
|
d(detaching) {
|
||||||
if (if_block) if_block.d(detaching);
|
if (if_block) if_block.d(detaching);
|
||||||
if (detaching) detach(if_block_anchor);
|
if (detaching) detach(if_block_anchor);
|
||||||
|
mounted = false;
|
||||||
|
dispose();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1440,7 +1461,7 @@
|
|||||||
onMount(() => {
|
onMount(() => {
|
||||||
const interval = setInterval(
|
const interval = setInterval(
|
||||||
() => {
|
() => {
|
||||||
$$invalidate(3, time = new Date());
|
$$invalidate(4, time = new Date());
|
||||||
},
|
},
|
||||||
1000
|
1000
|
||||||
);
|
);
|
||||||
@@ -1450,33 +1471,52 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleKeydown(e) {
|
||||||
|
// Backtick toggle
|
||||||
|
if (e.keyCode == 192) {
|
||||||
|
menuVisible.update(current => {
|
||||||
|
return !current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$$self.$$.update = () => {
|
$$self.$$.update = () => {
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(4, day = time.toLocaleString("default", { weekday: "short" }));
|
$$invalidate(5, day = time.toLocaleString("default", { weekday: "short" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(5, dom = time.getDate());
|
$$invalidate(6, dom = time.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(6, mon = time.toLocaleString("default", { month: "short" }));
|
$$invalidate(7, mon = time.toLocaleString("default", { month: "short" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*time*/ 8) {
|
if ($$self.$$.dirty & /*time*/ 16) {
|
||||||
$$invalidate(7, currentTime = time.toLocaleString("en-US", {
|
$$invalidate(8, currentTime = time.toLocaleString("en-US", {
|
||||||
hour: "numeric",
|
hour: "numeric",
|
||||||
minute: "numeric",
|
minute: "numeric",
|
||||||
hour12: true
|
hour12: true
|
||||||
}).toLowerCase());
|
}).toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 240) {
|
if ($$self.$$.dirty & /*day, dom, mon, currentTime*/ 480) {
|
||||||
$$invalidate(0, dateTimeString = `${day} ${dom} ${mon} ${currentTime}`);
|
$$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 {
|
class Menubar extends SvelteComponent {
|
||||||
@@ -1638,6 +1678,11 @@
|
|||||||
let trayLabelData = JSON.parse(updateTrayLabelJSON);
|
let trayLabelData = JSON.parse(updateTrayLabelJSON);
|
||||||
updateTrayLabel(trayLabelData);
|
updateTrayLabel(trayLabelData);
|
||||||
break
|
break
|
||||||
|
case 'D':
|
||||||
|
// Delete Tray Menu
|
||||||
|
const id = trayMessage.slice(1);
|
||||||
|
deleteTrayMenu(id);
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
log('Unknown tray message: ' + message.data);
|
log('Unknown tray message: ' + message.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wails/runtime",
|
"name": "@wails/runtime",
|
||||||
"version": "1.3.9",
|
"version": "1.3.12",
|
||||||
"description": "Wails V2 Javascript runtime library",
|
"description": "Wails V2 Javascript runtime library",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"types": "runtime.d.ts",
|
"types": "runtime.d.ts",
|
||||||
|
|||||||
@@ -24,6 +24,15 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleKeydown(e) {
|
||||||
|
// Backtick toggle
|
||||||
|
if( e.keyCode == 192 ) {
|
||||||
|
menuVisible.update( (current) => {
|
||||||
|
return !current;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $menuVisible }
|
{#if $menuVisible }
|
||||||
@@ -37,6 +46,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<svelte:window on:keydown={handleKeydown}/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
.tray-menus {
|
.tray-menus {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export function hideOverlay() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Menubar **/
|
/** Menubar **/
|
||||||
export const menuVisible = writable(true);
|
export const menuVisible = writable(false);
|
||||||
|
|
||||||
export function showMenuBar() {
|
export function showMenuBar() {
|
||||||
menuVisible.set(true);
|
menuVisible.set(true);
|
||||||
@@ -49,4 +49,16 @@ export function updateTrayLabel(tray) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteTrayMenu(id) {
|
||||||
|
trays.update((current) => {
|
||||||
|
// Remove existing if it exists, else add
|
||||||
|
const index = current.findIndex(item => item.ID === id);
|
||||||
|
if ( index === -1 ) {
|
||||||
|
return log("ERROR: Attempted to delete tray index ", id, "but it doesn't exist")
|
||||||
|
}
|
||||||
|
current.splice(index, 1);
|
||||||
|
return current;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export let selectedMenu = writable(null);
|
export let selectedMenu = writable(null);
|
||||||
@@ -10,7 +10,7 @@ The lightweight framework for web-like apps
|
|||||||
/* jshint esversion: 6 */
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
|
||||||
import {setTray, hideOverlay, showOverlay, updateTrayLabel} from "./store";
|
import {setTray, hideOverlay, showOverlay, updateTrayLabel, deleteTrayMenu} from "./store";
|
||||||
import {log} from "./log";
|
import {log} from "./log";
|
||||||
|
|
||||||
let websocket = null;
|
let websocket = null;
|
||||||
@@ -154,6 +154,11 @@ function handleMessage(message) {
|
|||||||
let trayLabelData = JSON.parse(updateTrayLabelJSON)
|
let trayLabelData = JSON.parse(updateTrayLabelJSON)
|
||||||
updateTrayLabel(trayLabelData)
|
updateTrayLabel(trayLabelData)
|
||||||
break
|
break
|
||||||
|
case 'D':
|
||||||
|
// Delete Tray Menu
|
||||||
|
const id = trayMessage.slice(1);
|
||||||
|
deleteTrayMenu(id)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
log('Unknown tray message: ' + message.data);
|
log('Unknown tray message: ' + message.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type Menu interface {
|
|||||||
UpdateApplicationMenu()
|
UpdateApplicationMenu()
|
||||||
UpdateContextMenu(contextMenu *menu.ContextMenu)
|
UpdateContextMenu(contextMenu *menu.ContextMenu)
|
||||||
SetTrayMenu(trayMenu *menu.TrayMenu)
|
SetTrayMenu(trayMenu *menu.TrayMenu)
|
||||||
|
DeleteTrayMenu(trayMenu *menu.TrayMenu)
|
||||||
UpdateTrayMenuLabel(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) {
|
func (m *menuRuntime) UpdateTrayMenuLabel(trayMenu *menu.TrayMenu) {
|
||||||
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
|
m.bus.Publish("menu:updatetraymenulabel", trayMenu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *menuRuntime) DeleteTrayMenu(trayMenu *menu.TrayMenu) {
|
||||||
|
m.bus.Publish("menu:deletetraymenu", trayMenu)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,20 +6,19 @@ import (
|
|||||||
|
|
||||||
// Runtime is a means for the user to interact with the application at runtime
|
// Runtime is a means for the user to interact with the application at runtime
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
Browser Browser
|
Browser Browser
|
||||||
Events Events
|
Events Events
|
||||||
Window Window
|
Window Window
|
||||||
Dialog Dialog
|
Dialog Dialog
|
||||||
System System
|
System System
|
||||||
Menu Menu
|
Menu Menu
|
||||||
Store *StoreProvider
|
Store *StoreProvider
|
||||||
Log Log
|
Log Log
|
||||||
bus *servicebus.ServiceBus
|
bus *servicebus.ServiceBus
|
||||||
shutdownCallback func()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new runtime
|
// New creates a new runtime
|
||||||
func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
|
func New(serviceBus *servicebus.ServiceBus) *Runtime {
|
||||||
result := &Runtime{
|
result := &Runtime{
|
||||||
Browser: newBrowser(),
|
Browser: newBrowser(),
|
||||||
Events: newEvents(serviceBus),
|
Events: newEvents(serviceBus),
|
||||||
@@ -36,11 +35,6 @@ func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
|
|||||||
|
|
||||||
// Quit the application
|
// Quit the application
|
||||||
func (r *Runtime) Quit() {
|
func (r *Runtime) Quit() {
|
||||||
// Call back to user's shutdown method if defined
|
|
||||||
if r.shutdownCallback != nil {
|
|
||||||
r.shutdownCallback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start shutdown of Wails
|
// Start shutdown of Wails
|
||||||
r.bus.Publish("quit", "runtime.Quit()")
|
r.bus.Publish("quit", "runtime.Quit()")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,25 +26,20 @@ type Manager struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
||||||
// The shutdown callback to notify the user's app that a shutdown
|
|
||||||
// has started
|
|
||||||
shutdownCallback func()
|
|
||||||
|
|
||||||
// Parent waitgroup
|
// Parent waitgroup
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new signal manager
|
// 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{
|
result := &Manager{
|
||||||
bus: bus,
|
bus: bus,
|
||||||
logger: logger.CustomLogger("Event Manager"),
|
logger: logger.CustomLogger("Event Manager"),
|
||||||
signalchannel: make(chan os.Signal, 2),
|
signalchannel: make(chan os.Signal, 2),
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
shutdownCallback: shutdownCallback,
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -67,11 +62,6 @@ func (m *Manager) Start() {
|
|||||||
m.logger.Trace("Ctrl+C detected. Shutting down...")
|
m.logger.Trace("Ctrl+C detected. Shutting down...")
|
||||||
m.bus.Publish("quit", "ctrl-c pressed")
|
m.bus.Publish("quit", "ctrl-c pressed")
|
||||||
|
|
||||||
// Shutdown app first
|
|
||||||
if m.shutdownCallback != nil {
|
|
||||||
m.shutdownCallback()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start shutdown of Wails
|
// Start shutdown of Wails
|
||||||
m.cancel()
|
m.cancel()
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,17 @@ func (m *Menu) Start() error {
|
|||||||
// Notify frontend of menu change
|
// Notify frontend of menu change
|
||||||
m.bus.Publish("menufrontend:settraymenu", updatedMenu)
|
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":
|
case "updatetraymenulabel":
|
||||||
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
||||||
updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu)
|
updatedLabel, err := m.menuManager.UpdateTrayMenuLabel(trayMenu)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ type Runtime struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewRuntime creates a new runtime subsystem
|
// 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
|
// Subscribe to log messages
|
||||||
runtimeChannel, err := bus.Subscribe("runtime:")
|
runtimeChannel, err := bus.Subscribe("runtime:")
|
||||||
@@ -52,13 +52,12 @@ func NewRuntime(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Runtime{
|
result := &Runtime{
|
||||||
runtimeChannel: runtimeChannel,
|
runtimeChannel: runtimeChannel,
|
||||||
hooksChannel: hooksChannel,
|
hooksChannel: hooksChannel,
|
||||||
logger: logger.CustomLogger("Runtime Subsystem"),
|
logger: logger.CustomLogger("Runtime Subsystem"),
|
||||||
runtime: runtime.New(bus, shutdownCallback),
|
runtime: runtime.New(bus),
|
||||||
startupCallback: startupCallback,
|
startupCallback: startupCallback,
|
||||||
shutdownCallback: shutdownCallback,
|
ctx: ctx,
|
||||||
ctx: ctx,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
94
v2/internal/subsystem/url.go
Normal file
94
v2/internal/subsystem/url.go
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package subsystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URL is the URL Handler subsystem. It handles messages with topics starting
|
||||||
|
// with "url:"
|
||||||
|
type URL struct {
|
||||||
|
urlChannel <-chan *servicebus.Message
|
||||||
|
|
||||||
|
// quit flag
|
||||||
|
shouldQuit bool
|
||||||
|
|
||||||
|
// Logger!
|
||||||
|
logger *logger.Logger
|
||||||
|
|
||||||
|
// Context for shutdown
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
|
||||||
|
// internal waitgroup
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
handlers map[string]func(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewURL creates a new log subsystem
|
||||||
|
func NewURL(bus *servicebus.ServiceBus, logger *logger.Logger, handlers map[string]func(string)) (*URL, error) {
|
||||||
|
|
||||||
|
// Subscribe to log messages
|
||||||
|
urlChannel, err := bus.Subscribe("url")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
result := &URL{
|
||||||
|
urlChannel: urlChannel,
|
||||||
|
logger: logger,
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
handlers: handlers,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the subsystem
|
||||||
|
func (u *URL) Start() error {
|
||||||
|
|
||||||
|
u.wg.Add(1)
|
||||||
|
|
||||||
|
// Spin off a go routine
|
||||||
|
go func() {
|
||||||
|
defer u.logger.Trace("URL Shutdown")
|
||||||
|
|
||||||
|
for u.shouldQuit == false {
|
||||||
|
select {
|
||||||
|
case <-u.ctx.Done():
|
||||||
|
u.wg.Done()
|
||||||
|
return
|
||||||
|
case urlMessage := <-u.urlChannel:
|
||||||
|
messageType := strings.TrimPrefix(urlMessage.Topic(), "url:")
|
||||||
|
switch messageType {
|
||||||
|
case "handler":
|
||||||
|
url := urlMessage.Data().(string)
|
||||||
|
splitURL := strings.Split(url, ":")
|
||||||
|
protocol := splitURL[0]
|
||||||
|
callback, ok := u.handlers[protocol]
|
||||||
|
if ok {
|
||||||
|
go callback(url)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
u.logger.Error("unknown url message: %+v", urlMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *URL) Close() {
|
||||||
|
u.cancel()
|
||||||
|
u.wg.Wait()
|
||||||
|
}
|
||||||
@@ -12,20 +12,19 @@ type Basic struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newBasic creates a new Basic application struct
|
// newBasic creates a new Basic application struct
|
||||||
func newBasic() *Basic {
|
func NewBasic() *Basic {
|
||||||
return &Basic{}
|
return &Basic{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WailsInit is called at application startup
|
// startup is called at application startup
|
||||||
func (b *Basic) WailsInit(runtime *wails.Runtime) error {
|
func (b *Basic) startup(runtime *wails.Runtime) {
|
||||||
// Perform your setup here
|
// Perform your setup here
|
||||||
b.runtime = runtime
|
b.runtime = runtime
|
||||||
runtime.Window.SetTitle("{{.ProjectName}}")
|
runtime.Window.SetTitle("{{.ProjectName}}")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WailsShutdown is called at application termination
|
// shutdown is called at application termination
|
||||||
func (b *Basic) WailsShutdown() {
|
func (b *Basic) shutdown() {
|
||||||
// Perform your teardown here
|
// Perform your teardown here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<link rel="stylesheet" href="/main.css">
|
<link rel="stylesheet" href="/main.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body data-wails-drag>
|
||||||
<div id="logo"></div>
|
<div id="logo"></div>
|
||||||
<div id="input">
|
<div id="input">
|
||||||
<input id="name" type="text"></input>
|
<input id="name" type="text"></input>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,21 +1,38 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// Create application with options
|
// Create application with options
|
||||||
app, err := wails.CreateApp("{{.ProjectName}}", 1024, 768)
|
app := NewBasic()
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Bind(newBasic())
|
err := wails.Run(&options.App{
|
||||||
|
Title: "{{.ProjectName}}",
|
||||||
err = app.Run()
|
Width: 800,
|
||||||
|
Height: 600,
|
||||||
|
DisableResize: true,
|
||||||
|
Mac: &mac.Options{
|
||||||
|
WebviewIsTransparent: true,
|
||||||
|
WindowBackgroundIsTranslucent: true,
|
||||||
|
TitleBar: mac.TitleBarHiddenInset(),
|
||||||
|
Menu: menu.DefaultMacMenu(),
|
||||||
|
},
|
||||||
|
LogLevel: logger.DEBUG,
|
||||||
|
Startup: app.startup,
|
||||||
|
Shutdown: app.shutdown,
|
||||||
|
Bind: []interface{}{
|
||||||
|
app,
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,13 @@ func (b *BaseBuilder) CleanUp() {
|
|||||||
// CompileProject compiles the project
|
// CompileProject compiles the project
|
||||||
func (b *BaseBuilder) CompileProject(options *Options) error {
|
func (b *BaseBuilder) CompileProject(options *Options) error {
|
||||||
|
|
||||||
|
// Run go mod tidy first
|
||||||
|
cmd := exec.Command(options.Compiler, "mod", "tidy")
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Default go build command
|
// Default go build command
|
||||||
commands := slicer.String([]string{"build"})
|
commands := slicer.String([]string{"build"})
|
||||||
|
|
||||||
@@ -188,7 +195,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
|
|
||||||
// Get application build directory
|
// Get application build directory
|
||||||
appDir := options.BuildDirectory
|
appDir := options.BuildDirectory
|
||||||
err := cleanBuildDirectory(options)
|
err = cleanBuildDirectory(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -211,7 +218,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
options.CompiledBinary = compiledBinary
|
options.CompiledBinary = compiledBinary
|
||||||
|
|
||||||
// Create the command
|
// Create the command
|
||||||
cmd := exec.Command(options.Compiler, commands.AsSlice()...)
|
cmd = exec.Command(options.Compiler, commands.AsSlice()...)
|
||||||
|
|
||||||
// Set the directory
|
// Set the directory
|
||||||
cmd.Dir = b.projectData.Path
|
cmd.Dir = b.projectData.Path
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type Options struct {
|
|||||||
BuildDirectory string // Directory to use for building the application
|
BuildDirectory string // Directory to use for building the application
|
||||||
CompiledBinary string // Fully qualified path to the compiled binary
|
CompiledBinary string // Fully qualified path to the compiled binary
|
||||||
KeepAssets bool // /Keep the generated assets/files
|
KeepAssets bool // /Keep the generated assets/files
|
||||||
|
AppleIdentity string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetModeAsString returns the current mode as a string
|
// GetModeAsString returns the current mode as a string
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -52,6 +54,14 @@ func packageApplication(options *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign app if needed
|
||||||
|
if options.AppleIdentity != "" {
|
||||||
|
err = signApplication(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,3 +186,21 @@ func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
|
|||||||
}()
|
}()
|
||||||
return icns.Encode(dest, srcImg)
|
return icns.Encode(dest, srcImg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signApplication(options *Options) error {
|
||||||
|
bundlename := filepath.Join(options.BuildDirectory, options.ProjectData.Name+".app")
|
||||||
|
identity := fmt.Sprintf(`"%s"`, options.AppleIdentity)
|
||||||
|
cmd := exec.Command("codesign", "--sign", identity, "--deep", "--force", "--verbose", "--timestamp", "--options", "runtime", bundlename)
|
||||||
|
var stdo, stde bytes.Buffer
|
||||||
|
cmd.Stdout = &stdo
|
||||||
|
cmd.Stderr = &stde
|
||||||
|
|
||||||
|
// Run command
|
||||||
|
err := cmd.Run()
|
||||||
|
|
||||||
|
// Format error if we have one
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s\n%s", err, string(stde.Bytes()))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ type Modifier string
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// CmdOrCtrlKey represents Command on Mac and Control on other platforms
|
// 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 represents Option on Mac and Alt on other platforms
|
||||||
OptionOrAltKey Modifier = "OptionOrAlt"
|
OptionOrAltKey Modifier = "optionoralt"
|
||||||
// ShiftKey represents the shift key on all systems
|
// 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 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 represents the control key on all systems
|
||||||
ControlKey Modifier = "Control"
|
ControlKey Modifier = "ctrl"
|
||||||
)
|
)
|
||||||
|
|
||||||
var modifierMap = map[string]Modifier{
|
var modifierMap = map[string]Modifier{
|
||||||
|
|||||||
@@ -39,9 +39,12 @@ type MenuItem struct {
|
|||||||
// Image - base64 image data
|
// Image - base64 image data
|
||||||
Image string
|
Image string
|
||||||
|
|
||||||
// MacTemplateImage indicates that on a mac, this image is a template image
|
// MacTemplateImage indicates that on a Mac, this image is a template image
|
||||||
MacTemplateImage bool
|
MacTemplateImage bool
|
||||||
|
|
||||||
|
// MacAlternate indicates that this item is an alternative to the previous menu item
|
||||||
|
MacAlternate bool
|
||||||
|
|
||||||
// Tooltip
|
// Tooltip
|
||||||
Tooltip string
|
Tooltip string
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,14 @@ package mac
|
|||||||
|
|
||||||
import "github.com/wailsapp/wails/v2/pkg/menu"
|
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
|
// Options are options specific to Mac
|
||||||
type Options struct {
|
type Options struct {
|
||||||
TitleBar *TitleBar
|
TitleBar *TitleBar
|
||||||
@@ -11,4 +19,6 @@ type Options struct {
|
|||||||
Menu *menu.Menu
|
Menu *menu.Menu
|
||||||
TrayMenus []*menu.TrayMenu
|
TrayMenus []*menu.TrayMenu
|
||||||
ContextMenus []*menu.ContextMenu
|
ContextMenus []*menu.ContextMenu
|
||||||
|
ActivationPolicy ActivationPolicy
|
||||||
|
URLHandlers map[string]func(string)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user