diff --git a/exp/examples/window/main.go b/exp/examples/window/main.go index 926a90d86..9f17be321 100644 --- a/exp/examples/window/main.go +++ b/exp/examples/window/main.go @@ -5,15 +5,19 @@ import ( "log" "strconv" - "github.com/wailsapp/wails/exp/pkg/options" + "github.com/wailsapp/wails/exp/pkg/events" "github.com/wailsapp/wails/exp/pkg/application" + "github.com/wailsapp/wails/exp/pkg/options" ) func main() { app := application.New() app.SetName("Window Demo") app.SetDescription("A demo of the windowing capabilities") + app.On(events.Mac.ApplicationDidFinishLaunching, func() { + log.Println("ApplicationDidFinishLaunching") + }) // Create a custom menu menu := app.NewMenu() @@ -22,7 +26,7 @@ func main() { windowCounter := 1 // Let's make a "Demo" menu - myMenu := menu.AddSubmenu("Window") + myMenu := menu.AddSubmenu("New") myMenu.Add("New Blank Window").OnClick(func(ctx *application.Context) { app.NewWindow().SetTitle("Window " + strconv.Itoa(windowCounter)).Run() windowCounter++ @@ -48,8 +52,11 @@ func main() { }) // Disabled menu item - myMenu.Add("Not Enabled").SetEnabled(false) - + adjustMenu := menu.AddSubmenu("Adjust") + adjustMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) { + app.CurrentWindow().SetPosition(0, 0) + windowCounter++ + }) app.SetMenu(menu) err := app.Run() diff --git a/exp/pkg/application/app_delegate.m b/exp/pkg/application/app_delegate.m index c3a7bdcde..555fae2a3 100644 --- a/exp/pkg/application/app_delegate.m +++ b/exp/pkg/application/app_delegate.m @@ -1,6 +1,10 @@ //go:build darwin + #import "app_delegate.h" #import "../events/events.h" + +extern bool hasListeners(unsigned int); + @implementation AppDelegate - (void)dealloc { @@ -9,83 +13,123 @@ // GENERATED EVENTS START - (void)applicationDidBecomeActive:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidBecomeActive); + if( hasListeners(EventApplicationDidBecomeActive) ) { + processApplicationEvent(EventApplicationDidBecomeActive); + } } - (void)applicationDidChangeBackingProperties:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeBackingProperties); + if( hasListeners(EventApplicationDidChangeBackingProperties) ) { + processApplicationEvent(EventApplicationDidChangeBackingProperties); + } } - (void)applicationDidChangeEffectiveAppearance:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeEffectiveAppearance); + if( hasListeners(EventApplicationDidChangeEffectiveAppearance) ) { + processApplicationEvent(EventApplicationDidChangeEffectiveAppearance); + } } - (void)applicationDidChangeIcon:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeIcon); + if( hasListeners(EventApplicationDidChangeIcon) ) { + processApplicationEvent(EventApplicationDidChangeIcon); + } } - (void)applicationDidChangeOcclusionState:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeOcclusionState); + if( hasListeners(EventApplicationDidChangeOcclusionState) ) { + processApplicationEvent(EventApplicationDidChangeOcclusionState); + } } - (void)applicationDidChangeScreenParameters:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeScreenParameters); + if( hasListeners(EventApplicationDidChangeScreenParameters) ) { + processApplicationEvent(EventApplicationDidChangeScreenParameters); + } } - (void)applicationDidChangeStatusBarFrame:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeStatusBarFrame); + if( hasListeners(EventApplicationDidChangeStatusBarFrame) ) { + processApplicationEvent(EventApplicationDidChangeStatusBarFrame); + } } - (void)applicationDidChangeStatusBarOrientation:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidChangeStatusBarOrientation); + if( hasListeners(EventApplicationDidChangeStatusBarOrientation) ) { + processApplicationEvent(EventApplicationDidChangeStatusBarOrientation); + } } - (void)applicationDidFinishLaunching:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidFinishLaunching); + if( hasListeners(EventApplicationDidFinishLaunching) ) { + processApplicationEvent(EventApplicationDidFinishLaunching); + } } - (void)applicationDidHide:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidHide); + if( hasListeners(EventApplicationDidHide) ) { + processApplicationEvent(EventApplicationDidHide); + } } - (void)applicationDidResignActive:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidResignActive); + if( hasListeners(EventApplicationDidResignActive) ) { + processApplicationEvent(EventApplicationDidResignActive); + } } - (void)applicationDidUnhide:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidUnhide); + if( hasListeners(EventApplicationDidUnhide) ) { + processApplicationEvent(EventApplicationDidUnhide); + } } - (void)applicationDidUpdate:(NSNotification *)notification { - processApplicationEvent(EventApplicationDidUpdate); + if( hasListeners(EventApplicationDidUpdate) ) { + processApplicationEvent(EventApplicationDidUpdate); + } } - (void)applicationWillBecomeActive:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillBecomeActive); + if( hasListeners(EventApplicationWillBecomeActive) ) { + processApplicationEvent(EventApplicationWillBecomeActive); + } } - (void)applicationWillFinishLaunching:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillFinishLaunching); + if( hasListeners(EventApplicationWillFinishLaunching) ) { + processApplicationEvent(EventApplicationWillFinishLaunching); + } } - (void)applicationWillHide:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillHide); + if( hasListeners(EventApplicationWillHide) ) { + processApplicationEvent(EventApplicationWillHide); + } } - (void)applicationWillResignActive:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillResignActive); + if( hasListeners(EventApplicationWillResignActive) ) { + processApplicationEvent(EventApplicationWillResignActive); + } } - (void)applicationWillTerminate:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillTerminate); + if( hasListeners(EventApplicationWillTerminate) ) { + processApplicationEvent(EventApplicationWillTerminate); + } } - (void)applicationWillUnhide:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillUnhide); + if( hasListeners(EventApplicationWillUnhide) ) { + processApplicationEvent(EventApplicationWillUnhide); + } } - (void)applicationWillUpdate:(NSNotification *)notification { - processApplicationEvent(EventApplicationWillUpdate); + if( hasListeners(EventApplicationWillUpdate) ) { + processApplicationEvent(EventApplicationWillUpdate); + } } // GENERATED EVENTS END diff --git a/exp/pkg/application/application.go b/exp/pkg/application/application.go index 039b6eba1..bc58fda06 100644 --- a/exp/pkg/application/application.go +++ b/exp/pkg/application/application.go @@ -48,6 +48,7 @@ type platformApp interface { getCurrentWindowID() uint showAboutDialog(name string, description string, icon []byte) setIcon(icon []byte) + on(id uint) } // Messages sent from javascript get routed here @@ -59,8 +60,9 @@ type windowMessage struct { var windowMessageBuffer = make(chan *windowMessage) type App struct { - options *options.Application - applicationEventListeners map[uint][]func() + options *options.Application + applicationEventListeners map[uint][]func() + applicationEventListenersLock sync.RWMutex // Windows windows map[uint]*Window @@ -102,7 +104,12 @@ func (a *App) getSystemTrayID() uint { } func (a *App) On(eventType events.ApplicationEventType, callback func()) { eventID := uint(eventType) + a.applicationEventListenersLock.Lock() + defer a.applicationEventListenersLock.Unlock() a.applicationEventListeners[eventID] = append(a.applicationEventListeners[eventID], callback) + if a.impl != nil { + a.impl.on(eventID) + } } func (a *App) NewWindow() *Window { return a.NewWindowWithOptions(nil) @@ -196,13 +203,17 @@ func (a *App) Run() error { a.impl.setApplicationMenu(a.ApplicationMenu) // set the application icon - a.impl.setIcon(a.icon) + if a.icon != nil { + a.impl.setIcon(a.icon) + } return a.impl.run() } func (a *App) handleApplicationEvent(event uint) { + a.applicationEventListenersLock.RLock() listeners, ok := a.applicationEventListeners[event] + a.applicationEventListenersLock.RUnlock() if !ok { return } diff --git a/exp/pkg/application/application_darwin.go b/exp/pkg/application/application_darwin.go index b92677b67..84b3c4433 100644 --- a/exp/pkg/application/application_darwin.go +++ b/exp/pkg/application/application_darwin.go @@ -12,6 +12,8 @@ package application #include "window_delegate.h" #include +extern void registerListener(unsigned int event); + #import static AppDelegate *appDelegate = nil; @@ -119,6 +121,10 @@ type macosApp struct { parent *App } +func (m *macosApp) on(eventID uint) { + C.registerListener(C.uint(eventID)) +} + func (m *macosApp) setIcon(icon []byte) { C.setApplicationIcon(unsafe.Pointer(&icon[0]), C.int(len(icon))) } @@ -146,12 +152,17 @@ func (m *macosApp) setApplicationMenu(menu *Menu) { } func (m *macosApp) run() error { + // Add a hook to the ApplicationDidFinishLaunching event m.parent.On(events.Mac.ApplicationDidFinishLaunching, func() { if m.parent.options != nil && m.parent.options.Mac != nil { C.setActivationPolicy(C.int(m.parent.options.Mac.ActivationPolicy)) } C.activateIgnoringOtherApps() }) + // setup event listeners + for eventID := range m.parent.applicationEventListeners { + m.on(eventID) + } C.run() return nil } diff --git a/exp/pkg/application/window.go b/exp/pkg/application/window.go index 0eb9f9871..a7ca3bfc7 100644 --- a/exp/pkg/application/window.go +++ b/exp/pkg/application/window.go @@ -8,42 +8,46 @@ import ( "github.com/wailsapp/wails/exp/pkg/options" ) -type windowImpl interface { - setTitle(title string) - setSize(width, height int) - setAlwaysOnTop(alwaysOnTop bool) - setURL(url string) - setResizable(resizable bool) - setMinSize(width, height int) - setMaxSize(width, height int) - execJS(js string) - setMaximised() - setMinimised() - setFullscreen() - isMinimised() bool - isMaximised() bool - isFullscreen() bool - restore() - setBackgroundColour(color *options.RGBA) - run() - center() - size() (int, int) - width() int - height() int - position() (int, int) - destroy() - reload() - forceReload() - toggleFullscreen() - toggleDevTools() - resetZoom() - zoomIn() - zoomOut() - close() - zoom() - minimize() - setHTML(html string) -} +type ( + windowImpl interface { + setTitle(title string) + setSize(width, height int) + setAlwaysOnTop(alwaysOnTop bool) + setURL(url string) + setResizable(resizable bool) + setMinSize(width, height int) + setMaxSize(width, height int) + execJS(js string) + setMaximised() + setMinimised() + setFullscreen() + isMinimised() bool + isMaximised() bool + isFullscreen() bool + restore() + setBackgroundColour(color *options.RGBA) + run() + center() + size() (int, int) + width() int + height() int + position() (int, int) + destroy() + reload() + forceReload() + toggleFullscreen() + toggleDevTools() + resetZoom() + zoomIn() + zoomOut() + close() + zoom() + minimize() + setHTML(html string) + setPosition(x int, y int) + on(eventID uint) + } +) type Window struct { options *options.Window @@ -260,8 +264,11 @@ func (w *Window) Center() { func (w *Window) On(eventType events.WindowEventType, callback func()) { eventID := uint(eventType) w.eventListenersLock.Lock() + defer w.eventListenersLock.Unlock() w.eventListeners[eventID] = append(w.eventListeners[eventID], callback) - w.eventListenersLock.Unlock() + if w.impl != nil { + w.impl.on(eventID) + } } func (w *Window) handleWindowEvent(id uint) { @@ -380,3 +387,12 @@ func (w *Window) SetHTML(html string) *Window { } return w } + +func (w *Window) SetPosition(x, y int) *Window { + w.options.X = x + w.options.Y = y + if w.impl != nil { + w.impl.setPosition(x, y) + } + return w +} diff --git a/exp/pkg/application/window_darwin.go b/exp/pkg/application/window_darwin.go index d4704b1cf..f638159e7 100644 --- a/exp/pkg/application/window_darwin.go +++ b/exp/pkg/application/window_darwin.go @@ -12,6 +12,7 @@ package application #include "Cocoa/Cocoa.h" #import +extern void registerListener(unsigned int event); // Create a new Window void* windowNew(unsigned int id, int width, int height) { @@ -252,6 +253,14 @@ void windowZoomOut(void* nsWindow) { }); } +// set the window position +void windowSetPosition(void* nsWindow, int x, int y) { + // Set window position on main thread + dispatch_async(dispatch_get_main_queue(), ^{ + [(NSWindow*)nsWindow setFrameOrigin:NSMakePoint(x, y)]; + }); +} + // Execute JS in NSWindow void windowExecJS(void* nsWindow, const char* js) { printf("windowExecJS\n"); @@ -651,6 +660,10 @@ type macosWindow struct { parent *Window } +func (w *macosWindow) on(eventID uint) { + C.registerListener(C.uint(eventID)) +} + func (w *macosWindow) zoom() { C.windowZoom(w.nsWindow) } @@ -807,6 +820,10 @@ func (w *macosWindow) size() (int, int) { return int(width), int(height) } +func (w *macosWindow) setPosition(x, y int) { + C.windowSetPosition(w.nsWindow, C.int(x), C.int(y)) +} + func (w *macosWindow) width() int { var width C.int var wg sync.WaitGroup @@ -831,6 +848,9 @@ func (w *macosWindow) height() int { } func (w *macosWindow) run() { + for eventId := range w.parent.eventListeners { + w.on(eventId) + } DispatchOnMainThread(func() { 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) diff --git a/exp/pkg/application/window_delegate.m b/exp/pkg/application/window_delegate.m index 5f4ffb762..e9be47f51 100644 --- a/exp/pkg/application/window_delegate.m +++ b/exp/pkg/application/window_delegate.m @@ -1,16 +1,15 @@ //go:build darwin -// -// WindowDelegate.m -// test -// -// 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*); +extern bool hasListeners(unsigned int); + @implementation WindowDelegate + - (BOOL)windowShouldClose:(NSWindow *)sender { if( self.hideOnClose ) { [NSApp hide:nil]; @@ -18,6 +17,7 @@ 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; @@ -36,12 +36,10 @@ extern void processMessage(unsigned int, const char*); const char *_m = [m UTF8String]; processMessage(self.windowId, _m); } - - (void)handleLeftMouseDown:(NSEvent *)event { self.leftMouseEvent = event; NSWindow *window = [event window]; WindowDelegate* delegate = (WindowDelegate*)[window delegate]; - if( self.invisibleTitleBarHeight > 0 ) { NSPoint location = [event locationInWindow]; NSRect frame = [window frame]; @@ -51,319 +49,470 @@ extern void processMessage(unsigned int, const char*); } } } - - (void)handleLeftMouseUp:(NSWindow *)window { self.leftMouseEvent = nil; } - - // GENERATED EVENTS START - (void)windowDidBecomeKey:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidBecomeKey); + if( hasListeners(EventWindowDidBecomeKey) ) { + processWindowEvent(self.windowId, EventWindowDidBecomeKey); + } } - (void)windowDidBecomeMain:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidBecomeMain); + if( hasListeners(EventWindowDidBecomeMain) ) { + processWindowEvent(self.windowId, EventWindowDidBecomeMain); + } } - (void)windowDidBeginSheet:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidBeginSheet); + if( hasListeners(EventWindowDidBeginSheet) ) { + processWindowEvent(self.windowId, EventWindowDidBeginSheet); + } } - (void)windowDidChangeAlpha:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeAlpha); + if( hasListeners(EventWindowDidChangeAlpha) ) { + processWindowEvent(self.windowId, EventWindowDidChangeAlpha); + } } - (void)windowDidChangeBackingLocation:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeBackingLocation); + if( hasListeners(EventWindowDidChangeBackingLocation) ) { + processWindowEvent(self.windowId, EventWindowDidChangeBackingLocation); + } } - (void)windowDidChangeBackingProperties:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeBackingProperties); + if( hasListeners(EventWindowDidChangeBackingProperties) ) { + processWindowEvent(self.windowId, EventWindowDidChangeBackingProperties); + } } - (void)windowDidChangeCollectionBehavior:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeCollectionBehavior); + if( hasListeners(EventWindowDidChangeCollectionBehavior) ) { + processWindowEvent(self.windowId, EventWindowDidChangeCollectionBehavior); + } } - (void)windowDidChangeEffectiveAppearance:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeEffectiveAppearance); + if( hasListeners(EventWindowDidChangeEffectiveAppearance) ) { + processWindowEvent(self.windowId, EventWindowDidChangeEffectiveAppearance); + } } - (void)windowDidChangeOcclusionState:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeOcclusionState); + if( hasListeners(EventWindowDidChangeOcclusionState) ) { + processWindowEvent(self.windowId, EventWindowDidChangeOcclusionState); + } } - (void)windowDidChangeOrderingMode:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeOrderingMode); + if( hasListeners(EventWindowDidChangeOrderingMode) ) { + processWindowEvent(self.windowId, EventWindowDidChangeOrderingMode); + } } - (void)windowDidChangeScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeScreen); + if( hasListeners(EventWindowDidChangeScreen) ) { + processWindowEvent(self.windowId, EventWindowDidChangeScreen); + } } - (void)windowDidChangeScreenParameters:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeScreenParameters); + if( hasListeners(EventWindowDidChangeScreenParameters) ) { + processWindowEvent(self.windowId, EventWindowDidChangeScreenParameters); + } } - (void)windowDidChangeScreenProfile:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeScreenProfile); + if( hasListeners(EventWindowDidChangeScreenProfile) ) { + processWindowEvent(self.windowId, EventWindowDidChangeScreenProfile); + } } - (void)windowDidChangeScreenSpace:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeScreenSpace); + if( hasListeners(EventWindowDidChangeScreenSpace) ) { + processWindowEvent(self.windowId, EventWindowDidChangeScreenSpace); + } } - (void)windowDidChangeScreenSpaceProperties:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeScreenSpaceProperties); + if( hasListeners(EventWindowDidChangeScreenSpaceProperties) ) { + processWindowEvent(self.windowId, EventWindowDidChangeScreenSpaceProperties); + } } - (void)windowDidChangeSharingType:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeSharingType); + if( hasListeners(EventWindowDidChangeSharingType) ) { + processWindowEvent(self.windowId, EventWindowDidChangeSharingType); + } } - (void)windowDidChangeSpace:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeSpace); + if( hasListeners(EventWindowDidChangeSpace) ) { + processWindowEvent(self.windowId, EventWindowDidChangeSpace); + } } - (void)windowDidChangeSpaceOrderingMode:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeSpaceOrderingMode); + if( hasListeners(EventWindowDidChangeSpaceOrderingMode) ) { + processWindowEvent(self.windowId, EventWindowDidChangeSpaceOrderingMode); + } } - (void)windowDidChangeTitle:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeTitle); + if( hasListeners(EventWindowDidChangeTitle) ) { + processWindowEvent(self.windowId, EventWindowDidChangeTitle); + } } - (void)windowDidChangeToolbar:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeToolbar); + if( hasListeners(EventWindowDidChangeToolbar) ) { + processWindowEvent(self.windowId, EventWindowDidChangeToolbar); + } } - (void)windowDidChangeVisibility:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidChangeVisibility); + if( hasListeners(EventWindowDidChangeVisibility) ) { + processWindowEvent(self.windowId, EventWindowDidChangeVisibility); + } } - (void)windowDidClose:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidClose); + if( hasListeners(EventWindowDidClose) ) { + processWindowEvent(self.windowId, EventWindowDidClose); + } } - (void)windowDidDeminiaturize:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidDeminiaturize); + if( hasListeners(EventWindowDidDeminiaturize) ) { + processWindowEvent(self.windowId, EventWindowDidDeminiaturize); + } } - (void)windowDidEndSheet:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidEndSheet); + if( hasListeners(EventWindowDidEndSheet) ) { + processWindowEvent(self.windowId, EventWindowDidEndSheet); + } } - (void)windowDidEnterFullScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidEnterFullScreen); + if( hasListeners(EventWindowDidEnterFullScreen) ) { + processWindowEvent(self.windowId, EventWindowDidEnterFullScreen); + } } - (void)windowDidEnterVersionBrowser:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidEnterVersionBrowser); + if( hasListeners(EventWindowDidEnterVersionBrowser) ) { + processWindowEvent(self.windowId, EventWindowDidEnterVersionBrowser); + } } - (void)windowDidExitFullScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidExitFullScreen); + if( hasListeners(EventWindowDidExitFullScreen) ) { + processWindowEvent(self.windowId, EventWindowDidExitFullScreen); + } } - (void)windowDidExitVersionBrowser:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidExitVersionBrowser); + if( hasListeners(EventWindowDidExitVersionBrowser) ) { + processWindowEvent(self.windowId, EventWindowDidExitVersionBrowser); + } } - (void)windowDidExpose:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidExpose); + if( hasListeners(EventWindowDidExpose) ) { + processWindowEvent(self.windowId, EventWindowDidExpose); + } } - (void)windowDidFocus:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidFocus); + if( hasListeners(EventWindowDidFocus) ) { + processWindowEvent(self.windowId, EventWindowDidFocus); + } } - (void)windowDidMiniaturize:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidMiniaturize); + if( hasListeners(EventWindowDidMiniaturize) ) { + processWindowEvent(self.windowId, EventWindowDidMiniaturize); + } } - (void)windowDidMove:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidMove); + if( hasListeners(EventWindowDidMove) ) { + processWindowEvent(self.windowId, EventWindowDidMove); + } } - (void)windowDidOrderOffScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidOrderOffScreen); + if( hasListeners(EventWindowDidOrderOffScreen) ) { + processWindowEvent(self.windowId, EventWindowDidOrderOffScreen); + } } - (void)windowDidOrderOnScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidOrderOnScreen); + if( hasListeners(EventWindowDidOrderOnScreen) ) { + processWindowEvent(self.windowId, EventWindowDidOrderOnScreen); + } } - (void)windowDidResignKey:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidResignKey); + if( hasListeners(EventWindowDidResignKey) ) { + processWindowEvent(self.windowId, EventWindowDidResignKey); + } } - (void)windowDidResignMain:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidResignMain); + if( hasListeners(EventWindowDidResignMain) ) { + processWindowEvent(self.windowId, EventWindowDidResignMain); + } } - (void)windowDidResize:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidResize); + if( hasListeners(EventWindowDidResize) ) { + processWindowEvent(self.windowId, EventWindowDidResize); + } } - (void)windowDidUnfocus:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUnfocus); + if( hasListeners(EventWindowDidUnfocus) ) { + processWindowEvent(self.windowId, EventWindowDidUnfocus); + } } - (void)windowDidUpdate:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdate); + if( hasListeners(EventWindowDidUpdate) ) { + processWindowEvent(self.windowId, EventWindowDidUpdate); + } } - (void)windowDidUpdateAlpha:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateAlpha); + if( hasListeners(EventWindowDidUpdateAlpha) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateAlpha); + } } - (void)windowDidUpdateCollectionBehavior:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateCollectionBehavior); + if( hasListeners(EventWindowDidUpdateCollectionBehavior) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateCollectionBehavior); + } } - (void)windowDidUpdateCollectionProperties:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateCollectionProperties); + if( hasListeners(EventWindowDidUpdateCollectionProperties) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateCollectionProperties); + } } - (void)windowDidUpdateShadow:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateShadow); + if( hasListeners(EventWindowDidUpdateShadow) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateShadow); + } } - (void)windowDidUpdateTitle:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateTitle); + if( hasListeners(EventWindowDidUpdateTitle) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateTitle); + } } - (void)windowDidUpdateToolbar:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateToolbar); + if( hasListeners(EventWindowDidUpdateToolbar) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateToolbar); + } } - (void)windowDidUpdateVisibility:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowDidUpdateVisibility); + if( hasListeners(EventWindowDidUpdateVisibility) ) { + processWindowEvent(self.windowId, EventWindowDidUpdateVisibility); + } } - (void)windowWillBecomeKey:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillBecomeKey); + if( hasListeners(EventWindowWillBecomeKey) ) { + processWindowEvent(self.windowId, EventWindowWillBecomeKey); + } } - (void)windowWillBecomeMain:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillBecomeMain); + if( hasListeners(EventWindowWillBecomeMain) ) { + processWindowEvent(self.windowId, EventWindowWillBecomeMain); + } } - (void)windowWillBeginSheet:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillBeginSheet); + if( hasListeners(EventWindowWillBeginSheet) ) { + processWindowEvent(self.windowId, EventWindowWillBeginSheet); + } } - (void)windowWillChangeOrderingMode:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillChangeOrderingMode); + if( hasListeners(EventWindowWillChangeOrderingMode) ) { + processWindowEvent(self.windowId, EventWindowWillChangeOrderingMode); + } } - (void)windowWillClose:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillClose); + if( hasListeners(EventWindowWillClose) ) { + processWindowEvent(self.windowId, EventWindowWillClose); + } } - (void)windowWillDeminiaturize:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillDeminiaturize); + if( hasListeners(EventWindowWillDeminiaturize) ) { + processWindowEvent(self.windowId, EventWindowWillDeminiaturize); + } } - (void)windowWillEnterFullScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillEnterFullScreen); + if( hasListeners(EventWindowWillEnterFullScreen) ) { + processWindowEvent(self.windowId, EventWindowWillEnterFullScreen); + } } - (void)windowWillEnterVersionBrowser:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillEnterVersionBrowser); + if( hasListeners(EventWindowWillEnterVersionBrowser) ) { + processWindowEvent(self.windowId, EventWindowWillEnterVersionBrowser); + } } - (void)windowWillExitFullScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillExitFullScreen); + if( hasListeners(EventWindowWillExitFullScreen) ) { + processWindowEvent(self.windowId, EventWindowWillExitFullScreen); + } } - (void)windowWillExitVersionBrowser:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillExitVersionBrowser); + if( hasListeners(EventWindowWillExitVersionBrowser) ) { + processWindowEvent(self.windowId, EventWindowWillExitVersionBrowser); + } } - (void)windowWillFocus:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillFocus); + if( hasListeners(EventWindowWillFocus) ) { + processWindowEvent(self.windowId, EventWindowWillFocus); + } } - (void)windowWillMiniaturize:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillMiniaturize); + if( hasListeners(EventWindowWillMiniaturize) ) { + processWindowEvent(self.windowId, EventWindowWillMiniaturize); + } } - (void)windowWillMove:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillMove); + if( hasListeners(EventWindowWillMove) ) { + processWindowEvent(self.windowId, EventWindowWillMove); + } } - (void)windowWillOrderOffScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillOrderOffScreen); + if( hasListeners(EventWindowWillOrderOffScreen) ) { + processWindowEvent(self.windowId, EventWindowWillOrderOffScreen); + } } - (void)windowWillOrderOnScreen:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillOrderOnScreen); + if( hasListeners(EventWindowWillOrderOnScreen) ) { + processWindowEvent(self.windowId, EventWindowWillOrderOnScreen); + } } - (void)windowWillResignMain:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillResignMain); + if( hasListeners(EventWindowWillResignMain) ) { + processWindowEvent(self.windowId, EventWindowWillResignMain); + } } - (void)windowWillResize:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillResize); + if( hasListeners(EventWindowWillResize) ) { + processWindowEvent(self.windowId, EventWindowWillResize); + } } - (void)windowWillUnfocus:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUnfocus); + if( hasListeners(EventWindowWillUnfocus) ) { + processWindowEvent(self.windowId, EventWindowWillUnfocus); + } } - (void)windowWillUpdate:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdate); + if( hasListeners(EventWindowWillUpdate) ) { + processWindowEvent(self.windowId, EventWindowWillUpdate); + } } - (void)windowWillUpdateAlpha:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateAlpha); + if( hasListeners(EventWindowWillUpdateAlpha) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateAlpha); + } } - (void)windowWillUpdateCollectionBehavior:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateCollectionBehavior); + if( hasListeners(EventWindowWillUpdateCollectionBehavior) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateCollectionBehavior); + } } - (void)windowWillUpdateCollectionProperties:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateCollectionProperties); + if( hasListeners(EventWindowWillUpdateCollectionProperties) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateCollectionProperties); + } } - (void)windowWillUpdateShadow:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateShadow); + if( hasListeners(EventWindowWillUpdateShadow) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateShadow); + } } - (void)windowWillUpdateTitle:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateTitle); + if( hasListeners(EventWindowWillUpdateTitle) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateTitle); + } } - (void)windowWillUpdateToolbar:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateToolbar); + if( hasListeners(EventWindowWillUpdateToolbar) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateToolbar); + } } - (void)windowWillUpdateVisibility:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUpdateVisibility); + if( hasListeners(EventWindowWillUpdateVisibility) ) { + processWindowEvent(self.windowId, EventWindowWillUpdateVisibility); + } } - (void)windowWillUseStandardFrame:(NSNotification *)notification { - processWindowEvent(self.windowId, EventWindowWillUseStandardFrame); + if( hasListeners(EventWindowWillUseStandardFrame) ) { + processWindowEvent(self.windowId, EventWindowWillUseStandardFrame); + } } - (void)webView:(WKWebView *)webview didStartProvisionalNavigation:(WKNavigation *)navigation { - processWindowEvent(self.windowId, EventWebViewDidStartProvisionalNavigation); + if( hasListeners(EventWebViewDidStartProvisionalNavigation) ) { + processWindowEvent(self.windowId, EventWebViewDidStartProvisionalNavigation); + } } - (void)webView:(WKWebView *)webview didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation { - processWindowEvent(self.windowId, EventWebViewDidReceiveServerRedirectForProvisionalNavigation); + if( hasListeners(EventWebViewDidReceiveServerRedirectForProvisionalNavigation) ) { + processWindowEvent(self.windowId, EventWebViewDidReceiveServerRedirectForProvisionalNavigation); + } } - (void)webView:(WKWebView *)webview didFinishNavigation:(WKNavigation *)navigation { - processWindowEvent(self.windowId, EventWebViewDidFinishNavigation); + if( hasListeners(EventWebViewDidFinishNavigation) ) { + processWindowEvent(self.windowId, EventWebViewDidFinishNavigation); + } } - (void)webView:(WKWebView *)webview didCommitNavigation:(WKNavigation *)navigation { - processWindowEvent(self.windowId, EventWebViewDidCommitNavigation); + if( hasListeners(EventWebViewDidCommitNavigation) ) { + processWindowEvent(self.windowId, EventWebViewDidCommitNavigation); + } } // GENERATED EVENTS END diff --git a/exp/pkg/events/events.h b/exp/pkg/events/events.h index 02de910be..2d1e56d6d 100644 --- a/exp/pkg/events/events.h +++ b/exp/pkg/events/events.h @@ -127,5 +127,7 @@ extern void processWindowEvent(unsigned int, unsigned int); #define EventWebViewDidFinishNavigation 118 #define EventWebViewDidCommitNavigation 119 +#define MAX_EVENTS 120 + #endif \ No newline at end of file diff --git a/exp/pkg/events/events_darwin.go b/exp/pkg/events/events_darwin.go new file mode 100644 index 000000000..12a7c3af4 --- /dev/null +++ b/exp/pkg/events/events_darwin.go @@ -0,0 +1,26 @@ +//go:build darwin + +package events + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Cocoa -mmacosx-version-min=10.13 + +#include "events.h" +#include +#include + +#include "events.h" + +bool hasListener[MAX_EVENTS] = {false}; + +void registerListener(unsigned int event) { + hasListener[event] = true; +} + +bool hasListeners(unsigned int event) { + return hasListener[event]; +} + +*/ +import "C" diff --git a/exp/pkg/options/window.go b/exp/pkg/options/window.go index b6ce5e280..2156919f3 100644 --- a/exp/pkg/options/window.go +++ b/exp/pkg/options/window.go @@ -34,6 +34,8 @@ type Window struct { HTML string JS string CSS string + X int + Y int } var WindowDefaults = &Window{ diff --git a/exp/tasks/events/generate.go b/exp/tasks/events/generate.go index c3810ecd9..b14af8b7c 100644 --- a/exp/tasks/events/generate.go +++ b/exp/tasks/events/generate.go @@ -49,8 +49,10 @@ func main() { applicationDelegateEvents := bytes.NewBufferString("") webviewDelegateEvents := bytes.NewBufferString("") + var id int + var line []byte // Loop over each line in the file - for id, line := range bytes.Split(eventNames, []byte{'\n'}) { + for id, line = range bytes.Split(eventNames, []byte{'\n'}) { // Skip empty lines if len(line) == 0 { @@ -91,7 +93,9 @@ func main() { // Check if this is a window event if strings.HasPrefix(event, "Window") { windowDelegateEvents.WriteString(`- (void)` + delegateEventFunction + `:(NSNotification *)notification { - processWindowEvent(self.windowId, Event` + eventTitle + `); + if( hasListeners(Event` + eventTitle + `) ) { + processWindowEvent(self.windowId, Event` + eventTitle + `); + } } `) @@ -101,104 +105,111 @@ func main() { 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( hasListeners(Event` + eventTitle + `) ) { + processWindowEvent(self.windowId, Event` + eventTitle + `); + } } `) } if strings.HasPrefix(event, "Application") { applicationDelegateEvents.WriteString(`- (void)` + delegateEventFunction + `:(NSNotification *)notification { - processApplicationEvent(Event` + eventTitle + `); + if( hasListeners(Event` + eventTitle + `) ) { + processApplicationEvent(Event` + eventTitle + `); + } } `) } } + } - // 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) - } + cHeaderEvents.WriteString("\n#define MAX_EVENTS " + strconv.Itoa(id-1) + "\n") - // 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 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) + } - // 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) - } + // 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 app_delegate.m file - appDelegate, err := os.ReadFile("../../pkg/application/app_delegate.m") - 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 } - // 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 bytes.Contains(line, []byte("// GENERATED EVENTS END")) { + inGeneratedEvents = false + buffer.WriteString("// GENERATED EVENTS END\n") + continue } - err = os.WriteFile("../../pkg/application/app_delegate.m", buffer.Bytes(), 0755) - if err != nil { - panic(err) + 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 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 { + if len(line) > 0 { + buffer.Write(line) + buffer.WriteString("\n") + } + } + } + err = os.WriteFile("../../pkg/application/app_delegate.m", buffer.Bytes(), 0755) + if err != nil { + panic(err) + } + }