//go:build darwin package application /* #cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c #cgo LDFLAGS: -framework Cocoa -mmacosx-version-min=10.13 #include "application.h" #include "app_delegate.h" #include "webview_window.h" #include extern void registerListener(unsigned int event); #import static AppDelegate *appDelegate = nil; static void init(void) { [NSApplication sharedApplication]; appDelegate = [[AppDelegate alloc] init]; [NSApp setDelegate:appDelegate]; [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) { NSWindow* eventWindow = [event window]; if (eventWindow == nil ) { return event; } WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[eventWindow delegate]; if (windowDelegate == nil) { return event; } if ([windowDelegate respondsToSelector:@selector(handleLeftMouseDown:)]) { [windowDelegate handleLeftMouseDown:event]; } return event; }]; [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseUp handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) { NSWindow* eventWindow = [event window]; if (eventWindow == nil ) { return event; } WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[eventWindow delegate]; if (windowDelegate == nil) { return event; } if ([windowDelegate respondsToSelector:@selector(handleLeftMouseUp:)]) { [windowDelegate handleLeftMouseUp:eventWindow]; } return event; }]; } static void setApplicationShouldTerminateAfterLastWindowClosed(bool shouldTerminate) { // Get the NSApp delegate AppDelegate *appDelegate = (AppDelegate*)[NSApp delegate]; // Set the applicationShouldTerminateAfterLastWindowClosed boolean appDelegate.shouldTerminateWhenLastWindowClosed = shouldTerminate; } static void setActivationPolicy(int policy) { [NSApp setActivationPolicy:policy]; } static void activateIgnoringOtherApps() { [NSApp activateIgnoringOtherApps:YES]; } static void run(void) { @autoreleasepool { [NSApp run]; [appDelegate release]; } } // Destroy application static void destroyApp(void) { [NSApp terminate:nil]; } // Set the application menu static void setApplicationMenu(void *menu) { NSMenu *nsMenu = (__bridge NSMenu *)menu; [NSApp setMainMenu:menu]; } // Get the application name static char* getAppName(void) { NSString *appName = [NSRunningApplication currentApplication].localizedName; if( appName == nil ) { appName = [[NSProcessInfo processInfo] processName]; } return strdup([appName UTF8String]); } // get the current window ID static unsigned int getCurrentWindowID(void) { NSWindow *window = [NSApp keyWindow]; // Get the window delegate WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)[window delegate]; return delegate.windowId; } // Set the application icon static void setApplicationIcon(void *icon, int length) { // On main thread dispatch_async(dispatch_get_main_queue(), ^{ NSImage *image = [[NSImage alloc] initWithData:[NSData dataWithBytes:icon length:length]]; [NSApp setApplicationIconImage:image]; }); } */ import "C" import ( "unsafe" "github.com/wailsapp/wails/v2/pkg/assetserver/webview" "github.com/wailsapp/wails/v3/pkg/events" ) type macosApp struct { applicationMenu unsafe.Pointer 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))) } func (m *macosApp) name() string { appName := C.getAppName() defer C.free(unsafe.Pointer(appName)) return C.GoString(appName) } func (m *macosApp) getCurrentWindowID() uint { return uint(C.getCurrentWindowID()) } func (m *macosApp) setApplicationMenu(menu *Menu) { if menu == nil { // Create a default menu for mac menu = defaultApplicationMenu() } menu.Update() // Convert impl to macosMenu object m.applicationMenu = (menu.impl).(*macosMenu).nsMenu C.setApplicationMenu(m.applicationMenu) } func (m *macosApp) run() error { // Add a hook to the ApplicationDidFinishLaunching event m.parent.On(events.Mac.ApplicationDidFinishLaunching, func() { C.setApplicationShouldTerminateAfterLastWindowClosed(C.bool(m.parent.options.Mac.ApplicationShouldTerminateAfterLastWindowClosed)) 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 } func (m *macosApp) destroy() { C.destroyApp() } func newPlatformApp(app *App) *macosApp { C.init() return &macosApp{ parent: app, } } //export processApplicationEvent func processApplicationEvent(eventID C.uint) { applicationEvents <- uint(eventID) } //export processWindowEvent func processWindowEvent(windowID C.uint, eventID C.uint) { windowEvents <- &WindowEvent{ WindowID: uint(windowID), EventID: uint(eventID), } } //export processMessage func processMessage(windowID C.uint, message *C.char) { windowMessageBuffer <- &windowMessage{ windowId: uint(windowID), message: C.GoString(message), } } //export processURLRequest func processURLRequest(windowID C.uint, wkUrlSchemeTask unsafe.Pointer) { webviewRequests <- &webViewAssetRequest{ windowId: uint(windowID), request: webview.NewRequest(wkUrlSchemeTask), } } //export processMenuItemClick func processMenuItemClick(menuID C.uint) { menuItemClicked <- uint(menuID) } func setIcon(icon []byte) { if icon == nil { return } C.setApplicationIcon(unsafe.Pointer(&icon[0]), C.int(len(icon))) }