From e7abe1c606f4ee21d533ea85cef9c85ddee84d6c Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Mon, 19 Dec 2022 21:17:50 +1100 Subject: [PATCH] Add Webview navigation events Add HTML/JS/CSS in config Add RenderHTML() Tidy up window delegate --- exp/examples/plain/main.go | 32 +++ exp/go.mod | 7 +- exp/go.sum | 9 - exp/pkg/application/app_delegate.h | 2 - exp/pkg/application/app_delegate.m | 27 +-- exp/pkg/application/application_darwin.go | 7 +- exp/pkg/application/keys.go | 68 +++++- exp/pkg/application/window.go | 17 +- exp/pkg/application/window_darwin.go | 103 +++++++--- exp/pkg/application/window_delegate.h | 2 +- exp/pkg/application/window_delegate.m | 41 ++-- exp/pkg/events/events.go | 240 +++++++++++----------- exp/pkg/events/events.h | 4 + exp/pkg/events/events.txt | 7 +- exp/pkg/options/window.go | 3 + exp/tasks/events/generate.go | 168 ++++++++------- 16 files changed, 447 insertions(+), 290 deletions(-) create mode 100644 exp/examples/plain/main.go diff --git a/exp/examples/plain/main.go b/exp/examples/plain/main.go new file mode 100644 index 000000000..64096a4b5 --- /dev/null +++ b/exp/examples/plain/main.go @@ -0,0 +1,32 @@ +package main + +import ( + _ "embed" + "log" + + "github.com/wailsapp/wails/exp/pkg/options" + + "github.com/wailsapp/wails/exp/pkg/application" +) + +func main() { + app := application.New() + + // Create window + app.NewWindowWithOptions(&options.Window{ + Title: "Plain Bundle", + EnableDevTools: true, + HTML: `Plain Bundle

Plain Bundle

This is a plain bundle. It has no frontend code.

`, + CSS: `body { background-color: rgba(255, 255, 255, 0); } .main { color: white; margin: 20%; }`, + Mac: &options.MacWindow{ + Backdrop: options.MacBackdropTranslucent, + TitleBar: options.TitleBarHiddenInset, + }, + }) + + err := app.Run() + + if err != nil { + log.Fatal(err) + } +} diff --git a/exp/go.mod b/exp/go.mod index 19cc91829..1969eb348 100644 --- a/exp/go.mod +++ b/exp/go.mod @@ -2,9 +2,4 @@ module github.com/wailsapp/wails/exp go 1.19 -require ( - github.com/leaanthony/clir v1.3.0 - github.com/samber/lo v1.36.0 -) - -require golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect +require github.com/leaanthony/clir v1.3.0 diff --git a/exp/go.sum b/exp/go.sum index eb2ed5fb8..ec90627a4 100644 --- a/exp/go.sum +++ b/exp/go.sum @@ -1,11 +1,2 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/leaanthony/clir v1.3.0 h1:L9nPDWrmc/qU9UWZZvRaFajWYuO0np9V5p+5gxyYno0= github.com/leaanthony/clir v1.3.0/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw= -github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/exp/pkg/application/app_delegate.h b/exp/pkg/application/app_delegate.h index db8021543..1d288bd6b 100644 --- a/exp/pkg/application/app_delegate.h +++ b/exp/pkg/application/app_delegate.h @@ -6,8 +6,6 @@ #import @interface AppDelegate : NSObject -@property NSApplicationActivationPolicy activationPolicy; -- (void)setApplicationActivationPolicy:(NSApplicationActivationPolicy)policy; @end #endif diff --git a/exp/pkg/application/app_delegate.m b/exp/pkg/application/app_delegate.m index 120efe38e..c3a7bdcde 100644 --- a/exp/pkg/application/app_delegate.m +++ b/exp/pkg/application/app_delegate.m @@ -1,31 +1,12 @@ //go:build darwin - #import "app_delegate.h" #import "../events/events.h" - @implementation AppDelegate - - (void)dealloc { [super dealloc]; } -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ - [NSApp setActivationPolicy:self.activationPolicy]; - [NSApp activateIgnoringOtherApps:YES]; - - //callOnApplicationDidFinishLaunchingHandler(); - processApplicationEvent(EventApplicationDidFinishLaunching); - -} - - -- (void)setApplicationActivationPolicy:(NSApplicationActivationPolicy)policy -{ - self.activationPolicy = policy; -} - // GENERATED EVENTS START - (void)applicationDidBecomeActive:(NSNotification *)notification { processApplicationEvent(EventApplicationDidBecomeActive); @@ -59,6 +40,10 @@ processApplicationEvent(EventApplicationDidChangeStatusBarOrientation); } +- (void)applicationDidFinishLaunching:(NSNotification *)notification { + processApplicationEvent(EventApplicationDidFinishLaunching); +} + - (void)applicationDidHide:(NSNotification *)notification { processApplicationEvent(EventApplicationDidHide); } @@ -104,8 +89,4 @@ } // GENERATED EVENTS END - @end - - - diff --git a/exp/pkg/application/application_darwin.go b/exp/pkg/application/application_darwin.go index 355b37690..4699383fe 100644 --- a/exp/pkg/application/application_darwin.go +++ b/exp/pkg/application/application_darwin.go @@ -23,7 +23,11 @@ static void init(void) { } static void setActivationPolicy(int policy) { - [appDelegate setApplicationActivationPolicy:policy]; + [NSApp setActivationPolicy:policy]; +} + +static void activateIgnoringOtherApps() { + [NSApp activateIgnoringOtherApps:YES]; } static void run(void) { @@ -123,6 +127,7 @@ func newPlatformApp(appOptions *options.Application) *macosApp { } C.init() C.setActivationPolicy(C.int(appOptions.Mac.ActivationPolicy)) + C.activateIgnoringOtherApps() return &macosApp{ options: appOptions, } diff --git a/exp/pkg/application/keys.go b/exp/pkg/application/keys.go index 4670e1833..d7d1beaf7 100644 --- a/exp/pkg/application/keys.go +++ b/exp/pkg/application/keys.go @@ -4,8 +4,6 @@ import ( "fmt" "strconv" "strings" - - "github.com/samber/lo" ) // modifier is actually a string @@ -42,7 +40,59 @@ type accelerator struct { Modifiers []modifier } -var namedKeys = []string{"backspace", "tab", "return", "enter", "escape", "left", "right", "up", "down", "space", "delete", "home", "end", "page up", "page down", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", "f33", "f34", "f35", "numlock"} +var namedKeys = map[string]struct{}{ + "backspace": {}, + "tab": {}, + "return": {}, + "enter": {}, + "escape": {}, + "left": {}, + "right": {}, + "up": {}, + "down": {}, + "space": {}, + "delete": {}, + "home": {}, + "end": {}, + "page up": {}, + "page down": {}, + "f1": {}, + "f2": {}, + "f3": {}, + "f4": {}, + "f5": {}, + "f6": {}, + "f7": {}, + "f8": {}, + "f9": {}, + "f10": {}, + "f11": {}, + "f12": {}, + "f13": {}, + "f14": {}, + "f15": {}, + "f16": {}, + "f17": {}, + "f18": {}, + "f19": {}, + "f20": {}, + "f21": {}, + "f22": {}, + "f23": {}, + "f24": {}, + "f25": {}, + "f26": {}, + "f27": {}, + "f28": {}, + "f29": {}, + "f30": {}, + "f31": {}, + "f32": {}, + "f33": {}, + "f34": {}, + "f35": {}, + "numlock": {}, +} func parseKey(key string) (string, bool) { @@ -55,7 +105,8 @@ func parseKey(key string) (string, bool) { } // Handle named keys - if lo.Contains(namedKeys, key) { + _, namedKey := namedKeys[key] + if namedKey { return key, true } @@ -89,6 +140,8 @@ func parseAccelerator(shortcut string) (*accelerator, error) { return nil, fmt.Errorf("no components given to validateComponents") } + modifiers := map[modifier]struct{}{} + // Check components for index, component := range components { @@ -109,10 +162,11 @@ func parseAccelerator(shortcut string) (*accelerator, error) { return nil, fmt.Errorf("'%s' is not a valid modifier", component) } // Save this data + modifiers[thisModifier] = struct{}{} + } + // return the keys as a slice + for thisModifier := range modifiers { result.Modifiers = append(result.Modifiers, thisModifier) } - - result.Modifiers = lo.Uniq(result.Modifiers) - return &result, nil } diff --git a/exp/pkg/application/window.go b/exp/pkg/application/window.go index 250767f58..2e90085e5 100644 --- a/exp/pkg/application/window.go +++ b/exp/pkg/application/window.go @@ -43,6 +43,7 @@ type windowImpl interface { close() zoom() minimize() + renderHTML(html string) } type Window struct { @@ -66,6 +67,12 @@ func getWindowID() uint { } func NewWindow(options *options.Window) *Window { + if options.Width == 0 { + options.Width = 800 + } + if options.Height == 0 { + options.Height = 600 + } return &Window{ id: getWindowID(), options: options, @@ -94,7 +101,7 @@ func (w *Window) SetSize(width, height int) { func (w *Window) Run() { w.implLock.Lock() - w.impl = newWindowImpl(w.id, w.options) + w.impl = newWindowImpl(w) w.implLock.Unlock() w.impl.run() } @@ -173,7 +180,6 @@ func (w *Window) ExecJS(js string) { w.impl.execJS(js) } -// Set Maximized func (w *Window) SetMaximized() { w.options.StartState = options.WindowStateMaximised if w.impl == nil { @@ -375,3 +381,10 @@ func (w *Window) Zoom() { } w.impl.zoom() } + +func (w *Window) RenderHTML(html string) { + if w.impl == nil { + return + } + w.impl.renderHTML(html) +} diff --git a/exp/pkg/application/window_darwin.go b/exp/pkg/application/window_darwin.go index 595f813f7..db0e187a4 100644 --- a/exp/pkg/application/window_darwin.go +++ b/exp/pkg/application/window_darwin.go @@ -45,6 +45,9 @@ void* windowNew(unsigned int id, int width, int height) { WKWebView* webView = [[WKWebView alloc] initWithFrame:frame configuration:config]; [view addSubview:webView]; + // support webview events + [webView setNavigationDelegate:delegate]; + // Ensure webview resizes with the window [webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; @@ -229,14 +232,18 @@ void windowZoomOut(void* nsWindow) { } // Execute JS in NSWindow -void windowExecJS(void* nsWindow, char* js) { +void windowExecJS(void* nsWindow, const char* js) { +printf("windowExecJS\n"); // Execute JS on main thread dispatch_async(dispatch_get_main_queue(), ^{ +printf("windowExecJS 2\n"); + // Get window delegate WindowDelegate* delegate = (WindowDelegate*)[(NSWindow*)nsWindow delegate]; // Execute JS in webview + printf("windowExecJS: %s\n", js); [delegate.webView evaluateJavaScript:[NSString stringWithUTF8String:js] completionHandler:nil]; - free(js); + free((void*)js); }); } @@ -546,23 +553,47 @@ static void windowMaximize(void *window) { [(NSWindow*)window zoom:nil]; }); } + +// webviewRenderHTML renders the given HTML +static void windowRenderHTML(void *window, const char *html) { + dispatch_async(dispatch_get_main_queue(), ^{ + // get main window + NSWindow* nsWindow = (NSWindow*)window; + // get window delegate + WindowDelegate* windowDelegate = (WindowDelegate*)[nsWindow delegate]; + // render html + [(WKWebView*)windowDelegate.webView loadHTMLString:[NSString stringWithUTF8String:html] baseURL:nil]; + }); +} + +static void windowInjectCSS(void *window, const char *css) { + dispatch_async(dispatch_get_main_queue(), ^{ + // get main window + NSWindow* nsWindow = (NSWindow*)window; + // get window delegate + WindowDelegate* windowDelegate = (WindowDelegate*)[nsWindow delegate]; + // inject css + [(WKWebView*)windowDelegate.webView evaluateJavaScript:[NSString stringWithFormat:@"(function() { var style = document.createElement('style'); style.appendChild(document.createTextNode('%@')); document.head.appendChild(style); })();", [NSString stringWithUTF8String:css]] completionHandler:nil]; + free((void*)css); + }); +} + */ import "C" import ( "sync" "unsafe" + "github.com/wailsapp/wails/exp/pkg/events" + "github.com/wailsapp/wails/exp/pkg/options" ) var showDevTools = func(window unsafe.Pointer) {} type macosWindow struct { - id uint nsWindow unsafe.Pointer - options *options.Window - - // devtools + parent *Window } func (w *macosWindow) zoom() { @@ -603,12 +634,12 @@ func (w *macosWindow) toggleFullscreen() { func (w *macosWindow) reload() { //TODO: Implement - println("reload called on Window", w.id) + println("reload called on Window", w.parent.id) } func (w *macosWindow) forceReload() { //TODO: Implement - println("forceReload called on Window", w.id) + println("forceReload called on Window", w.parent.id) } func (w *macosWindow) center() { @@ -667,6 +698,7 @@ func (w *macosWindow) restoreWindow() { } func (w *macosWindow) execJS(js string) { + println("execJS called on Window", w.parent.id) C.windowExecJS(w.nsWindow, C.CString(js)) } @@ -678,10 +710,9 @@ func (w *macosWindow) setAlwaysOnTop(alwaysOnTop bool) { C.windowSetAlwaysOnTop(w.nsWindow, C.bool(alwaysOnTop)) } -func newWindowImpl(id uint, options *options.Window) *macosWindow { +func newWindowImpl(parent *Window) *macosWindow { result := &macosWindow{ - id: id, - options: options, + parent: parent, } return result } @@ -746,22 +777,22 @@ func (w *macosWindow) height() int { func (w *macosWindow) run() { DispatchOnMainThread(func() { - w.nsWindow = C.windowNew(C.uint(w.id), C.int(w.options.Width), C.int(w.options.Height)) - w.setTitle(w.options.Title) - w.setAlwaysOnTop(w.options.AlwaysOnTop) - w.setResizable(!w.options.DisableResize) - if w.options.MinWidth != 0 || w.options.MinHeight != 0 { - w.setMinSize(w.options.MinWidth, w.options.MinHeight) + w.nsWindow = C.windowNew(C.uint(w.parent.id), C.int(w.parent.options.Width), C.int(w.parent.options.Height)) + w.setTitle(w.parent.options.Title) + w.setAlwaysOnTop(w.parent.options.AlwaysOnTop) + w.setResizable(!w.parent.options.DisableResize) + if w.parent.options.MinWidth != 0 || w.parent.options.MinHeight != 0 { + w.setMinSize(w.parent.options.MinWidth, w.parent.options.MinHeight) } - if w.options.MaxWidth != 0 || w.options.MaxHeight != 0 { - w.setMaxSize(w.options.MaxWidth, w.options.MaxHeight) + if w.parent.options.MaxWidth != 0 || w.parent.options.MaxHeight != 0 { + w.setMaxSize(w.parent.options.MaxWidth, w.parent.options.MaxHeight) } - if w.options.EnableDevTools { + if w.parent.options.EnableDevTools { w.enableDevTools() } - w.setBackgroundColor(w.options.BackgroundColour) - if w.options.Mac != nil { - macOptions := w.options.Mac + w.setBackgroundColor(w.parent.options.BackgroundColour) + if w.parent.options.Mac != nil { + macOptions := w.parent.options.Mac switch macOptions.Backdrop { case options.MacBackdropTransparent: C.windowSetTransparent(w.nsWindow) @@ -785,7 +816,7 @@ func (w *macosWindow) run() { C.windowSetAppearanceTypeByName(w.nsWindow, C.CString(string(macOptions.Appearance))) } - switch w.options.StartState { + switch w.parent.options.StartState { case options.WindowStateMaximised: w.setMaximised() case options.WindowStateMinimised: @@ -798,9 +829,22 @@ func (w *macosWindow) run() { } C.windowCenter(w.nsWindow) - if w.options.URL != "" { - w.navigateToURL(w.options.URL) + if w.parent.options.URL != "" { + w.navigateToURL(w.parent.options.URL) } + // Ee need to wait for the HTML to load before we can execute the javascript + w.parent.On(events.Mac.WebViewDidFinishNavigation, func() { + if w.parent.options.JS != "" { + w.execJS(w.parent.options.JS) + } + if w.parent.options.CSS != "" { + C.windowInjectCSS(w.nsWindow, C.CString(w.parent.options.CSS)) + } + }) + if w.parent.options.HTML != "" { + w.renderHTML(w.parent.options.HTML) + } + C.windowShow(w.nsWindow) }) } @@ -827,3 +871,10 @@ func (w *macosWindow) position() (int, int) { func (w *macosWindow) destroy() { C.windowDestroy(w.nsWindow) } + +func (w *macosWindow) renderHTML(html string) { + // Convert HTML to C string + cHTML := C.CString(html) + // Render HTML + C.windowRenderHTML(w.nsWindow, cHTML) +} diff --git a/exp/pkg/application/window_delegate.h b/exp/pkg/application/window_delegate.h index c0446abee..3927efc6f 100644 --- a/exp/pkg/application/window_delegate.h +++ b/exp/pkg/application/window_delegate.h @@ -6,7 +6,7 @@ #import #import -@interface WindowDelegate : NSObject +@interface WindowDelegate : NSObject @property bool hideOnClose; @property (retain) WKWebView* webView; diff --git a/exp/pkg/application/window_delegate.m b/exp/pkg/application/window_delegate.m index 5a5488c4d..8f21e7086 100644 --- a/exp/pkg/application/window_delegate.m +++ b/exp/pkg/application/window_delegate.m @@ -5,14 +5,11 @@ // // Created by Lea Anthony on 10/10/21. // - #import #import #import "window_delegate.h" #import "../events/events.h" - extern void processMessage(unsigned int, const char*); - @implementation WindowDelegate - (BOOL)windowShouldClose:(NSWindow *)sender { if( self.hideOnClose ) { @@ -21,11 +18,9 @@ extern void processMessage(unsigned int, const char*); } return true; } - // Handle script messages from the external bridge - (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message { NSString *m = message.body; - /* // TODO: Check for drag if ( [m isEqualToString:@"drag"] ) { @@ -38,12 +33,14 @@ extern void processMessage(unsigned int, const char*); return; } */ - const char *_m = [m UTF8String]; - processMessage(self.windowId, _m); } +- (void) mouseDown:(NSEvent*)someEvent { + NSLog(@"MOUSE DOWN!!!"); +} + // GENERATED EVENTS START - (void)windowDidBecomeKey:(NSNotification *)notification { processWindowEvent(self.windowId, EventWindowDidBecomeKey); @@ -337,19 +334,21 @@ extern void processMessage(unsigned int, const char*); processWindowEvent(self.windowId, EventWindowWillUseStandardFrame); } +- (void)webView:(WKWebView *)webview didStartProvisionalNavigation:(WKNavigation *)navigation { + processWindowEvent(self.windowId, EventWebViewDidStartProvisionalNavigation); +} + +- (void)webView:(WKWebView *)webview didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation { + processWindowEvent(self.windowId, EventWebViewDidReceiveServerRedirectForProvisionalNavigation); +} + +- (void)webView:(WKWebView *)webview didFinishNavigation:(WKNavigation *)navigation { + processWindowEvent(self.windowId, EventWebViewDidFinishNavigation); +} + +- (void)webView:(WKWebView *)webview didCommitNavigation:(WKNavigation *)navigation { + processWindowEvent(self.windowId, EventWebViewDidCommitNavigation); +} + // GENERATED EVENTS END - @end - - - - - - - - - - - - - diff --git a/exp/pkg/events/events.go b/exp/pkg/events/events.go index eaca310f8..f003e7c49 100644 --- a/exp/pkg/events/events.go +++ b/exp/pkg/events/events.go @@ -6,122 +6,126 @@ type WindowEventType uint var Mac = newMacEvents() type macEvents struct { - ApplicationDidBecomeActive ApplicationEventType - ApplicationDidChangeBackingProperties ApplicationEventType - ApplicationDidChangeEffectiveAppearance ApplicationEventType - ApplicationDidChangeIcon ApplicationEventType - ApplicationDidChangeOcclusionState ApplicationEventType - ApplicationDidChangeScreenParameters ApplicationEventType - ApplicationDidChangeStatusBarFrame ApplicationEventType - ApplicationDidChangeStatusBarOrientation ApplicationEventType - ApplicationDidFinishLaunching ApplicationEventType - ApplicationDidHide ApplicationEventType - ApplicationDidResignActive ApplicationEventType - ApplicationDidUnhide ApplicationEventType - ApplicationDidUpdate ApplicationEventType - ApplicationWillBecomeActive ApplicationEventType - ApplicationWillFinishLaunching ApplicationEventType - ApplicationWillHide ApplicationEventType - ApplicationWillResignActive ApplicationEventType - ApplicationWillTerminate ApplicationEventType - ApplicationWillUnhide ApplicationEventType - ApplicationWillUpdate ApplicationEventType - WindowDidBecomeKey WindowEventType - WindowDidBecomeMain WindowEventType - WindowDidBeginSheet WindowEventType - WindowDidChangeAlpha WindowEventType - WindowDidChangeBackingLocation WindowEventType - WindowDidChangeBackingProperties WindowEventType - WindowDidChangeCollectionBehavior WindowEventType - WindowDidChangeEffectiveAppearance WindowEventType - WindowDidChangeOcclusionState WindowEventType - WindowDidChangeOrderingMode WindowEventType - WindowDidChangeScreen WindowEventType - WindowDidChangeScreenParameters WindowEventType - WindowDidChangeScreenProfile WindowEventType - WindowDidChangeScreenSpace WindowEventType - WindowDidChangeScreenSpaceProperties WindowEventType - WindowDidChangeSharingType WindowEventType - WindowDidChangeSpace WindowEventType - WindowDidChangeSpaceOrderingMode WindowEventType - WindowDidChangeTitle WindowEventType - WindowDidChangeToolbar WindowEventType - WindowDidChangeVisibility WindowEventType - WindowDidClose WindowEventType - WindowDidDeminiaturize WindowEventType - WindowDidEndSheet WindowEventType - WindowDidEnterFullScreen WindowEventType - WindowDidEnterVersionBrowser WindowEventType - WindowDidExitFullScreen WindowEventType - WindowDidExitVersionBrowser WindowEventType - WindowDidExpose WindowEventType - WindowDidFocus WindowEventType - WindowDidMiniaturize WindowEventType - WindowDidMove WindowEventType - WindowDidOrderOffScreen WindowEventType - WindowDidOrderOnScreen WindowEventType - WindowDidResignKey WindowEventType - WindowDidResignMain WindowEventType - WindowDidResize WindowEventType - WindowDidUnfocus WindowEventType - WindowDidUpdate WindowEventType - WindowDidUpdateAlpha WindowEventType - WindowDidUpdateCollectionBehavior WindowEventType - WindowDidUpdateCollectionProperties WindowEventType - WindowDidUpdateShadow WindowEventType - WindowDidUpdateTitle WindowEventType - WindowDidUpdateToolbar WindowEventType - WindowDidUpdateVisibility WindowEventType - WindowWillBecomeKey WindowEventType - WindowWillBecomeMain WindowEventType - WindowWillBeginSheet WindowEventType - WindowWillChangeOrderingMode WindowEventType - WindowWillClose WindowEventType - WindowWillDeminiaturize WindowEventType - WindowWillEnterFullScreen WindowEventType - WindowWillEnterVersionBrowser WindowEventType - WindowWillExitFullScreen WindowEventType - WindowWillExitVersionBrowser WindowEventType - WindowWillFocus WindowEventType - WindowWillMiniaturize WindowEventType - WindowWillMove WindowEventType - WindowWillOrderOffScreen WindowEventType - WindowWillOrderOnScreen WindowEventType - WindowWillResignMain WindowEventType - WindowWillResize WindowEventType - WindowWillUnfocus WindowEventType - WindowWillUpdate WindowEventType - WindowWillUpdateAlpha WindowEventType - WindowWillUpdateCollectionBehavior WindowEventType - WindowWillUpdateCollectionProperties WindowEventType - WindowWillUpdateShadow WindowEventType - WindowWillUpdateTitle WindowEventType - WindowWillUpdateToolbar WindowEventType - WindowWillUpdateVisibility WindowEventType - WindowWillUseStandardFrame WindowEventType - MenuWillOpen ApplicationEventType - MenuDidOpen ApplicationEventType - MenuDidClose ApplicationEventType - MenuWillSendAction ApplicationEventType - MenuDidSendAction ApplicationEventType - MenuWillHighlightItem ApplicationEventType - MenuDidHighlightItem ApplicationEventType - MenuWillDisplayItem ApplicationEventType - MenuDidDisplayItem ApplicationEventType - MenuWillAddItem ApplicationEventType - MenuDidAddItem ApplicationEventType - MenuWillRemoveItem ApplicationEventType - MenuDidRemoveItem ApplicationEventType - MenuWillBeginTracking ApplicationEventType - MenuDidBeginTracking ApplicationEventType - MenuWillEndTracking ApplicationEventType - MenuDidEndTracking ApplicationEventType - MenuWillUpdate ApplicationEventType - MenuDidUpdate ApplicationEventType - MenuWillPopUp ApplicationEventType - MenuDidPopUp ApplicationEventType - MenuWillSendActionToItem ApplicationEventType - MenuDidSendActionToItem ApplicationEventType + ApplicationDidBecomeActive ApplicationEventType + ApplicationDidChangeBackingProperties ApplicationEventType + ApplicationDidChangeEffectiveAppearance ApplicationEventType + ApplicationDidChangeIcon ApplicationEventType + ApplicationDidChangeOcclusionState ApplicationEventType + ApplicationDidChangeScreenParameters ApplicationEventType + ApplicationDidChangeStatusBarFrame ApplicationEventType + ApplicationDidChangeStatusBarOrientation ApplicationEventType + ApplicationDidFinishLaunching ApplicationEventType + ApplicationDidHide ApplicationEventType + ApplicationDidResignActive ApplicationEventType + ApplicationDidUnhide ApplicationEventType + ApplicationDidUpdate ApplicationEventType + ApplicationWillBecomeActive ApplicationEventType + ApplicationWillFinishLaunching ApplicationEventType + ApplicationWillHide ApplicationEventType + ApplicationWillResignActive ApplicationEventType + ApplicationWillTerminate ApplicationEventType + ApplicationWillUnhide ApplicationEventType + ApplicationWillUpdate ApplicationEventType + WindowDidBecomeKey WindowEventType + WindowDidBecomeMain WindowEventType + WindowDidBeginSheet WindowEventType + WindowDidChangeAlpha WindowEventType + WindowDidChangeBackingLocation WindowEventType + WindowDidChangeBackingProperties WindowEventType + WindowDidChangeCollectionBehavior WindowEventType + WindowDidChangeEffectiveAppearance WindowEventType + WindowDidChangeOcclusionState WindowEventType + WindowDidChangeOrderingMode WindowEventType + WindowDidChangeScreen WindowEventType + WindowDidChangeScreenParameters WindowEventType + WindowDidChangeScreenProfile WindowEventType + WindowDidChangeScreenSpace WindowEventType + WindowDidChangeScreenSpaceProperties WindowEventType + WindowDidChangeSharingType WindowEventType + WindowDidChangeSpace WindowEventType + WindowDidChangeSpaceOrderingMode WindowEventType + WindowDidChangeTitle WindowEventType + WindowDidChangeToolbar WindowEventType + WindowDidChangeVisibility WindowEventType + WindowDidClose WindowEventType + WindowDidDeminiaturize WindowEventType + WindowDidEndSheet WindowEventType + WindowDidEnterFullScreen WindowEventType + WindowDidEnterVersionBrowser WindowEventType + WindowDidExitFullScreen WindowEventType + WindowDidExitVersionBrowser WindowEventType + WindowDidExpose WindowEventType + WindowDidFocus WindowEventType + WindowDidMiniaturize WindowEventType + WindowDidMove WindowEventType + WindowDidOrderOffScreen WindowEventType + WindowDidOrderOnScreen WindowEventType + WindowDidResignKey WindowEventType + WindowDidResignMain WindowEventType + WindowDidResize WindowEventType + WindowDidUnfocus WindowEventType + WindowDidUpdate WindowEventType + WindowDidUpdateAlpha WindowEventType + WindowDidUpdateCollectionBehavior WindowEventType + WindowDidUpdateCollectionProperties WindowEventType + WindowDidUpdateShadow WindowEventType + WindowDidUpdateTitle WindowEventType + WindowDidUpdateToolbar WindowEventType + WindowDidUpdateVisibility WindowEventType + WindowWillBecomeKey WindowEventType + WindowWillBecomeMain WindowEventType + WindowWillBeginSheet WindowEventType + WindowWillChangeOrderingMode WindowEventType + WindowWillClose WindowEventType + WindowWillDeminiaturize WindowEventType + WindowWillEnterFullScreen WindowEventType + WindowWillEnterVersionBrowser WindowEventType + WindowWillExitFullScreen WindowEventType + WindowWillExitVersionBrowser WindowEventType + WindowWillFocus WindowEventType + WindowWillMiniaturize WindowEventType + WindowWillMove WindowEventType + WindowWillOrderOffScreen WindowEventType + WindowWillOrderOnScreen WindowEventType + WindowWillResignMain WindowEventType + WindowWillResize WindowEventType + WindowWillUnfocus WindowEventType + WindowWillUpdate WindowEventType + WindowWillUpdateAlpha WindowEventType + WindowWillUpdateCollectionBehavior WindowEventType + WindowWillUpdateCollectionProperties WindowEventType + WindowWillUpdateShadow WindowEventType + WindowWillUpdateTitle WindowEventType + WindowWillUpdateToolbar WindowEventType + WindowWillUpdateVisibility WindowEventType + WindowWillUseStandardFrame WindowEventType + MenuWillOpen ApplicationEventType + MenuDidOpen ApplicationEventType + MenuDidClose ApplicationEventType + MenuWillSendAction ApplicationEventType + MenuDidSendAction ApplicationEventType + MenuWillHighlightItem ApplicationEventType + MenuDidHighlightItem ApplicationEventType + MenuWillDisplayItem ApplicationEventType + MenuDidDisplayItem ApplicationEventType + MenuWillAddItem ApplicationEventType + MenuDidAddItem ApplicationEventType + MenuWillRemoveItem ApplicationEventType + MenuDidRemoveItem ApplicationEventType + MenuWillBeginTracking ApplicationEventType + MenuDidBeginTracking ApplicationEventType + MenuWillEndTracking ApplicationEventType + MenuDidEndTracking ApplicationEventType + MenuWillUpdate ApplicationEventType + MenuDidUpdate ApplicationEventType + MenuWillPopUp ApplicationEventType + MenuDidPopUp ApplicationEventType + MenuWillSendActionToItem ApplicationEventType + MenuDidSendActionToItem ApplicationEventType + WebViewDidStartProvisionalNavigation WindowEventType + WebViewDidReceiveServerRedirectForProvisionalNavigation WindowEventType + WebViewDidFinishNavigation WindowEventType + WebViewDidCommitNavigation WindowEventType } func newMacEvents() macEvents { @@ -242,5 +246,9 @@ func newMacEvents() macEvents { MenuDidPopUp: 113, MenuWillSendActionToItem: 114, MenuDidSendActionToItem: 115, + WebViewDidStartProvisionalNavigation: 116, + WebViewDidReceiveServerRedirectForProvisionalNavigation: 117, + WebViewDidFinishNavigation: 118, + WebViewDidCommitNavigation: 119, } } diff --git a/exp/pkg/events/events.h b/exp/pkg/events/events.h index 85e700a95..02de910be 100644 --- a/exp/pkg/events/events.h +++ b/exp/pkg/events/events.h @@ -122,6 +122,10 @@ extern void processWindowEvent(unsigned int, unsigned int); #define EventMenuDidPopUp 113 #define EventMenuWillSendActionToItem 114 #define EventMenuDidSendActionToItem 115 +#define EventWebViewDidStartProvisionalNavigation 116 +#define EventWebViewDidReceiveServerRedirectForProvisionalNavigation 117 +#define EventWebViewDidFinishNavigation 118 +#define EventWebViewDidCommitNavigation 119 #endif \ No newline at end of file diff --git a/exp/pkg/events/events.txt b/exp/pkg/events/events.txt index 4eacfe99b..858bb2ad5 100644 --- a/exp/pkg/events/events.txt +++ b/exp/pkg/events/events.txt @@ -6,7 +6,7 @@ mac:ApplicationDidChangeOcclusionState mac:ApplicationDidChangeScreenParameters mac:ApplicationDidChangeStatusBarFrame mac:ApplicationDidChangeStatusBarOrientation -mac:ApplicationDidFinishLaunching! +mac:ApplicationDidFinishLaunching mac:ApplicationDidHide mac:ApplicationDidResignActive mac:ApplicationDidUnhide @@ -114,3 +114,8 @@ mac:MenuWillPopUp mac:MenuDidPopUp mac:MenuWillSendActionToItem mac:MenuDidSendActionToItem +mac:WebViewDidStartProvisionalNavigation +mac:WebViewDidReceiveServerRedirectForProvisionalNavigation +mac:WebViewDidFinishNavigation +mac:WebViewDidCommitNavigation + diff --git a/exp/pkg/options/window.go b/exp/pkg/options/window.go index f0f8c011f..fc931f95b 100644 --- a/exp/pkg/options/window.go +++ b/exp/pkg/options/window.go @@ -32,6 +32,9 @@ type Window struct { Mac *MacWindow BackgroundColour *RGBA Assets Assets + HTML string + JS string + CSS string } var WindowDefaults = &Window{ diff --git a/exp/tasks/events/generate.go b/exp/tasks/events/generate.go index 6fbd018d0..c3810ecd9 100644 --- a/exp/tasks/events/generate.go +++ b/exp/tasks/events/generate.go @@ -47,6 +47,7 @@ func main() { cHeaderEvents := bytes.NewBufferString("") windowDelegateEvents := bytes.NewBufferString("") applicationDelegateEvents := bytes.NewBufferString("") + webviewDelegateEvents := bytes.NewBufferString("") // Loop over each line in the file for id, line := range bytes.Split(eventNames, []byte{'\n'}) { @@ -78,6 +79,9 @@ func main() { if strings.HasPrefix(event, "Window") { eventType = "WindowEventType" } + if strings.HasPrefix(event, "WebView") { + eventType = "WindowEventType" + } macEventsDecl.WriteString("\t" + eventTitle + " " + eventType + "\n") macEventsValues.WriteString("\t\t" + event + ": " + strconv.Itoa(id) + ",\n") cHeaderEvents.WriteString("#define Event" + eventTitle + " " + strconv.Itoa(id) + "\n") @@ -90,6 +94,16 @@ func main() { processWindowEvent(self.windowId, Event` + eventTitle + `); } +`) + } + // Check if this is a webview event + if strings.HasPrefix(event, "WebView") { + webViewFunction := strings.TrimPrefix(event, "WebView") + webViewFunction = string(bytes.ToLower([]byte{webViewFunction[0]})) + webViewFunction[1:] + webviewDelegateEvents.WriteString(`- (void)webView:(WKWebView *)webview ` + webViewFunction + `:(WKNavigation *)navigation { + processWindowEvent(self.windowId, Event` + eventTitle + `); +} + `) } if strings.HasPrefix(event, "Application") { @@ -99,88 +113,92 @@ func main() { `) } + } - } + // Save the eventsGo template substituting the values and decls + templateToWrite := strings.ReplaceAll(eventsGo, "$$MACEVENTSDECL", macEventsDecl.String()) + templateToWrite = strings.ReplaceAll(templateToWrite, "$$MACEVENTSVALUES", macEventsValues.String()) + err = os.WriteFile("../../pkg/events/events.go", []byte(templateToWrite), 0644) + if err != nil { + panic(err) + } - // Save the eventsGo template substituting the values and decls - templateToWrite := strings.ReplaceAll(eventsGo, "$$MACEVENTSDECL", macEventsDecl.String()) - templateToWrite = strings.ReplaceAll(templateToWrite, "$$MACEVENTSVALUES", macEventsValues.String()) - err = os.WriteFile("../../pkg/events/events.go", []byte(templateToWrite), 0644) - if err != nil { - panic(err) - } + // Save the eventsH template substituting the values and decls + templateToWrite = strings.ReplaceAll(eventsH, "$$CHEADEREVENTS", cHeaderEvents.String()) + err = os.WriteFile("../../pkg/events/events.h", []byte(templateToWrite), 0644) + if err != nil { + panic(err) + } - // Save the eventsH template substituting the values and decls - templateToWrite = strings.ReplaceAll(eventsH, "$$CHEADEREVENTS", cHeaderEvents.String()) - err = os.WriteFile("../../pkg/events/events.h", []byte(templateToWrite), 0644) - if err != nil { - panic(err) - } + // Load the window_delegate.m file + windowDelegate, err := os.ReadFile("../../pkg/application/window_delegate.m") + if err != nil { + panic(err) + } + // iterate over the lines until we reach a line that says "// GENERATED EVENTS START" + // then we insert the events + // then we iterate until we reach a line that says "// GENERATED EVENTS END" + // then we write the file + var buffer bytes.Buffer + var inGeneratedEvents bool + for _, line := range bytes.Split(windowDelegate, []byte{'\n'}) { + if bytes.Contains(line, []byte("// GENERATED EVENTS START")) { + inGeneratedEvents = true + buffer.WriteString("// GENERATED EVENTS START\n") + buffer.WriteString(windowDelegateEvents.String()) + buffer.WriteString(webviewDelegateEvents.String()) + continue + } + if bytes.Contains(line, []byte("// GENERATED EVENTS END")) { + inGeneratedEvents = false + buffer.WriteString("// GENERATED EVENTS END\n") + continue + } + if !inGeneratedEvents { + if len(line) > 0 { + buffer.Write(line) + buffer.WriteString("\n") + } + } + } + err = os.WriteFile("../../pkg/application/window_delegate.m", buffer.Bytes(), 0755) + if err != nil { + panic(err) + } - // Load the window_delegate.m file - windowDelegate, err := os.ReadFile("../../pkg/application/window_delegate.m") - if err != nil { - panic(err) - } - // iterate over the lines until we reach a line that says "// GENERATED EVENTS START" - // then we insert the events - // then we iterate until we reach a line that says "// GENERATED EVENTS END" - // then we write the file - var buffer bytes.Buffer - var inGeneratedEvents bool - for _, line := range bytes.Split(windowDelegate, []byte{'\n'}) { - if bytes.Contains(line, []byte("// GENERATED EVENTS START")) { - inGeneratedEvents = true - buffer.WriteString("// GENERATED EVENTS START\n") - buffer.WriteString(windowDelegateEvents.String()) - continue + // Load the app_delegate.m file + appDelegate, err := os.ReadFile("../../pkg/application/app_delegate.m") + if err != nil { + panic(err) } - if bytes.Contains(line, []byte("// GENERATED EVENTS END")) { - inGeneratedEvents = false - buffer.WriteString("// GENERATED EVENTS END\n") - continue + // iterate over the lines until we reach a line that says "// GENERATED EVENTS START" + // then we insert the events + // then we iterate until we reach a line that says "// GENERATED EVENTS END" + // then we write the file + buffer.Reset() + for _, line := range bytes.Split(appDelegate, []byte{'\n'}) { + if bytes.Contains(line, []byte("// GENERATED EVENTS START")) { + inGeneratedEvents = true + buffer.WriteString("// GENERATED EVENTS START\n") + buffer.WriteString(applicationDelegateEvents.String()) + continue + } + if bytes.Contains(line, []byte("// GENERATED EVENTS END")) { + inGeneratedEvents = false + buffer.WriteString("// GENERATED EVENTS END\n") + continue + } + if !inGeneratedEvents { + if len(line) > 0 { + buffer.Write(line) + buffer.WriteString("\n") + } + } } - if !inGeneratedEvents { - buffer.Write(line) - buffer.WriteString("\n") + err = os.WriteFile("../../pkg/application/app_delegate.m", buffer.Bytes(), 0755) + if err != nil { + panic(err) } } - err = os.WriteFile("../../pkg/application/window_delegate.m", buffer.Bytes(), 0755) - if err != nil { - panic(err) - } - - // Load the app_delegate.m file - appDelegate, err := os.ReadFile("../../pkg/application/app_delegate.m") - if err != nil { - panic(err) - } - // iterate over the lines until we reach a line that says "// GENERATED EVENTS START" - // then we insert the events - // then we iterate until we reach a line that says "// GENERATED EVENTS END" - // then we write the file - buffer.Reset() - for _, line := range bytes.Split(appDelegate, []byte{'\n'}) { - if bytes.Contains(line, []byte("// GENERATED EVENTS START")) { - inGeneratedEvents = true - buffer.WriteString("// GENERATED EVENTS START\n") - buffer.WriteString(applicationDelegateEvents.String()) - continue - } - if bytes.Contains(line, []byte("// GENERATED EVENTS END")) { - inGeneratedEvents = false - buffer.WriteString("// GENERATED EVENTS END\n") - continue - } - if !inGeneratedEvents { - buffer.Write(line) - buffer.WriteString("\n") - } - } - err = os.WriteFile("../../pkg/application/app_delegate.m", buffer.Bytes(), 0755) - if err != nil { - panic(err) - } - }