mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
Graceful shutdown
This commit is contained in:
@@ -3,6 +3,9 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
"github.com/wailsapp/wails/v2/internal/ffenestri"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
@@ -26,10 +29,10 @@ type App struct {
|
|||||||
options *options.App
|
options *options.App
|
||||||
|
|
||||||
// Subsystems
|
// Subsystems
|
||||||
log *subsystem.Log
|
log *subsystem.Log
|
||||||
runtime *subsystem.Runtime
|
runtime *subsystem.Runtime
|
||||||
event *subsystem.Event
|
event *subsystem.Event
|
||||||
binding *subsystem.Binding
|
//binding *subsystem.Binding
|
||||||
call *subsystem.Call
|
call *subsystem.Call
|
||||||
menu *subsystem.Menu
|
menu *subsystem.Menu
|
||||||
dispatcher *messagedispatcher.Dispatcher
|
dispatcher *messagedispatcher.Dispatcher
|
||||||
@@ -109,8 +112,13 @@ func (a *App) Run() error {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
// Setup a context
|
||||||
|
var subsystemWaitGroup sync.WaitGroup
|
||||||
|
parentContext := context.WithValue(context.Background(), "waitgroup", &subsystemWaitGroup)
|
||||||
|
ctx, cancel := context.WithCancel(parentContext)
|
||||||
|
|
||||||
// Setup signal handler
|
// Setup signal handler
|
||||||
signalsubsystem, err := signal.NewManager(a.servicebus, a.logger)
|
signalsubsystem, err := signal.NewManager(ctx, cancel, a.servicebus, a.logger, a.shutdownCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -124,7 +132,7 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimesubsystem, err := subsystem.NewRuntime(a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, a.shutdownCallback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -138,17 +146,6 @@ func (a *App) Run() error {
|
|||||||
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
a.loglevelStore = a.runtime.GoRuntime().Store.New("wails:loglevel", a.options.LogLevel)
|
||||||
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
a.appconfigStore = a.runtime.GoRuntime().Store.New("wails:appconfig", a.options)
|
||||||
|
|
||||||
// Start the binding subsystem
|
|
||||||
bindingsubsystem, err := subsystem.NewBinding(a.servicebus, a.logger, a.bindings, a.runtime.GoRuntime())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
a.binding = bindingsubsystem
|
|
||||||
err = a.binding.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the logging subsystem
|
// Start the logging subsystem
|
||||||
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
log, err := subsystem.NewLog(a.servicebus, a.logger, a.loglevelStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -172,18 +169,18 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the eventing subsystem
|
// Start the eventing subsystem
|
||||||
event, err := subsystem.NewEvent(a.servicebus, a.logger)
|
eventsubsystem, err := subsystem.NewEvent(ctx, a.servicebus, a.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.event = event
|
a.event = eventsubsystem
|
||||||
err = a.event.Start()
|
err = a.event.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the menu subsystem
|
// Start the menu subsystem
|
||||||
menusubsystem, err := subsystem.NewMenu(a.servicebus, a.logger, a.menuManager)
|
menusubsystem, err := subsystem.NewMenu(ctx, a.servicebus, a.logger, a.menuManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -194,11 +191,11 @@ func (a *App) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the call subsystem
|
// Start the call subsystem
|
||||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
callSubsystem, err := subsystem.NewCall(ctx, a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.call = call
|
a.call = callSubsystem
|
||||||
err = a.call.Start()
|
err = a.call.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -210,12 +207,31 @@ func (a *App) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := 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 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close down all the subsystems
|
||||||
|
a.logger.Trace("Cancelling subsystems")
|
||||||
|
cancel()
|
||||||
|
subsystemWaitGroup.Wait()
|
||||||
|
|
||||||
|
a.logger.Trace("Cancelling dispatcher")
|
||||||
|
dispatcher.Close()
|
||||||
|
|
||||||
|
// Close log
|
||||||
|
a.logger.Trace("Stopping log")
|
||||||
|
log.Close()
|
||||||
|
|
||||||
|
a.logger.Trace("Stopping Service bus")
|
||||||
err = a.servicebus.Stop()
|
err = a.servicebus.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
println("Desktop.Run() finished")
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package ffenestri
|
package ffenestri
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
"github.com/wailsapp/wails/v2/internal/messagedispatcher"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
@@ -118,7 +119,8 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug
|
|||||||
fullscreen := a.bool2Cint(a.config.Fullscreen)
|
fullscreen := a.bool2Cint(a.config.Fullscreen)
|
||||||
startHidden := a.bool2Cint(a.config.StartHidden)
|
startHidden := a.bool2Cint(a.config.StartHidden)
|
||||||
logLevel := C.int(a.config.LogLevel)
|
logLevel := C.int(a.config.LogLevel)
|
||||||
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel)
|
hideWindowOnClose := a.bool2Cint(a.config.HideWindowOnClose)
|
||||||
|
app := C.NewApplication(title, width, height, resizable, devtools, fullscreen, startHidden, logLevel, hideWindowOnClose)
|
||||||
|
|
||||||
// Save app reference
|
// Save app reference
|
||||||
a.app = (*C.struct_Application)(app)
|
a.app = (*C.struct_Application)(app)
|
||||||
@@ -167,6 +169,7 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug
|
|||||||
// Yes - Save memory reference and run app, cleaning up afterwards
|
// Yes - Save memory reference and run app, cleaning up afterwards
|
||||||
a.saveMemoryReference(unsafe.Pointer(app))
|
a.saveMemoryReference(unsafe.Pointer(app))
|
||||||
C.Run(app, 0, nil)
|
C.Run(app, 0, nil)
|
||||||
|
println("Back in ffenestri.go")
|
||||||
} else {
|
} else {
|
||||||
// Oh no! We couldn't initialise the application
|
// Oh no! We couldn't initialise the application
|
||||||
a.logger.Fatal("Cannot initialise Application.")
|
a.logger.Fatal("Cannot initialise Application.")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
struct Application;
|
struct Application;
|
||||||
|
|
||||||
extern struct Application *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel);
|
extern struct Application *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose);
|
||||||
extern void SetMinWindowSize(struct Application*, int minWidth, int minHeight);
|
extern void SetMinWindowSize(struct Application*, int minWidth, int minHeight);
|
||||||
extern void SetMaxWindowSize(struct Application*, int maxWidth, int maxHeight);
|
extern void SetMaxWindowSize(struct Application*, int maxWidth, int maxHeight);
|
||||||
extern void Run(struct Application*, int argc, char **argv);
|
extern void Run(struct Application*, int argc, char **argv);
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ BOOL yes(id self, SEL cmd)
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no command simply returns NO!
|
||||||
|
BOOL no(id self, SEL cmd)
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
// Prints a hashmap entry
|
// Prints a hashmap entry
|
||||||
int hashmap_log(void *const context, struct hashmap_element_s *const e) {
|
int hashmap_log(void *const context, struct hashmap_element_s *const e) {
|
||||||
printf("%s: %p ", (char*)e->key, e->data);
|
printf("%s: %p ", (char*)e->key, e->data);
|
||||||
@@ -65,6 +71,7 @@ struct Application {
|
|||||||
// Cocoa data
|
// Cocoa data
|
||||||
id application;
|
id application;
|
||||||
id delegate;
|
id delegate;
|
||||||
|
id windowDelegate;
|
||||||
id mainWindow;
|
id mainWindow;
|
||||||
id wkwebview;
|
id wkwebview;
|
||||||
id manager;
|
id manager;
|
||||||
@@ -92,6 +99,7 @@ struct Application {
|
|||||||
const char *appearance;
|
const char *appearance;
|
||||||
int decorations;
|
int decorations;
|
||||||
int logLevel;
|
int logLevel;
|
||||||
|
int hideWindowOnClose;
|
||||||
|
|
||||||
// Features
|
// Features
|
||||||
int frame;
|
int frame;
|
||||||
@@ -120,6 +128,9 @@ struct Application {
|
|||||||
// Bindings
|
// Bindings
|
||||||
const char *bindings;
|
const char *bindings;
|
||||||
|
|
||||||
|
// shutting down flag
|
||||||
|
bool shuttingDown;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debug works like sprintf but mutes if the global debug flag is true
|
// Debug works like sprintf but mutes if the global debug flag is true
|
||||||
@@ -222,6 +233,9 @@ void applyWindowColour(struct Application *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetColour(struct Application *app, int red, int green, int blue, int alpha) {
|
void SetColour(struct Application *app, int red, int green, int blue, int alpha) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
app->red = red;
|
app->red = red;
|
||||||
app->green = green;
|
app->green = green;
|
||||||
app->blue = blue;
|
app->blue = blue;
|
||||||
@@ -235,12 +249,18 @@ void FullSizeContent(struct Application *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Hide(struct Application *app) {
|
void Hide(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
msg(app->application, s("hide:"))
|
msg(app->application, s("hide:"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Show(struct Application *app) {
|
void Show(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
msg(app->mainWindow, s("makeKeyAndOrderFront:"), NULL);
|
msg(app->mainWindow, s("makeKeyAndOrderFront:"), NULL);
|
||||||
msg(app->application, s("activateIgnoringOtherApps:"), YES);
|
msg(app->application, s("activateIgnoringOtherApps:"), YES);
|
||||||
@@ -422,6 +442,7 @@ void freeDialogIconCache(struct Application *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DestroyApplication(struct Application *app) {
|
void DestroyApplication(struct Application *app) {
|
||||||
|
app->shuttingDown = true;
|
||||||
Debug(app, "Destroying Application");
|
Debug(app, "Destroying Application");
|
||||||
|
|
||||||
// Free the bindings
|
// Free the bindings
|
||||||
@@ -466,10 +487,16 @@ void DestroyApplication(struct Application *app) {
|
|||||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("error"));
|
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("error"));
|
||||||
|
|
||||||
// Close main window
|
// Close main window
|
||||||
msg(app->mainWindow, s("close"));
|
if( app->windowDelegate != NULL ) {
|
||||||
|
printf("\n\n\n\nReleasing window delegate\n\n\n\n\n");
|
||||||
|
msg(app->windowDelegate, s("release"));
|
||||||
|
printf("\n\n\n\n\nRemoving window delegate\n\n\n\n\n\n\n");
|
||||||
|
msg(app->mainWindow, s("setDelegate:"), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// msg(app->mainWindow, s("close"));
|
||||||
|
|
||||||
|
|
||||||
// Terminate app
|
|
||||||
msg(c("NSApp"), s("terminate:"), NULL);
|
|
||||||
Debug(app, "Finished Destroying Application");
|
Debug(app, "Finished Destroying Application");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,11 +504,32 @@ void DestroyApplication(struct Application *app) {
|
|||||||
// 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");
|
||||||
DestroyApplication(app);
|
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
|
// SetTitle sets the main window title to the given string
|
||||||
void SetTitle(struct Application *app, const char *title) {
|
void SetTitle(struct Application *app, const char *title) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
Debug(app, "SetTitle Called");
|
Debug(app, "SetTitle Called");
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
msg(app->mainWindow, s("setTitle:"), str(title));
|
msg(app->mainWindow, s("setTitle:"), str(title));
|
||||||
@@ -503,6 +551,9 @@ bool isFullScreen(struct Application *app) {
|
|||||||
|
|
||||||
// Fullscreen sets the main window to be fullscreen
|
// Fullscreen sets the main window to be fullscreen
|
||||||
void Fullscreen(struct Application *app) {
|
void Fullscreen(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
Debug(app, "Fullscreen Called");
|
Debug(app, "Fullscreen Called");
|
||||||
if( ! isFullScreen(app) ) {
|
if( ! isFullScreen(app) ) {
|
||||||
ToggleFullscreen(app);
|
ToggleFullscreen(app);
|
||||||
@@ -511,6 +562,9 @@ void Fullscreen(struct Application *app) {
|
|||||||
|
|
||||||
// UnFullscreen resets the main window after a fullscreen
|
// UnFullscreen resets the main window after a fullscreen
|
||||||
void UnFullscreen(struct Application *app) {
|
void UnFullscreen(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
Debug(app, "UnFullscreen Called");
|
Debug(app, "UnFullscreen Called");
|
||||||
if( isFullScreen(app) ) {
|
if( isFullScreen(app) ) {
|
||||||
ToggleFullscreen(app);
|
ToggleFullscreen(app);
|
||||||
@@ -518,6 +572,9 @@ void UnFullscreen(struct Application *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Center(struct Application *app) {
|
void Center(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
Debug(app, "Center Called");
|
Debug(app, "Center Called");
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
MAIN_WINDOW_CALL("center");
|
MAIN_WINDOW_CALL("center");
|
||||||
@@ -532,23 +589,35 @@ void ToggleMaximise(struct Application *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Maximise(struct Application *app) {
|
void Maximise(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
if( app->maximised == 0) {
|
if( app->maximised == 0) {
|
||||||
ToggleMaximise(app);
|
ToggleMaximise(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unmaximise(struct Application *app) {
|
void Unmaximise(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
if( app->maximised == 1) {
|
if( app->maximised == 1) {
|
||||||
ToggleMaximise(app);
|
ToggleMaximise(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Minimise(struct Application *app) {
|
void Minimise(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
MAIN_WINDOW_CALL("miniaturize:");
|
MAIN_WINDOW_CALL("miniaturize:");
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
void Unminimise(struct Application *app) {
|
void Unminimise(struct Application *app) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
MAIN_WINDOW_CALL("deminiaturize:");
|
MAIN_WINDOW_CALL("deminiaturize:");
|
||||||
);
|
);
|
||||||
@@ -572,6 +641,9 @@ void dumpFrame(struct Application *app, const char *message, CGRect frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetSize(struct Application *app, int width, int height) {
|
void SetSize(struct Application *app, int width, int height) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
id screen = getCurrentScreen(app);
|
id screen = getCurrentScreen(app);
|
||||||
|
|
||||||
@@ -588,6 +660,9 @@ void SetSize(struct Application *app, int width, int height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetPosition(struct Application *app, int x, int y) {
|
void SetPosition(struct Application *app, int x, int y) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
id screen = getCurrentScreen(app);
|
id screen = getCurrentScreen(app);
|
||||||
CGRect screenFrame = GET_FRAME(screen);
|
CGRect screenFrame = GET_FRAME(screen);
|
||||||
@@ -613,6 +688,9 @@ void processDialogButton(id alert, char *buttonTitle, char *cancelButton, char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern void MessageDialog(struct Application *app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton) {
|
extern void MessageDialog(struct Application *app, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
id alert = ALLOC_INIT("NSAlert");
|
id alert = ALLOC_INIT("NSAlert");
|
||||||
char *dialogType = type;
|
char *dialogType = type;
|
||||||
@@ -726,6 +804,9 @@ extern void MessageDialog(struct Application *app, char *callbackID, char *type,
|
|||||||
|
|
||||||
// OpenDialog opens a dialog to select files/directories
|
// OpenDialog opens a dialog to select files/directories
|
||||||
void OpenDialog(struct Application *app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories) {
|
void OpenDialog(struct Application *app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int allowFiles, int allowDirs, int allowMultiple, int showHiddenFiles, int canCreateDirectories, int resolvesAliases, int treatPackagesAsDirectories) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
Debug(app, "OpenDialog Called with callback id: %s", callbackID);
|
Debug(app, "OpenDialog Called with callback id: %s", callbackID);
|
||||||
|
|
||||||
// Create an open panel
|
// Create an open panel
|
||||||
@@ -814,6 +895,9 @@ void OpenDialog(struct Application *app, char *callbackID, char *title, char *fi
|
|||||||
|
|
||||||
// SaveDialog opens a dialog to select files/directories
|
// SaveDialog opens a dialog to select files/directories
|
||||||
void SaveDialog(struct Application *app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories) {
|
void SaveDialog(struct Application *app, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
Debug(app, "SaveDialog Called with callback id: %s", callbackID);
|
Debug(app, "SaveDialog Called with callback id: %s", callbackID);
|
||||||
|
|
||||||
// Create an open panel
|
// Create an open panel
|
||||||
@@ -891,6 +975,9 @@ void DisableFrame(struct Application *app)
|
|||||||
|
|
||||||
void setMinMaxSize(struct Application *app)
|
void setMinMaxSize(struct Application *app)
|
||||||
{
|
{
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
if (app->maxHeight > 0 && app->maxWidth > 0)
|
if (app->maxHeight > 0 && app->maxWidth > 0)
|
||||||
{
|
{
|
||||||
msg(app->mainWindow, s("setMaxSize:"), CGSizeMake(app->maxWidth, app->maxHeight));
|
msg(app->mainWindow, s("setMaxSize:"), CGSizeMake(app->maxWidth, app->maxHeight));
|
||||||
@@ -917,6 +1004,9 @@ void setMinMaxSize(struct Application *app)
|
|||||||
|
|
||||||
void SetMinWindowSize(struct Application *app, int minWidth, int minHeight)
|
void SetMinWindowSize(struct Application *app, int minWidth, int minHeight)
|
||||||
{
|
{
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
app->minWidth = minWidth;
|
app->minWidth = minWidth;
|
||||||
app->minHeight = minHeight;
|
app->minHeight = minHeight;
|
||||||
|
|
||||||
@@ -930,6 +1020,9 @@ void SetMinWindowSize(struct Application *app, int minWidth, int minHeight)
|
|||||||
|
|
||||||
void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight)
|
void SetMaxWindowSize(struct Application *app, int maxWidth, int maxHeight)
|
||||||
{
|
{
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
app->maxWidth = maxWidth;
|
app->maxWidth = maxWidth;
|
||||||
app->maxHeight = maxHeight;
|
app->maxHeight = maxHeight;
|
||||||
|
|
||||||
@@ -950,24 +1043,40 @@ void SetDebug(void *applicationPointer, int flag) {
|
|||||||
|
|
||||||
// AddContextMenu sets the context menu map for this application
|
// AddContextMenu sets the context menu map for this application
|
||||||
void AddContextMenu(struct Application *app, const char *contextMenuJSON) {
|
void AddContextMenu(struct Application *app, const char *contextMenuJSON) {
|
||||||
AddContextMenuToStore(app->contextMenuStore, contextMenuJSON);
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
|
AddContextMenuToStore(app->contextMenuStore, contextMenuJSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateContextMenu(struct Application *app, const char* contextMenuJSON) {
|
void UpdateContextMenu(struct Application *app, const char* contextMenuJSON) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
UpdateContextMenuInStore(app->contextMenuStore, contextMenuJSON);
|
UpdateContextMenuInStore(app->contextMenuStore, contextMenuJSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTrayMenu(struct Application *app, const char *trayMenuJSON) {
|
void AddTrayMenu(struct Application *app, const char *trayMenuJSON) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
AddTrayMenuToStore(app->trayMenuStore, trayMenuJSON);
|
AddTrayMenuToStore(app->trayMenuStore, trayMenuJSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTrayMenu(struct Application *app, const char* trayMenuJSON) {
|
void SetTrayMenu(struct Application *app, const char* trayMenuJSON) {
|
||||||
|
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
UpdateTrayMenuInStore(app->trayMenuStore, trayMenuJSON);
|
UpdateTrayMenuInStore(app->trayMenuStore, trayMenuJSON);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
|
void UpdateTrayMenuLabel(struct Application* app, const char* JSON) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
UpdateTrayMenuLabelInStore(app->trayMenuStore, JSON);
|
UpdateTrayMenuLabelInStore(app->trayMenuStore, JSON);
|
||||||
);
|
);
|
||||||
@@ -1034,6 +1143,9 @@ void createApplication(struct Application *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
ON_MAIN_THREAD(
|
ON_MAIN_THREAD(
|
||||||
const char *result = isDarkMode(app) ? "T" : "F";
|
const char *result = isDarkMode(app) ? "T" : "F";
|
||||||
|
|
||||||
@@ -1054,9 +1166,9 @@ void DarkModeEnabled(struct Application *app, const char *callbackID) {
|
|||||||
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) yes, "c@:@");
|
class_addMethod(delegateClass, s("applicationShouldTerminateAfterLastWindowClosed:"), (IMP) no, "c@:@");
|
||||||
class_addMethod(delegateClass, s("applicationWillTerminate:"), (IMP) closeWindow, "v@:@");
|
// 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
|
||||||
@@ -1082,6 +1194,11 @@ void createDelegate(struct Application *app) {
|
|||||||
msg(app->application, s("setDelegate:"), delegate);
|
msg(app->application, s("setDelegate:"), delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool windowShouldClose(id self, SEL cmd, id sender) {
|
||||||
|
msg(sender, s("orderBack:"));
|
||||||
|
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");
|
||||||
@@ -1100,6 +1217,15 @@ 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
|
||||||
|
Class delegateClass = objc_allocateClassPair((Class) c("NSObject"), "WindowDelegate", 0);
|
||||||
|
bool resultAddProtoc = class_addProtocol(delegateClass, objc_getProtocol("NSWindowDelegate"));
|
||||||
|
class_replaceMethod(delegateClass, s("windowShouldClose:"), (IMP) windowShouldClose, "v@:@");
|
||||||
|
app->windowDelegate = msg((id)delegateClass, s("new"));
|
||||||
|
msg(mainWindow, s("setDelegate:"), app->windowDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
app->mainWindow = mainWindow;
|
app->mainWindow = mainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1186,7 +1312,7 @@ void parseMenuRole(struct Application *app, id parentMenu, JsonNode *item) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( STREQ(roleName, "quit")) {
|
if ( STREQ(roleName, "quit")) {
|
||||||
addMenuItem(parentMenu, "Quit (More work TBD)", "terminate:", "q", FALSE);
|
addMenuItem(parentMenu, "Quit", "terminate:", "q", FALSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( STREQ(roleName, "togglefullscreen")) {
|
if ( STREQ(roleName, "togglefullscreen")) {
|
||||||
@@ -1464,6 +1590,9 @@ void updateMenu(struct Application *app, const char *menuAsJSON) {
|
|||||||
|
|
||||||
// SetApplicationMenu sets the initial menu for the application
|
// SetApplicationMenu sets the initial menu for the application
|
||||||
void SetApplicationMenu(struct Application *app, const char *menuAsJSON) {
|
void SetApplicationMenu(struct Application *app, const char *menuAsJSON) {
|
||||||
|
// Guard against calling during shutdown
|
||||||
|
if( app->shuttingDown ) return;
|
||||||
|
|
||||||
if ( app->applicationMenu == NULL ) {
|
if ( app->applicationMenu == NULL ) {
|
||||||
app->applicationMenu = NewApplicationMenu(menuAsJSON);
|
app->applicationMenu = NewApplicationMenu(menuAsJSON);
|
||||||
return;
|
return;
|
||||||
@@ -1705,11 +1834,13 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
Debug(app, "Run called");
|
Debug(app, "Run called");
|
||||||
msg(app->application, s("run"));
|
msg(app->application, s("run"));
|
||||||
|
|
||||||
|
DestroyApplication(app);
|
||||||
|
|
||||||
MEMFREE(internalCode);
|
MEMFREE(internalCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel) {
|
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) {
|
||||||
|
|
||||||
// Load the tray icons
|
// Load the tray icons
|
||||||
LoadTrayIcons();
|
LoadTrayIcons();
|
||||||
@@ -1730,6 +1861,7 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
|||||||
result->startHidden = startHidden;
|
result->startHidden = startHidden;
|
||||||
result->decorations = 0;
|
result->decorations = 0;
|
||||||
result->logLevel = logLevel;
|
result->logLevel = logLevel;
|
||||||
|
result->hideWindowOnClose = hideWindowOnClose;
|
||||||
|
|
||||||
result->mainWindow = NULL;
|
result->mainWindow = NULL;
|
||||||
result->mouseEvent = NULL;
|
result->mouseEvent = NULL;
|
||||||
@@ -1758,12 +1890,17 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
|||||||
// Context Menus
|
// Context Menus
|
||||||
result->contextMenuStore = NewContextMenuStore();
|
result->contextMenuStore = NewContextMenuStore();
|
||||||
|
|
||||||
|
// Window delegate
|
||||||
|
result->windowDelegate = NULL;
|
||||||
|
|
||||||
// Window Appearance
|
// Window Appearance
|
||||||
result->titlebarAppearsTransparent = 0;
|
result->titlebarAppearsTransparent = 0;
|
||||||
result->webviewIsTranparent = 0;
|
result->webviewIsTranparent = 0;
|
||||||
|
|
||||||
result->sendMessageToBackend = (ffenestriCallback) messageFromWindowCallback;
|
result->sendMessageToBackend = (ffenestriCallback) messageFromWindowCallback;
|
||||||
|
|
||||||
|
result->shuttingDown = false;
|
||||||
|
|
||||||
return (void*) result;
|
return (void*) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package messagedispatcher
|
package messagedispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -24,7 +25,6 @@ type Dispatcher struct {
|
|||||||
dialogChannel <-chan *servicebus.Message
|
dialogChannel <-chan *servicebus.Message
|
||||||
systemChannel <-chan *servicebus.Message
|
systemChannel <-chan *servicebus.Message
|
||||||
menuChannel <-chan *servicebus.Message
|
menuChannel <-chan *servicebus.Message
|
||||||
running bool
|
|
||||||
|
|
||||||
servicebus *servicebus.ServiceBus
|
servicebus *servicebus.ServiceBus
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
@@ -32,6 +32,13 @@ type Dispatcher struct {
|
|||||||
// Clients
|
// Clients
|
||||||
clients map[string]*DispatchClient
|
clients map[string]*DispatchClient
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
|
||||||
|
// Context for cancellation
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
|
||||||
|
// internal wait group
|
||||||
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// New dispatcher. Needs a service bus to send to.
|
// New dispatcher. Needs a service bus to send to.
|
||||||
@@ -76,6 +83,9 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create context
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
result := &Dispatcher{
|
result := &Dispatcher{
|
||||||
servicebus: servicebus,
|
servicebus: servicebus,
|
||||||
eventChannel: eventChannel,
|
eventChannel: eventChannel,
|
||||||
@@ -87,6 +97,8 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
|||||||
dialogChannel: dialogChannel,
|
dialogChannel: dialogChannel,
|
||||||
systemChannel: systemChannel,
|
systemChannel: systemChannel,
|
||||||
menuChannel: menuChannel,
|
menuChannel: menuChannel,
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -97,15 +109,18 @@ func (d *Dispatcher) Start() error {
|
|||||||
|
|
||||||
d.logger.Trace("Starting")
|
d.logger.Trace("Starting")
|
||||||
|
|
||||||
d.running = true
|
d.wg.Add(1)
|
||||||
|
|
||||||
// Spin off a go routine
|
// Spin off a go routine
|
||||||
go func() {
|
go func() {
|
||||||
for d.running {
|
defer d.logger.Trace("Shutdown")
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
|
case <-d.ctx.Done():
|
||||||
|
d.wg.Done()
|
||||||
|
return
|
||||||
case <-d.quitChannel:
|
case <-d.quitChannel:
|
||||||
d.processQuit()
|
d.processQuit()
|
||||||
d.running = false
|
|
||||||
case resultMessage := <-d.resultChannel:
|
case resultMessage := <-d.resultChannel:
|
||||||
d.processCallResult(resultMessage)
|
d.processCallResult(resultMessage)
|
||||||
case eventMessage := <-d.eventChannel:
|
case eventMessage := <-d.eventChannel:
|
||||||
@@ -120,9 +135,6 @@ func (d *Dispatcher) Start() error {
|
|||||||
d.processMenuMessage(menuMessage)
|
d.processMenuMessage(menuMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call shutdown
|
|
||||||
d.shutdown()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -136,10 +148,6 @@ func (d *Dispatcher) processQuit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dispatcher) shutdown() {
|
|
||||||
d.logger.Trace("Shutdown")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterClient will register the given callback with the dispatcher
|
// RegisterClient will register the given callback with the dispatcher
|
||||||
// and return a DispatchClient that the caller can use to send messages
|
// and return a DispatchClient that the caller can use to send messages
|
||||||
func (d *Dispatcher) RegisterClient(client Client) *DispatchClient {
|
func (d *Dispatcher) RegisterClient(client Client) *DispatchClient {
|
||||||
@@ -524,3 +532,8 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
|||||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) Close() {
|
||||||
|
d.cancel()
|
||||||
|
d.wg.Wait()
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,19 +6,20 @@ 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) *Runtime {
|
func New(serviceBus *servicebus.ServiceBus, shutdownCallback func()) *Runtime {
|
||||||
result := &Runtime{
|
result := &Runtime{
|
||||||
Browser: newBrowser(),
|
Browser: newBrowser(),
|
||||||
Events: newEvents(serviceBus),
|
Events: newEvents(serviceBus),
|
||||||
@@ -35,5 +36,11 @@ func New(serviceBus *servicebus.ServiceBus) *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
|
||||||
r.bus.Publish("quit", "runtime.Quit()")
|
r.bus.Publish("quit", "runtime.Quit()")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package servicebus
|
package servicebus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -12,23 +13,26 @@ import (
|
|||||||
type ServiceBus struct {
|
type ServiceBus struct {
|
||||||
listeners map[string][]chan *Message
|
listeners map[string][]chan *Message
|
||||||
messageQueue chan *Message
|
messageQueue chan *Message
|
||||||
quitChannel chan struct{}
|
|
||||||
wg sync.WaitGroup
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
closed bool
|
closed bool
|
||||||
debug bool
|
debug bool
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ServiceBus
|
// New creates a new ServiceBus
|
||||||
// The internal message queue is set to 100 messages
|
// The internal message queue is set to 100 messages
|
||||||
// Listener queues are set to 10
|
// Listener queues are set to 10
|
||||||
func New(logger *logger.Logger) *ServiceBus {
|
func New(logger *logger.Logger) *ServiceBus {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return &ServiceBus{
|
return &ServiceBus{
|
||||||
listeners: make(map[string][]chan *Message),
|
listeners: make(map[string][]chan *Message),
|
||||||
messageQueue: make(chan *Message, 100),
|
messageQueue: make(chan *Message, 100),
|
||||||
quitChannel: make(chan struct{}, 1),
|
|
||||||
logger: logger.CustomLogger("Service Bus"),
|
logger: logger.CustomLogger("Service Bus"),
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,24 +67,22 @@ func (s *ServiceBus) Debug() {
|
|||||||
// Start the service bus
|
// Start the service bus
|
||||||
func (s *ServiceBus) Start() error {
|
func (s *ServiceBus) Start() error {
|
||||||
|
|
||||||
s.logger.Trace("Starting")
|
|
||||||
|
|
||||||
// Prevent starting when closed
|
// Prevent starting when closed
|
||||||
if s.closed {
|
if s.closed {
|
||||||
return fmt.Errorf("cannot call start on closed servicebus")
|
return fmt.Errorf("cannot call start on closed servicebus")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We run in a different thread
|
s.logger.Trace("Starting")
|
||||||
s.wg.Add(1)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer s.logger.Trace("Stopped")
|
||||||
quit := false
|
|
||||||
|
|
||||||
// Loop until we get a quit message
|
// Loop until we get a quit message
|
||||||
for !quit {
|
for {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
case <-s.ctx.Done():
|
||||||
|
return
|
||||||
|
|
||||||
// Listen for messages
|
// Listen for messages
|
||||||
case message := <-s.messageQueue:
|
case message := <-s.messageQueue:
|
||||||
@@ -91,16 +93,9 @@ func (s *ServiceBus) Start() error {
|
|||||||
}
|
}
|
||||||
// Dispatch message
|
// Dispatch message
|
||||||
s.dispatchMessage(message)
|
s.dispatchMessage(message)
|
||||||
|
|
||||||
// Listen for quit messages
|
|
||||||
case <-s.quitChannel:
|
|
||||||
quit = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicate we have shut down
|
|
||||||
s.wg.Done()
|
|
||||||
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -117,10 +112,7 @@ func (s *ServiceBus) Stop() error {
|
|||||||
s.closed = true
|
s.closed = true
|
||||||
|
|
||||||
// Send quit message
|
// Send quit message
|
||||||
s.quitChannel <- struct{}{}
|
s.cancel()
|
||||||
|
|
||||||
// Wait for dispatcher to stop
|
|
||||||
s.wg.Wait()
|
|
||||||
|
|
||||||
// Close down subscriber channels
|
// Close down subscriber channels
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
@@ -135,7 +127,6 @@ func (s *ServiceBus) Stop() error {
|
|||||||
// Close message queue
|
// Close message queue
|
||||||
close(s.messageQueue)
|
close(s.messageQueue)
|
||||||
|
|
||||||
s.logger.Trace("Stopped")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +163,6 @@ func (s *ServiceBus) Subscribe(topic string) (<-chan *Message, error) {
|
|||||||
func (s *ServiceBus) Publish(topic string, data interface{}) {
|
func (s *ServiceBus) Publish(topic string, data interface{}) {
|
||||||
// Prevent publish when closed
|
// Prevent publish when closed
|
||||||
if s.closed {
|
if s.closed {
|
||||||
s.logger.Fatal("cannot call publish on closed servicebus")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +174,6 @@ func (s *ServiceBus) Publish(topic string, data interface{}) {
|
|||||||
func (s *ServiceBus) PublishForTarget(topic string, data interface{}, target string) {
|
func (s *ServiceBus) PublishForTarget(topic string, data interface{}, target string) {
|
||||||
// Prevent publish when closed
|
// Prevent publish when closed
|
||||||
if s.closed {
|
if s.closed {
|
||||||
s.logger.Fatal("cannot call publish on closed servicebus")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message := NewMessageForTarget(topic, data, target)
|
message := NewMessageForTarget(topic, data, target)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package signal
|
package signal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
gosignal "os/signal"
|
gosignal "os/signal"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
@@ -20,24 +22,29 @@ type Manager struct {
|
|||||||
// signalChannel
|
// signalChannel
|
||||||
signalchannel chan os.Signal
|
signalchannel chan os.Signal
|
||||||
|
|
||||||
// Quit channel
|
// ctx
|
||||||
quitChannel <-chan *servicebus.Message
|
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
|
// NewManager creates a new signal manager
|
||||||
func NewManager(bus *servicebus.ServiceBus, logger *logger.Logger) (*Manager, error) {
|
func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.ServiceBus, logger *logger.Logger, shutdownCallback func()) (*Manager, error) {
|
||||||
|
|
||||||
// Register quit channel
|
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
||||||
quitChannel: quitChannel,
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
shutdownCallback: shutdownCallback,
|
||||||
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -49,20 +56,28 @@ func (m *Manager) Start() {
|
|||||||
// Hook into interrupts
|
// Hook into interrupts
|
||||||
gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM)
|
gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
// Spin off signal listener
|
m.wg.Add(1)
|
||||||
|
|
||||||
|
// Spin off signal listener and wait for either a cancellation
|
||||||
|
// or signal
|
||||||
go func() {
|
go func() {
|
||||||
running := true
|
select {
|
||||||
for running {
|
case <-m.signalchannel:
|
||||||
select {
|
println()
|
||||||
case <-m.signalchannel:
|
m.logger.Trace("Ctrl+C detected. Shutting down...")
|
||||||
println()
|
m.bus.Publish("quit", "ctrl-c pressed")
|
||||||
m.logger.Trace("Ctrl+C detected. Shutting down...")
|
|
||||||
m.bus.Publish("quit", "ctrl-c pressed")
|
// Shutdown app first
|
||||||
case <-m.quitChannel:
|
if m.shutdownCallback != nil {
|
||||||
running = false
|
m.shutdownCallback()
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start shutdown of Wails
|
||||||
|
m.cancel()
|
||||||
|
|
||||||
|
case <-m.ctx.Done():
|
||||||
}
|
}
|
||||||
m.logger.Trace("Shutdown")
|
m.logger.Trace("Shutdown")
|
||||||
|
m.wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import (
|
|||||||
// Binding is the Binding subsystem. It manages all service bus messages
|
// Binding is the Binding subsystem. It manages all service bus messages
|
||||||
// starting with "binding".
|
// starting with "binding".
|
||||||
type Binding struct {
|
type Binding struct {
|
||||||
quitChannel <-chan *servicebus.Message
|
|
||||||
bindingChannel <-chan *servicebus.Message
|
bindingChannel <-chan *servicebus.Message
|
||||||
running bool
|
|
||||||
|
running bool
|
||||||
|
|
||||||
// Binding db
|
// Binding db
|
||||||
bindings *binding.Bindings
|
bindings *binding.Bindings
|
||||||
@@ -27,12 +27,6 @@ type Binding struct {
|
|||||||
// NewBinding creates a new binding subsystem. Uses the given bindings db for reference.
|
// NewBinding creates a new binding subsystem. Uses the given bindings db for reference.
|
||||||
func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *binding.Bindings, runtime *runtime.Runtime) (*Binding, error) {
|
func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *binding.Bindings, runtime *runtime.Runtime) (*Binding, error) {
|
||||||
|
|
||||||
// Register quit channel
|
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to event messages
|
// Subscribe to event messages
|
||||||
bindingChannel, err := bus.Subscribe("binding")
|
bindingChannel, err := bus.Subscribe("binding")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,7 +34,6 @@ func NewBinding(bus *servicebus.ServiceBus, logger *logger.Logger, bindings *bin
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Binding{
|
result := &Binding{
|
||||||
quitChannel: quitChannel,
|
|
||||||
bindingChannel: bindingChannel,
|
bindingChannel: bindingChannel,
|
||||||
logger: logger.CustomLogger("Binding Subsystem"),
|
logger: logger.CustomLogger("Binding Subsystem"),
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
@@ -61,20 +54,16 @@ func (b *Binding) Start() error {
|
|||||||
go func() {
|
go func() {
|
||||||
for b.running {
|
for b.running {
|
||||||
select {
|
select {
|
||||||
case <-b.quitChannel:
|
|
||||||
b.running = false
|
|
||||||
case bindingMessage := <-b.bindingChannel:
|
case bindingMessage := <-b.bindingChannel:
|
||||||
b.logger.Trace("Got binding message: %+v", bindingMessage)
|
b.logger.Trace("Got binding message: %+v", bindingMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
b.logger.Trace("Shutdown")
|
||||||
// Call shutdown
|
|
||||||
b.shutdown()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Binding) shutdown() {
|
func (b *Binding) Close() {
|
||||||
b.logger.Trace("Shutdown")
|
b.running = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package subsystem
|
package subsystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/dialog"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
@@ -16,9 +19,10 @@ import (
|
|||||||
// Call is the Call subsystem. It manages all service bus messages
|
// Call is the Call subsystem. It manages all service bus messages
|
||||||
// starting with "call".
|
// starting with "call".
|
||||||
type Call struct {
|
type Call struct {
|
||||||
quitChannel <-chan *servicebus.Message
|
|
||||||
callChannel <-chan *servicebus.Message
|
callChannel <-chan *servicebus.Message
|
||||||
running bool
|
|
||||||
|
// quit flag
|
||||||
|
shouldQuit bool
|
||||||
|
|
||||||
// bindings DB
|
// bindings DB
|
||||||
DB *binding.DB
|
DB *binding.DB
|
||||||
@@ -31,16 +35,16 @@ type Call struct {
|
|||||||
|
|
||||||
// runtime
|
// runtime
|
||||||
runtime *runtime.Runtime
|
runtime *runtime.Runtime
|
||||||
|
|
||||||
|
// context
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
|
// parent waitgroup
|
||||||
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCall creates a new call subsystem
|
// NewCall creates a new call subsystem
|
||||||
func NewCall(bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB, runtime *runtime.Runtime) (*Call, error) {
|
func NewCall(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB, runtime *runtime.Runtime) (*Call, error) {
|
||||||
|
|
||||||
// Register quit channel
|
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to event messages
|
// Subscribe to event messages
|
||||||
callChannel, err := bus.Subscribe("call:invoke")
|
callChannel, err := bus.Subscribe("call:invoke")
|
||||||
@@ -49,12 +53,13 @@ func NewCall(bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB,
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Call{
|
result := &Call{
|
||||||
quitChannel: quitChannel,
|
|
||||||
callChannel: callChannel,
|
callChannel: callChannel,
|
||||||
logger: logger.CustomLogger("Call Subsystem"),
|
logger: logger.CustomLogger("Call Subsystem"),
|
||||||
DB: DB,
|
DB: DB,
|
||||||
bus: bus,
|
bus: bus,
|
||||||
runtime: runtime,
|
runtime: runtime,
|
||||||
|
ctx: ctx,
|
||||||
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -63,22 +68,21 @@ func NewCall(bus *servicebus.ServiceBus, logger *logger.Logger, DB *binding.DB,
|
|||||||
// Start the subsystem
|
// Start the subsystem
|
||||||
func (c *Call) Start() error {
|
func (c *Call) Start() error {
|
||||||
|
|
||||||
c.running = true
|
c.wg.Add(1)
|
||||||
|
|
||||||
// Spin off a go routine
|
// Spin off a go routine
|
||||||
go func() {
|
go func() {
|
||||||
for c.running {
|
defer c.logger.Trace("Shutdown")
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-c.quitChannel:
|
case <-c.ctx.Done():
|
||||||
c.running = false
|
c.wg.Done()
|
||||||
|
return
|
||||||
case callMessage := <-c.callChannel:
|
case callMessage := <-c.callChannel:
|
||||||
// TODO: Check if this works ok in a goroutine
|
|
||||||
c.processCall(callMessage)
|
c.processCall(callMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call shutdown
|
|
||||||
c.shutdown()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -190,10 +194,6 @@ func (c *Call) sendError(err error, payload *message.CallMessage, clientID strin
|
|||||||
c.bus.PublishForTarget("call:result", string(messageData), clientID)
|
c.bus.PublishForTarget("call:result", string(messageData), clientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Call) shutdown() {
|
|
||||||
c.logger.Trace("Shutdown")
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallbackMessage defines a message that contains the result of a call
|
// CallbackMessage defines a message that contains the result of a call
|
||||||
type CallbackMessage struct {
|
type CallbackMessage struct {
|
||||||
Result interface{} `json:"result"`
|
Result interface{} `json:"result"`
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package subsystem
|
package subsystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -22,9 +23,7 @@ type eventListener struct {
|
|||||||
// Event is the Eventing subsystem. It manages all service bus messages
|
// Event is the Eventing subsystem. It manages all service bus messages
|
||||||
// starting with "event".
|
// starting with "event".
|
||||||
type Event struct {
|
type Event struct {
|
||||||
quitChannel <-chan *servicebus.Message
|
|
||||||
eventChannel <-chan *servicebus.Message
|
eventChannel <-chan *servicebus.Message
|
||||||
running bool
|
|
||||||
|
|
||||||
// Event listeners
|
// Event listeners
|
||||||
listeners map[string][]*eventListener
|
listeners map[string][]*eventListener
|
||||||
@@ -32,16 +31,16 @@ type Event struct {
|
|||||||
|
|
||||||
// logger
|
// logger
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
|
// ctx
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
|
// parent waitgroup
|
||||||
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEvent creates a new log subsystem
|
// NewEvent creates a new log subsystem
|
||||||
func NewEvent(bus *servicebus.ServiceBus, logger *logger.Logger) (*Event, error) {
|
func NewEvent(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger) (*Event, error) {
|
||||||
|
|
||||||
// Register quit channel
|
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to event messages
|
// Subscribe to event messages
|
||||||
eventChannel, err := bus.Subscribe("event")
|
eventChannel, err := bus.Subscribe("event")
|
||||||
@@ -50,10 +49,11 @@ func NewEvent(bus *servicebus.ServiceBus, logger *logger.Logger) (*Event, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Event{
|
result := &Event{
|
||||||
quitChannel: quitChannel,
|
|
||||||
eventChannel: eventChannel,
|
eventChannel: eventChannel,
|
||||||
logger: logger.CustomLogger("Event Subsystem"),
|
logger: logger.CustomLogger("Event Subsystem"),
|
||||||
listeners: make(map[string][]*eventListener),
|
listeners: make(map[string][]*eventListener),
|
||||||
|
ctx: ctx,
|
||||||
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -80,15 +80,16 @@ func (e *Event) Start() error {
|
|||||||
|
|
||||||
e.logger.Trace("Starting")
|
e.logger.Trace("Starting")
|
||||||
|
|
||||||
e.running = true
|
e.wg.Add(1)
|
||||||
|
|
||||||
// Spin off a go routine
|
// Spin off a go routine
|
||||||
go func() {
|
go func() {
|
||||||
for e.running {
|
defer e.logger.Trace("Shutdown")
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-e.quitChannel:
|
case <-e.ctx.Done():
|
||||||
e.running = false
|
e.wg.Done()
|
||||||
break
|
return
|
||||||
case eventMessage := <-e.eventChannel:
|
case eventMessage := <-e.eventChannel:
|
||||||
splitTopic := strings.Split(eventMessage.Topic(), ":")
|
splitTopic := strings.Split(eventMessage.Topic(), ":")
|
||||||
eventType := splitTopic[1]
|
eventType := splitTopic[1]
|
||||||
@@ -128,8 +129,6 @@ func (e *Event) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call shutdown
|
|
||||||
e.shutdown()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -190,7 +189,3 @@ func (e *Event) notifyListeners(eventName string, message *message.EventMessage)
|
|||||||
// Unlock
|
// Unlock
|
||||||
e.notifyLock.Unlock()
|
e.notifyLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Event) shutdown() {
|
|
||||||
e.logger.Trace("Shutdown")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package subsystem
|
package subsystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/runtime"
|
"github.com/wailsapp/wails/v2/internal/runtime"
|
||||||
@@ -12,15 +14,23 @@ import (
|
|||||||
// Log is the Logging subsystem. It handles messages with topics starting
|
// Log is the Logging subsystem. It handles messages with topics starting
|
||||||
// with "log:"
|
// with "log:"
|
||||||
type Log struct {
|
type Log struct {
|
||||||
logChannel <-chan *servicebus.Message
|
logChannel <-chan *servicebus.Message
|
||||||
quitChannel <-chan *servicebus.Message
|
|
||||||
running bool
|
// quit flag
|
||||||
|
shouldQuit bool
|
||||||
|
|
||||||
// Logger!
|
// Logger!
|
||||||
logger *logger.Logger
|
logger *logger.Logger
|
||||||
|
|
||||||
// Loglevel store
|
// Loglevel store
|
||||||
logLevelStore *runtime.Store
|
logLevelStore *runtime.Store
|
||||||
|
|
||||||
|
// Context for shutdown
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
|
||||||
|
// internal waitgroup
|
||||||
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLog creates a new log subsystem
|
// NewLog creates a new log subsystem
|
||||||
@@ -32,17 +42,14 @@ func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger, logLevelStore *ru
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to quit messages
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result := &Log{
|
result := &Log{
|
||||||
logChannel: logChannel,
|
logChannel: logChannel,
|
||||||
quitChannel: quitChannel,
|
|
||||||
logger: logger,
|
logger: logger,
|
||||||
logLevelStore: logLevelStore,
|
logLevelStore: logLevelStore,
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -51,15 +58,17 @@ func NewLog(bus *servicebus.ServiceBus, logger *logger.Logger, logLevelStore *ru
|
|||||||
// Start the subsystem
|
// Start the subsystem
|
||||||
func (l *Log) Start() error {
|
func (l *Log) Start() error {
|
||||||
|
|
||||||
l.running = true
|
l.wg.Add(1)
|
||||||
|
|
||||||
// Spin off a go routine
|
// Spin off a go routine
|
||||||
go func() {
|
go func() {
|
||||||
for l.running {
|
defer l.logger.Trace("Logger Shutdown")
|
||||||
|
|
||||||
|
for l.shouldQuit == false {
|
||||||
select {
|
select {
|
||||||
case <-l.quitChannel:
|
case <-l.ctx.Done():
|
||||||
l.running = false
|
l.wg.Done()
|
||||||
break
|
return
|
||||||
case logMessage := <-l.logChannel:
|
case logMessage := <-l.logChannel:
|
||||||
logType := strings.TrimPrefix(logMessage.Topic(), "log:")
|
logType := strings.TrimPrefix(logMessage.Topic(), "log:")
|
||||||
switch logType {
|
switch logType {
|
||||||
@@ -98,8 +107,12 @@ func (l *Log) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l.logger.Trace("Logger Shutdown")
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Log) Close() {
|
||||||
|
l.cancel()
|
||||||
|
l.wg.Wait()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package subsystem
|
package subsystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||||
@@ -13,9 +16,10 @@ import (
|
|||||||
// Menu is the subsystem that handles the operation of menus. It manages all service bus messages
|
// Menu is the subsystem that handles the operation of menus. It manages all service bus messages
|
||||||
// starting with "menu".
|
// starting with "menu".
|
||||||
type Menu struct {
|
type Menu struct {
|
||||||
quitChannel <-chan *servicebus.Message
|
|
||||||
menuChannel <-chan *servicebus.Message
|
menuChannel <-chan *servicebus.Message
|
||||||
running bool
|
|
||||||
|
// shutdown flag
|
||||||
|
shouldQuit bool
|
||||||
|
|
||||||
// logger
|
// logger
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
@@ -25,16 +29,16 @@ type Menu struct {
|
|||||||
|
|
||||||
// Menu Manager
|
// Menu Manager
|
||||||
menuManager *menumanager.Manager
|
menuManager *menumanager.Manager
|
||||||
|
|
||||||
|
// ctx
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
|
// parent waitgroup
|
||||||
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMenu creates a new menu subsystem
|
// NewMenu creates a new menu subsystem
|
||||||
func NewMenu(bus *servicebus.ServiceBus, logger *logger.Logger, menuManager *menumanager.Manager) (*Menu, error) {
|
func NewMenu(ctx context.Context, bus *servicebus.ServiceBus, logger *logger.Logger, menuManager *menumanager.Manager) (*Menu, error) {
|
||||||
|
|
||||||
// Register quit channel
|
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to menu messages
|
// Subscribe to menu messages
|
||||||
menuChannel, err := bus.Subscribe("menu:")
|
menuChannel, err := bus.Subscribe("menu:")
|
||||||
@@ -43,11 +47,12 @@ func NewMenu(bus *servicebus.ServiceBus, logger *logger.Logger, menuManager *men
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Menu{
|
result := &Menu{
|
||||||
quitChannel: quitChannel,
|
|
||||||
menuChannel: menuChannel,
|
menuChannel: menuChannel,
|
||||||
logger: logger.CustomLogger("Menu Subsystem"),
|
logger: logger.CustomLogger("Menu Subsystem"),
|
||||||
bus: bus,
|
bus: bus,
|
||||||
menuManager: menuManager,
|
menuManager: menuManager,
|
||||||
|
ctx: ctx,
|
||||||
|
wg: ctx.Value("waitgroup").(*sync.WaitGroup),
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -58,15 +63,16 @@ func (m *Menu) Start() error {
|
|||||||
|
|
||||||
m.logger.Trace("Starting")
|
m.logger.Trace("Starting")
|
||||||
|
|
||||||
m.running = true
|
m.wg.Add(1)
|
||||||
|
|
||||||
// Spin off a go routine
|
// Spin off a go routine
|
||||||
go func() {
|
go func() {
|
||||||
for m.running {
|
defer m.logger.Trace("Shutdown")
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-m.quitChannel:
|
case <-m.ctx.Done():
|
||||||
m.running = false
|
m.wg.Done()
|
||||||
break
|
return
|
||||||
case menuMessage := <-m.menuChannel:
|
case menuMessage := <-m.menuChannel:
|
||||||
splitTopic := strings.Split(menuMessage.Topic(), ":")
|
splitTopic := strings.Split(menuMessage.Topic(), ":")
|
||||||
menuMessageType := splitTopic[1]
|
menuMessageType := splitTopic[1]
|
||||||
@@ -147,14 +153,7 @@ func (m *Menu) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call shutdown
|
|
||||||
m.shutdown()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) shutdown() {
|
|
||||||
m.logger.Trace("Shutdown")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package subsystem
|
package subsystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -12,7 +13,6 @@ import (
|
|||||||
// Runtime is the Runtime subsystem. It handles messages with topics starting
|
// Runtime is the Runtime subsystem. It handles messages with topics starting
|
||||||
// with "runtime:"
|
// with "runtime:"
|
||||||
type Runtime struct {
|
type Runtime struct {
|
||||||
quitChannel <-chan *servicebus.Message
|
|
||||||
runtimeChannel <-chan *servicebus.Message
|
runtimeChannel <-chan *servicebus.Message
|
||||||
|
|
||||||
// The hooks channel allows us to hook into frontend startup
|
// The hooks channel allows us to hook into frontend startup
|
||||||
@@ -20,22 +20,20 @@ type Runtime struct {
|
|||||||
startupCallback func(*runtime.Runtime)
|
startupCallback func(*runtime.Runtime)
|
||||||
shutdownCallback func()
|
shutdownCallback func()
|
||||||
|
|
||||||
running bool
|
// quit flag
|
||||||
|
shouldQuit bool
|
||||||
|
|
||||||
logger logger.CustomLogger
|
logger logger.CustomLogger
|
||||||
|
|
||||||
// Runtime library
|
// Runtime library
|
||||||
runtime *runtime.Runtime
|
runtime *runtime.Runtime
|
||||||
|
|
||||||
|
//ctx
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRuntime creates a new runtime subsystem
|
// NewRuntime creates a new runtime subsystem
|
||||||
func NewRuntime(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), shutdownCallback func()) (*Runtime, error) {
|
||||||
|
|
||||||
// Register quit channel
|
|
||||||
quitChannel, err := bus.Subscribe("quit")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe to log messages
|
// Subscribe to log messages
|
||||||
runtimeChannel, err := bus.Subscribe("runtime:")
|
runtimeChannel, err := bus.Subscribe("runtime:")
|
||||||
@@ -50,13 +48,13 @@ func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger, startupCallba
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &Runtime{
|
result := &Runtime{
|
||||||
quitChannel: quitChannel,
|
|
||||||
runtimeChannel: runtimeChannel,
|
runtimeChannel: runtimeChannel,
|
||||||
hooksChannel: hooksChannel,
|
hooksChannel: hooksChannel,
|
||||||
logger: logger.CustomLogger("Runtime Subsystem"),
|
logger: logger.CustomLogger("Runtime Subsystem"),
|
||||||
runtime: runtime.New(bus),
|
runtime: runtime.New(bus, shutdownCallback),
|
||||||
startupCallback: startupCallback,
|
startupCallback: startupCallback,
|
||||||
shutdownCallback: shutdownCallback,
|
shutdownCallback: shutdownCallback,
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -65,15 +63,11 @@ func NewRuntime(bus *servicebus.ServiceBus, logger *logger.Logger, startupCallba
|
|||||||
// Start the subsystem
|
// Start the subsystem
|
||||||
func (r *Runtime) Start() error {
|
func (r *Runtime) Start() error {
|
||||||
|
|
||||||
r.running = true
|
|
||||||
|
|
||||||
// Spin off a go routine
|
// Spin off a go routine
|
||||||
go func() {
|
go func() {
|
||||||
for r.running {
|
defer r.logger.Trace("Shutdown")
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-r.quitChannel:
|
|
||||||
r.running = false
|
|
||||||
break
|
|
||||||
case hooksMessage := <-r.hooksChannel:
|
case hooksMessage := <-r.hooksChannel:
|
||||||
r.logger.Trace(fmt.Sprintf("Received hooksmessage: %+v", hooksMessage))
|
r.logger.Trace(fmt.Sprintf("Received hooksmessage: %+v", hooksMessage))
|
||||||
messageSlice := strings.Split(hooksMessage.Topic(), ":")
|
messageSlice := strings.Split(hooksMessage.Topic(), ":")
|
||||||
@@ -113,11 +107,10 @@ func (r *Runtime) Start() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Error(err.Error())
|
r.logger.Error(err.Error())
|
||||||
}
|
}
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call shutdown
|
|
||||||
r.shutdown()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -128,15 +121,6 @@ func (r *Runtime) GoRuntime() *runtime.Runtime {
|
|||||||
return r.runtime
|
return r.runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runtime) shutdown() {
|
|
||||||
if r.shutdownCallback != nil {
|
|
||||||
go r.shutdownCallback()
|
|
||||||
} else {
|
|
||||||
r.logger.Warning("no shutdown callback registered!")
|
|
||||||
}
|
|
||||||
r.logger.Trace("Shutdown")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Runtime) processBrowserMessage(method string, data interface{}) error {
|
func (r *Runtime) processBrowserMessage(method string, data interface{}) error {
|
||||||
switch method {
|
switch method {
|
||||||
case "open":
|
case "open":
|
||||||
|
|||||||
@@ -14,27 +14,28 @@ import (
|
|||||||
|
|
||||||
// App contains options for creating the App
|
// App contains options for creating the App
|
||||||
type App struct {
|
type App struct {
|
||||||
Title string
|
Title string
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
DisableResize bool
|
DisableResize bool
|
||||||
Fullscreen bool
|
Fullscreen bool
|
||||||
MinWidth int
|
MinWidth int
|
||||||
MinHeight int
|
MinHeight int
|
||||||
MaxWidth int
|
MaxWidth int
|
||||||
MaxHeight int
|
MaxHeight int
|
||||||
StartHidden bool
|
StartHidden bool
|
||||||
DevTools bool
|
HideWindowOnClose bool
|
||||||
RGBA int
|
DevTools bool
|
||||||
ContextMenus []*menu.ContextMenu
|
RGBA int
|
||||||
TrayMenus []*menu.TrayMenu
|
ContextMenus []*menu.ContextMenu
|
||||||
Menu *menu.Menu
|
TrayMenus []*menu.TrayMenu
|
||||||
Mac *mac.Options
|
Menu *menu.Menu
|
||||||
Logger logger.Logger `json:"-"`
|
Mac *mac.Options
|
||||||
LogLevel logger.LogLevel
|
Logger logger.Logger `json:"-"`
|
||||||
Startup func(*wailsruntime.Runtime) `json:"-"`
|
LogLevel logger.LogLevel
|
||||||
Shutdown func() `json:"-"`
|
Startup func(*wailsruntime.Runtime) `json:"-"`
|
||||||
Bind []interface{}
|
Shutdown func() `json:"-"`
|
||||||
|
Bind []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergeDefaults will set the minimum default values for an application
|
// MergeDefaults will set the minimum default values for an application
|
||||||
|
|||||||
Reference in New Issue
Block a user