From 84bcb3a8d57f01fae30caab145c9c6a37dbf406c Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Sun, 15 Sep 2024 19:01:30 +0200 Subject: [PATCH 01/20] first implementation of a macos panel --- v3/pkg/application/application.go | 4 +- v3/pkg/application/application_darwin.go | 18 + v3/pkg/application/screen_darwin.go | 5 + v3/pkg/application/webview_panel_darwin.go | 196 ++++ .../webview_panel_options_darwin.go | 34 + v3/pkg/application/webview_window_darwin.go | 973 ++---------------- v3/pkg/application/webview_window_darwin.h | 8 +- v3/pkg/application/webview_window_darwin.m | 38 +- .../application/webview_window_darwin_dev.go | 8 + v3/pkg/application/webview_window_darwin_go.h | 124 +++ v3/pkg/application/webview_window_darwin_go.m | 770 ++++++++++++++ 11 files changed, 1295 insertions(+), 883 deletions(-) create mode 100644 v3/pkg/application/webview_panel_darwin.go create mode 100644 v3/pkg/application/webview_panel_options_darwin.go create mode 100644 v3/pkg/application/webview_window_darwin_go.h create mode 100644 v3/pkg/application/webview_window_darwin_go.m diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index c67557c6e18..33d409471b6 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -669,7 +669,7 @@ func (a *App) handleMenuItemClicked(menuItemID uint) { menuItem.handleClick() } -func (a *App) CurrentWindow() *WebviewWindow { +func (a *App) CurrentWindow() Window { if a.impl == nil { return nil } @@ -680,7 +680,7 @@ func (a *App) CurrentWindow() *WebviewWindow { if result == nil { return nil } - return result.(*WebviewWindow) + return result } // OnShutdown adds a function to be run when the application is shutting down. diff --git a/v3/pkg/application/application_darwin.go b/v3/pkg/application/application_darwin.go index 7587ff4545e..b863f0e1516 100644 --- a/v3/pkg/application/application_darwin.go +++ b/v3/pkg/application/application_darwin.go @@ -364,3 +364,21 @@ func (a *App) platformEnvironment() map[string]any { func fatalHandler(errFunc func(error)) { return } + +func (a *App) NewWebviewPanelWithOptions(panelOptions WebviewPanelOptions) *WebviewPanel { + newPanel := NewPanel(panelOptions) + id := newPanel.ID() + + a.windowsLock.Lock() + a.windows[id] = newPanel + a.windowsLock.Unlock() + + // Call hooks + for _, hook := range a.windowCreatedCallbacks { + hook(newPanel) + } + + a.runOrDeferToAppRun(newPanel) + + return newPanel +} diff --git a/v3/pkg/application/screen_darwin.go b/v3/pkg/application/screen_darwin.go index 661c45446c0..0199dcb3432 100644 --- a/v3/pkg/application/screen_darwin.go +++ b/v3/pkg/application/screen_darwin.go @@ -173,6 +173,11 @@ func getScreenForWindow(window *macosWebviewWindow) (*Screen, error) { return cScreenToScreen(cScreen), nil } +func getScreenForPanel(window *macosWebviewPanel) (*Screen, error) { + cScreen := C.getScreenForWindow(window.nsPanel) + return cScreenToScreen(cScreen), nil +} + func getScreenForSystray(systray *macosSystemTray) (*Screen, error) { // Get the Window for the status item // https://stackoverflow.com/a/5875019/4188138 diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go new file mode 100644 index 00000000000..fc9d4527f13 --- /dev/null +++ b/v3/pkg/application/webview_panel_darwin.go @@ -0,0 +1,196 @@ +package application + +/* +#cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c +#cgo LDFLAGS: -framework Cocoa -framework WebKit + +#include "webview_window_darwin_go.h" + +// Set NSPanel floating +void panelSetFloating(void* nsPanel, bool floating) { + // Set panel floating on main thread + NSWindow *window = ((WebviewWindow*)nsPanel).w; + NSPanel *panel = (NSPanel *) window; + + [panel setLevel:floating ? NSFloatingWindowLevel : NSNormalWindowLevel]; + [panel setFloatingPanel:floating ? YES : NO]; + [panel setStyleMask:floating ? panel.styleMask | NSWindowStyleMaskNonactivatingPanel : panel.styleMask & ~NSWindowStyleMaskNonactivatingPanel]; + NSWindowCollectionBehavior panelCB = NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorFullScreenAuxiliary; + [panel setCollectionBehavior:floating ? panel.collectionBehavior | panelCB : panel.collectionBehavior & ~panelCB]; +} +*/ +import "C" +import ( + "unsafe" + + "github.com/wailsapp/wails/v3/internal/runtime" + "github.com/wailsapp/wails/v3/pkg/events" +) + +type WebviewPanel struct { + WebviewWindow + + options WebviewPanelOptions + impl *macosWebviewPanel + // keyBindings holds the keybindings for the panel + keyBindings map[string]func(*WebviewPanel) +} + +// NewPanel creates a new panel with the given options +func NewPanel(options WebviewPanelOptions) *WebviewPanel { + if options.Width == 0 { + options.Width = 800 + } + if options.Height == 0 { + options.Height = 600 + } + if options.URL == "" { + options.URL = "/" + } + + result := &WebviewPanel{ + WebviewWindow: WebviewWindow{ + id: getWindowID(), + options: options.WebviewWindowOptions, + eventListeners: make(map[uint][]*WindowEventListener), + contextMenus: make(map[string]*Menu), + eventHooks: make(map[uint][]*WindowEventListener), + menuBindings: make(map[string]*MenuItem), + }, + options: options, + } + + result.setupEventMapping() + + // Listen for window closing events and de + result.On(events.Common.WindowClosing, func(event *WindowEvent) { + shouldClose := true + if result.options.ShouldClose != nil { + shouldClose = result.options.ShouldClose(result) + } + if shouldClose { + globalApplication.deleteWindowByID(result.id) + InvokeSync(result.impl.close) + } + }) + + // Process keybindings + if result.options.KeyBindings != nil { + result.keyBindings = processKeyBindingOptionsForPanel(result.options.KeyBindings) + } + + return result +} + +func (p *WebviewPanel) Run() { + if p.impl != nil { + return + } + + p.impl = newPanel(p) + p.WebviewWindow.impl = &p.impl.macosWebviewWindow + + InvokeSync(p.impl.run) +} + +// SetFloating makes the panel float above other application in every workspace. +func (p *WebviewPanel) SetFloating(b bool) Window { + p.options.Floating = b + if p.impl != nil { + InvokeSync(func() { + p.impl.setFloating(b) + }) + } + return p +} + +func (p *WebviewPanel) HandleKeyEvent(acceleratorString string) { + if p.impl == nil && !p.isDestroyed() { + return + } + InvokeSync(func() { + p.impl.handleKeyEvent(acceleratorString) + }) +} + +func (p *WebviewPanel) processKeyBinding(acceleratorString string) bool { + // Check menu bindings + if p.menuBindings != nil { + p.menuBindingsLock.RLock() + defer p.menuBindingsLock.RUnlock() + if menuItem := p.menuBindings[acceleratorString]; menuItem != nil { + menuItem.handleClick() + return true + } + } + + // Check key bindings + if p.keyBindings != nil { + p.keyBindingsLock.RLock() + defer p.keyBindingsLock.RUnlock() + if callback := p.keyBindings[acceleratorString]; callback != nil { + // Execute callback + go callback(p) + return true + } + } + + return globalApplication.processKeyBinding(acceleratorString, &p.WebviewWindow) +} + +type macosWebviewPanel struct { + macosWebviewWindow + + nsPanel unsafe.Pointer + parent *WebviewPanel +} + +func (p *macosWebviewPanel) setFloating(floating bool) { + C.panelSetFloating(p.nsPanel, C.bool(floating)) +} + +func newPanel(parent *WebviewPanel) *macosWebviewPanel { + result := &macosWebviewPanel{ + macosWebviewWindow: macosWebviewWindow{ + parent: &parent.WebviewWindow, + }, + parent: parent, + } + result.parent.RegisterHook(events.Mac.WebViewDidFinishNavigation, func(event *WindowEvent) { + result.execJS(runtime.Core()) + }) + return result +} + +func (p *macosWebviewPanel) run() { + for eventId := range p.parent.eventListeners { + p.on(eventId) + } + globalApplication.dispatchOnMainThread(func() { + options := p.parent.options + macOptions := options.Mac + + p.nsPanel = C.panelNew(C.uint(p.parent.id), + C.int(options.Width), + C.int(options.Height), + C.bool(macOptions.EnableFraudulentWebsiteWarnings), + C.bool(options.Frameless), + C.bool(options.EnableDragAndDrop), + p.getWebviewPreferences(), + ) + p.macosWebviewWindow.nsWindow = p.nsPanel + + p.setup(&options.WebviewWindowOptions, &macOptions) + p.setFloating(options.Floating) + }) +} + +func (p *macosWebviewPanel) handleKeyEvent(acceleratorString string) { + // Parse acceleratorString + accelerator, err := parseAccelerator(acceleratorString) + if err != nil { + globalApplication.error("unable to parse accelerator: %s", err.Error()) + return + } + p.parent.processKeyBinding(accelerator.String()) +} diff --git a/v3/pkg/application/webview_panel_options_darwin.go b/v3/pkg/application/webview_panel_options_darwin.go new file mode 100644 index 00000000000..004de093648 --- /dev/null +++ b/v3/pkg/application/webview_panel_options_darwin.go @@ -0,0 +1,34 @@ +package application + +type WebviewPanelOptions struct { + WebviewWindowOptions + + // Floating will make the panel float above other application in every workspace. + Floating bool + + // ShouldClose is called when the panel is about to close. + // Return true to allow the panel to close, or false to prevent it from closing. + ShouldClose func(panel *WebviewPanel) bool + + // KeyBindings is a map of key bindings to functions + KeyBindings map[string]func(panel *WebviewPanel) +} + +var WebviewPanelDefaults = &WebviewPanelOptions{ + WebviewWindowOptions: *WebviewWindowDefaults, +} + +func processKeyBindingOptionsForPanel(keyBindings map[string]func(panel *WebviewPanel)) map[string]func(panel *WebviewPanel) { + result := make(map[string]func(panel *WebviewPanel)) + for key, callback := range keyBindings { + // Parse the key to an accelerator + acc, err := parseAccelerator(key) + if err != nil { + globalApplication.error("Invalid keybinding: %s", err.Error()) + continue + } + result[acc.String()] = callback + globalApplication.debug("Added Keybinding", "accelerator", acc.String()) + } + return result +} diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index 52e9c152647..91b47eefb8b 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -6,772 +6,7 @@ package application #cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c #cgo LDFLAGS: -framework Cocoa -framework WebKit -#include "application_darwin.h" -#include "webview_window_darwin.h" -#include -#include "Cocoa/Cocoa.h" -#import -#import -#import "webview_window_darwin_drag.h" - -struct WebviewPreferences { - bool *TabFocusesLinks; - bool *TextInteractionEnabled; - bool *FullscreenEnabled; -}; - -extern void registerListener(unsigned int event); - -// Create a new Window -void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { - NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - if (frameless) { - styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable; - } - WebviewWindow* window = [[WebviewWindow alloc] initWithContentRect:NSMakeRect(0, 0, width-1, height-1) - styleMask:styleMask - backing:NSBackingStoreBuffered - defer:NO]; - - // Create delegate - WebviewWindowDelegate* delegate = [[WebviewWindowDelegate alloc] init]; - [delegate autorelease]; - - // Set delegate - [window setDelegate:delegate]; - delegate.windowId = id; - - // Add NSView to window - NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, width-1, height-1)]; - [view autorelease]; - - [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - if( frameless ) { - [view setWantsLayer:YES]; - view.layer.cornerRadius = 8.0; - } - [window setContentView:view]; - - // Embed wkwebview in window - NSRect frame = NSMakeRect(0, 0, width, height); - WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init]; - [config autorelease]; - - // Set preferences - if (preferences.TabFocusesLinks != NULL) { - config.preferences.tabFocusesLinks = *preferences.TabFocusesLinks; - } - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110300 - if (@available(macOS 11.3, *)) { - if (preferences.TextInteractionEnabled != NULL) { - config.preferences.textInteractionEnabled = *preferences.TextInteractionEnabled; - } - } -#endif - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120300 - if (@available(macOS 12.3, *)) { - if (preferences.FullscreenEnabled != NULL) { - config.preferences.elementFullscreenEnabled = *preferences.FullscreenEnabled; - } - } -#endif - - config.suppressesIncrementalRendering = true; - config.applicationNameForUserAgent = @"wails.io"; - [config setURLSchemeHandler:delegate forURLScheme:@"wails"]; - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 - if (@available(macOS 10.15, *)) { - config.preferences.fraudulentWebsiteWarningEnabled = fraudulentWebsiteWarningEnabled; - } -#endif - - // Setup user content controller - WKUserContentController* userContentController = [WKUserContentController new]; - [userContentController autorelease]; - - [userContentController addScriptMessageHandler:delegate name:@"external"]; - config.userContentController = userContentController; - - WKWebView* webView = [[WKWebView alloc] initWithFrame:frame configuration:config]; - [webView autorelease]; - - [view addSubview:webView]; - - // support webview events - [webView setNavigationDelegate:delegate]; - - // Ensure webview resizes with the window - [webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - if( enableDragAndDrop ) { - WebviewDrag* dragView = [[WebviewDrag alloc] initWithFrame:NSMakeRect(0, 0, width-1, height-1)]; - [dragView autorelease]; - - [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [view addSubview:dragView]; - dragView.windowId = id; - } - - window.webView = webView; - return window; -} - - -void printWindowStyle(void *window) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - NSWindowStyleMask styleMask = [nsWindow styleMask]; - // Get delegate - WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; - - printf("Window %d style mask: ", windowDelegate.windowId); - - if (styleMask & NSWindowStyleMaskTitled) - { - printf("NSWindowStyleMaskTitled "); - } - - if (styleMask & NSWindowStyleMaskClosable) - { - printf("NSWindowStyleMaskClosable "); - } - - if (styleMask & NSWindowStyleMaskMiniaturizable) - { - printf("NSWindowStyleMaskMiniaturizable "); - } - - if (styleMask & NSWindowStyleMaskResizable) - { - printf("NSWindowStyleMaskResizable "); - } - - if (styleMask & NSWindowStyleMaskFullSizeContentView) - { - printf("NSWindowStyleMaskFullSizeContentView "); - } - - if (styleMask & NSWindowStyleMaskNonactivatingPanel) - { - printf("NSWindowStyleMaskNonactivatingPanel "); - } - - if (styleMask & NSWindowStyleMaskFullScreen) - { - printf("NSWindowStyleMaskFullScreen "); - } - - if (styleMask & NSWindowStyleMaskBorderless) - { - printf("MSWindowStyleMaskBorderless "); - } - - printf("\n"); -} - - -// setInvisibleTitleBarHeight sets the invisible title bar height -void setInvisibleTitleBarHeight(void* window, unsigned int height) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // Get delegate - WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; - // Set height - delegate.invisibleTitleBarHeight = height; -} - -// Make NSWindow transparent -void windowSetTransparent(void* nsWindow) { - [(WebviewWindow*)nsWindow setOpaque:NO]; - [(WebviewWindow*)nsWindow setBackgroundColor:[NSColor clearColor]]; -} - -void windowSetInvisibleTitleBar(void* nsWindow, unsigned int height) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[window delegate]; - delegate.invisibleTitleBarHeight = height; -} - - -// Set the title of the NSWindow -void windowSetTitle(void* nsWindow, char* title) { - NSString* nsTitle = [NSString stringWithUTF8String:title]; - [(WebviewWindow*)nsWindow setTitle:nsTitle]; - free(title); -} - -// Set the size of the NSWindow -void windowSetSize(void* nsWindow, int width, int height) { - // Set window size on main thread - WebviewWindow* window = (WebviewWindow*)nsWindow; - NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; - [window setContentSize:contentSize]; - [window setFrame:NSMakeRect(window.frame.origin.x, window.frame.origin.y, width, height) display:YES animate:YES]; -} - -// Set NSWindow always on top -void windowSetAlwaysOnTop(void* nsWindow, bool alwaysOnTop) { - // Set window always on top on main thread - [(WebviewWindow*)nsWindow setLevel:alwaysOnTop ? NSFloatingWindowLevel : NSNormalWindowLevel]; -} - -// Load URL in NSWindow -void navigationLoadURL(void* nsWindow, char* url) { - // Load URL on main thread - NSURL* nsURL = [NSURL URLWithString:[NSString stringWithUTF8String:url]]; - NSURLRequest* request = [NSURLRequest requestWithURL:nsURL]; - WebviewWindow* window = (WebviewWindow*)nsWindow; - [window.webView loadRequest:request]; - free(url); -} - -// Set NSWindow resizable -void windowSetResizable(void* nsWindow, bool resizable) { - // Set window resizable on main thread - WebviewWindow* window = (WebviewWindow*)nsWindow; - if (resizable) { - NSWindowStyleMask styleMask = [window styleMask] | NSWindowStyleMaskResizable; - [window setStyleMask:styleMask]; - } else { - NSWindowStyleMask styleMask = [window styleMask] & ~NSWindowStyleMaskResizable; - [window setStyleMask:styleMask]; - } -} - -// Set NSWindow min size -void windowSetMinSize(void* nsWindow, int width, int height) { - // Set window min size on main thread - WebviewWindow* window = (WebviewWindow*)nsWindow; - NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; - [window setContentMinSize:contentSize]; - NSSize size = { width, height }; - [window setMinSize:size]; -} - -// Set NSWindow max size -void windowSetMaxSize(void* nsWindow, int width, int height) { - // Set window max size on main thread - NSSize size = { FLT_MAX, FLT_MAX }; - size.width = width > 0 ? width : FLT_MAX; - size.height = height > 0 ? height : FLT_MAX; - WebviewWindow* window = (WebviewWindow*)nsWindow; - NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, size.width, size.height)].size; - [window setContentMaxSize:contentSize]; - [window setMaxSize:size]; -} - -// windowZoomReset -void windowZoomReset(void* nsWindow) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - [window.webView setMagnification:1.0]; -} - -// windowZoomSet -void windowZoomSet(void* nsWindow, double zoom) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - // Reset zoom - [window.webView setMagnification:zoom]; -} - -// windowZoomGet -float windowZoomGet(void* nsWindow) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - // Get zoom - return [window.webView magnification]; -} - -// windowZoomIn -void windowZoomIn(void* nsWindow) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - // Zoom in - [window.webView setMagnification:window.webView.magnification + 0.05]; -} - -// windowZoomOut -void windowZoomOut(void* nsWindow) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - // Zoom out - if( window.webView.magnification > 1.05 ) { - [window.webView setMagnification:window.webView.magnification - 0.05]; - } else { - [window.webView setMagnification:1.0]; - } -} - -// set the window position relative to the screen -void windowSetRelativePosition(void* nsWindow, int x, int y) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - NSScreen* screen = [window screen]; - if( screen == NULL ) { - screen = [NSScreen mainScreen]; - } - NSRect windowFrame = [window frame]; - NSRect screenFrame = [screen frame]; - windowFrame.origin.x = screenFrame.origin.x + (float)x; - windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y; - - [window setFrame:windowFrame display:TRUE animate:FALSE]; -} - -// Execute JS in NSWindow -void windowExecJS(void* nsWindow, const char* js) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - [window.webView evaluateJavaScript:[NSString stringWithUTF8String:js] completionHandler:nil]; - free((void*)js); -} - -// Make NSWindow backdrop translucent -void windowSetTranslucent(void* nsWindow) { - // Get window - WebviewWindow* window = (WebviewWindow*)nsWindow; - - id contentView = [window contentView]; - NSVisualEffectView *effectView = [NSVisualEffectView alloc]; - NSRect bounds = [contentView bounds]; - [effectView initWithFrame:bounds]; - [effectView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [effectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; - [effectView setState:NSVisualEffectStateActive]; - [contentView addSubview:effectView positioned:NSWindowBelow relativeTo:nil]; -} - -// Make webview background transparent -void webviewSetTransparent(void* nsWindow) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - // Set webview background transparent - [window.webView setValue:@NO forKey:@"drawsBackground"]; -} - -// Set webview background colour -void webviewSetBackgroundColour(void* nsWindow, int r, int g, int b, int alpha) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - // Set webview background color - [window.webView setValue:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0] forKey:@"backgroundColor"]; -} - -// Set the window background colour -void windowSetBackgroundColour(void* nsWindow, int r, int g, int b, int alpha) { - [(WebviewWindow*)nsWindow setBackgroundColor:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0]]; -} - -bool windowIsMaximised(void* nsWindow) { - return [(WebviewWindow*)nsWindow isZoomed]; -} - -bool windowIsFullscreen(void* nsWindow) { - return [(WebviewWindow*)nsWindow styleMask] & NSWindowStyleMaskFullScreen; -} - -bool windowIsMinimised(void* nsWindow) { - return [(WebviewWindow*)nsWindow isMiniaturized]; -} - -bool windowIsFocused(void* nsWindow) { - return [(WebviewWindow*)nsWindow isKeyWindow]; -} - -// Set Window fullscreen -void windowFullscreen(void* nsWindow) { - if( windowIsFullscreen(nsWindow) ) { - return; - } - dispatch_async(dispatch_get_main_queue(), ^{ - [(WebviewWindow*)nsWindow toggleFullScreen:nil]; - });} - -void windowUnFullscreen(void* nsWindow) { - if( !windowIsFullscreen(nsWindow) ) { - return; - } - dispatch_async(dispatch_get_main_queue(), ^{ - [(WebviewWindow*)nsWindow toggleFullScreen:nil]; - }); -} - -// restore window to normal size -void windowRestore(void* nsWindow) { - // If window is fullscreen - if([(WebviewWindow*)nsWindow styleMask] & NSWindowStyleMaskFullScreen) { - [(WebviewWindow*)nsWindow toggleFullScreen:nil]; - } - // If window is maximised - if([(WebviewWindow*)nsWindow isZoomed]) { - [(WebviewWindow*)nsWindow zoom:nil]; - } - // If window in minimised - if([(WebviewWindow*)nsWindow isMiniaturized]) { - [(WebviewWindow*)nsWindow deminiaturize:nil]; - } -} - -// disable window fullscreen button -void setFullscreenButtonEnabled(void* nsWindow, bool enabled) { - NSButton *fullscreenButton = [(WebviewWindow*)nsWindow standardWindowButton:NSWindowZoomButton]; - fullscreenButton.enabled = enabled; -} - -// Set the titlebar style -void windowSetTitleBarAppearsTransparent(void* nsWindow, bool transparent) { - if( transparent ) { - [(WebviewWindow*)nsWindow setTitlebarAppearsTransparent:true]; - } else { - [(WebviewWindow*)nsWindow setTitlebarAppearsTransparent:false]; - } -} - -// Set window fullsize content view -void windowSetFullSizeContent(void* nsWindow, bool fullSize) { - if( fullSize ) { - [(WebviewWindow*)nsWindow setStyleMask:[(WebviewWindow*)nsWindow styleMask] | NSWindowStyleMaskFullSizeContentView]; - } else { - [(WebviewWindow*)nsWindow setStyleMask:[(WebviewWindow*)nsWindow styleMask] & ~NSWindowStyleMaskFullSizeContentView]; - } -} - -// Set Hide Titlebar -void windowSetHideTitleBar(void* nsWindow, bool hideTitlebar) { - if( hideTitlebar ) { - [(WebviewWindow*)nsWindow setStyleMask:[(WebviewWindow*)nsWindow styleMask] & ~NSWindowStyleMaskTitled]; - } else { - [(WebviewWindow*)nsWindow setStyleMask:[(WebviewWindow*)nsWindow styleMask] | NSWindowStyleMaskTitled]; - } -} - -// Set Hide Title in Titlebar -void windowSetHideTitle(void* nsWindow, bool hideTitle) { - if( hideTitle ) { - [(WebviewWindow*)nsWindow setTitleVisibility:NSWindowTitleHidden]; - } else { - [(WebviewWindow*)nsWindow setTitleVisibility:NSWindowTitleVisible]; - } -} - -// Set Window use toolbar -void windowSetUseToolbar(void* nsWindow, bool useToolbar) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - if( useToolbar ) { - NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"]; - [toolbar autorelease]; - [window setToolbar:toolbar]; - } else { - [window setToolbar:nil]; - } -} - -// Set window toolbar style -void windowSetToolbarStyle(void* nsWindow, int style) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - NSToolbar* toolbar = [window toolbar]; - if ( toolbar == nil ) { - return; - } - [window setToolbarStyle:style]; - } -#endif - -} -// Set Hide Toolbar Separator -void windowSetHideToolbarSeparator(void* nsWindow, bool hideSeparator) { - NSToolbar* toolbar = [(WebviewWindow*)nsWindow toolbar]; - if( toolbar == nil ) { - return; - } - [toolbar setShowsBaselineSeparator:!hideSeparator]; -} - -// Configure the toolbar auto-hide feature -void windowSetShowToolbarWhenFullscreen(void* window, bool setting) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // Get delegate - WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; - // Set height - delegate.showToolbarWhenFullscreen = setting; -} - -// Set Window appearance type -void windowSetAppearanceTypeByName(void* nsWindow, const char *appearanceName) { - // set window appearance type by name - // Convert appearance name to NSString - NSString* appearanceNameString = [NSString stringWithUTF8String:appearanceName]; - // Set appearance - [(WebviewWindow*)nsWindow setAppearance:[NSAppearance appearanceNamed:appearanceNameString]]; - - free((void*)appearanceName); -} - -// Center window on current monitor -void windowCenter(void* nsWindow) { - [(WebviewWindow*)nsWindow center]; -} - -// Get the current size of the window -void windowGetSize(void* nsWindow, int* width, int* height) { - NSRect frame = [(WebviewWindow*)nsWindow frame]; - *width = frame.size.width; - *height = frame.size.height; -} - -// Get window width -int windowGetWidth(void* nsWindow) { - return [(WebviewWindow*)nsWindow frame].size.width; -} - -// Get window height -int windowGetHeight(void* nsWindow) { - return [(WebviewWindow*)nsWindow frame].size.height; -} - -// Get window position -void windowGetRelativePosition(void* nsWindow, int* x, int* y) { - WebviewWindow* window = (WebviewWindow*)nsWindow; - NSRect frame = [window frame]; - *x = frame.origin.x; - - // Translate to screen coordinates so Y=0 is the top of the screen - NSScreen* screen = [window screen]; - if( screen == NULL ) { - screen = [NSScreen mainScreen]; - } - NSRect screenFrame = [screen frame]; - *y = screenFrame.size.height - frame.origin.y - frame.size.height; -} - -// Get absolute window position -void windowGetPosition(void* nsWindow, int* x, int* y) { - NSRect frame = [(WebviewWindow*)nsWindow frame]; - *x = frame.origin.x; - *y = frame.origin.y; -} - -void windowSetPosition(void* nsWindow, int x, int y) { - NSRect frame = [(WebviewWindow*)nsWindow frame]; - frame.origin.x = x; - frame.origin.y = y; - [(WebviewWindow*)nsWindow setFrame:frame display:YES]; -} - -// Destroy window -void windowDestroy(void* nsWindow) { - [(WebviewWindow*)nsWindow close]; -} - -// Remove drop shadow from window -void windowSetShadow(void* nsWindow, bool hasShadow) { - [(WebviewWindow*)nsWindow setHasShadow:hasShadow]; -} - - -// windowClose closes the current window -static void windowClose(void *window) { - [(WebviewWindow*)window close]; -} - -// windowZoom -static void windowZoom(void *window) { - [(WebviewWindow*)window zoom:nil]; -} - -// webviewRenderHTML renders the given HTML -static void windowRenderHTML(void *window, const char *html) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // get window delegate - WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; - // render html - [nsWindow.webView loadHTMLString:[NSString stringWithUTF8String:html] baseURL:nil]; -} - -static void windowInjectCSS(void *window, const char *css) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // inject css - [nsWindow.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); -} - -static void windowMinimise(void *window) { - [(WebviewWindow*)window miniaturize:nil]; -} - -// zoom maximizes the window to the screen dimensions -static void windowMaximise(void *window) { - [(WebviewWindow*)window zoom:nil]; -} - -static bool isFullScreen(void *window) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - long mask = [nsWindow styleMask]; - return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; -} - -static bool isVisible(void *window) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - return (nsWindow.occlusionState & NSWindowOcclusionStateVisible) == NSWindowOcclusionStateVisible; -} - -// windowSetFullScreen -static void windowSetFullScreen(void *window, bool fullscreen) { - if (isFullScreen(window)) { - return; - } - WebviewWindow* nsWindow = (WebviewWindow*)window; - windowSetMaxSize(nsWindow, 0, 0); - windowSetMinSize(nsWindow, 0, 0); - [nsWindow toggleFullScreen:nil]; -} - -// windowUnminimise -static void windowUnminimise(void *window) { - [(WebviewWindow*)window deminiaturize:nil]; -} - -// windowUnmaximise -static void windowUnmaximise(void *window) { - [(WebviewWindow*)window zoom:nil]; -} - -static void windowDisableSizeConstraints(void *window) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // disable size constraints - [nsWindow setContentMinSize:CGSizeZero]; - [nsWindow setContentMaxSize:CGSizeZero]; -} - -static void windowShow(void *window) { - [(WebviewWindow*)window makeKeyAndOrderFront:nil]; -} - -static void windowHide(void *window) { - [(WebviewWindow*)window orderOut:nil]; -} - -// setButtonState sets the state of the given button -// 0 = enabled -// 1 = disabled -// 2 = hidden -static void setButtonState(void *button, int state) { - if (button == nil) { - return; - } - NSButton *nsbutton = (NSButton*)button; - nsbutton.hidden = state == 2; - nsbutton.enabled = state != 1; -} - -// setMinimiseButtonState sets the minimise button state -static void setMinimiseButtonState(void *window, int state) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - NSButton *minimiseButton = [nsWindow standardWindowButton:NSWindowMiniaturizeButton]; - setButtonState(minimiseButton, state); -} - -// setMaximiseButtonState sets the maximise button state -static void setMaximiseButtonState(void *window, int state) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - NSButton *maximiseButton = [nsWindow standardWindowButton:NSWindowZoomButton]; - setButtonState(maximiseButton, state); -} - -// setCloseButtonState sets the close button state -static void setCloseButtonState(void *window, int state) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - NSButton *closeButton = [nsWindow standardWindowButton:NSWindowCloseButton]; - setButtonState(closeButton, state); -} - -// windowShowMenu opens an NSMenu at the given coordinates -static void windowShowMenu(void *window, void *menu, int x, int y) { - NSMenu* nsMenu = (NSMenu*)menu; - WKWebView* webView = ((WebviewWindow*)window).webView; - NSPoint point = NSMakePoint(x, y); - [nsMenu popUpMenuPositioningItem:nil atLocation:point inView:webView]; -} - -// windowIgnoreMouseEvents makes the window ignore mouse events -static void windowIgnoreMouseEvents(void *window, bool ignore) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - [nsWindow setIgnoresMouseEvents:ignore]; -} - -// Make the given window frameless -static void windowSetFrameless(void *window, bool frameless) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // set the window style to be frameless - if (frameless) { - [nsWindow setStyleMask:([nsWindow styleMask] | NSWindowStyleMaskFullSizeContentView)]; - } else { - [nsWindow setStyleMask:([nsWindow styleMask] & ~NSWindowStyleMaskFullSizeContentView)]; - } -} - -static void startDrag(void *window) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - - // Get delegate - WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; - - // start drag - [windowDelegate startDrag:nsWindow]; -} - -// Credit: https://stackoverflow.com/q/33319295 -static void windowPrint(void *window) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - // Check if macOS 11.0 or newer - if (@available(macOS 11.0, *)) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; - WKWebView* webView = nsWindow.webView; - - // TODO: Think about whether to expose this as config - NSPrintInfo *pInfo = [NSPrintInfo sharedPrintInfo]; - pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic; - pInfo.verticalPagination = NSPrintingPaginationModeAutomatic; - pInfo.verticallyCentered = YES; - pInfo.horizontallyCentered = YES; - pInfo.orientation = NSPaperOrientationLandscape; - pInfo.leftMargin = 30; - pInfo.rightMargin = 30; - pInfo.topMargin = 30; - pInfo.bottomMargin = 30; - - NSPrintOperation *po = [webView printOperationWithPrintInfo:pInfo]; - po.showsPrintPanel = YES; - po.showsProgressPanel = YES; - - // Without the next line you get an exception. Also it seems to - // completely ignore the values in the rect. I tried changing them - // in both x and y direction to include content scrolled off screen. - // It had no effect whatsoever in either direction. - po.view.frame = webView.bounds; - - // [printOperation runOperation] DOES NOT WORK WITH WKWEBVIEW, use - [po runOperationModalForWindow:window delegate:windowDelegate didRunSelector:nil contextInfo:nil]; - } -#endif -} - -void setWindowEnabled(void *window, bool enabled) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - [nsWindow setIgnoresMouseEvents:!enabled]; -} - -void windowSetEnabled(void *window, bool enabled) { - // TODO: Implement -} - -void windowFocus(void *window) { - WebviewWindow* nsWindow = (WebviewWindow*)window; - // If the current application is not active, activate it - if (![[NSApplication sharedApplication] isActive]) { - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - } - [nsWindow makeKeyAndOrderFront:nil]; - [nsWindow makeKeyWindow]; -} - +#include "webview_window_darwin_go.h" */ import "C" import ( @@ -1130,121 +365,125 @@ func (w *macosWebviewWindow) run() { C.bool(options.EnableDragAndDrop), w.getWebviewPreferences(), ) - w.setTitle(options.Title) - w.setAlwaysOnTop(options.AlwaysOnTop) - w.setResizable(!options.DisableResize) - if options.MinWidth != 0 || options.MinHeight != 0 { - w.setMinSize(options.MinWidth, options.MinHeight) - } - if options.MaxWidth != 0 || options.MaxHeight != 0 { - w.setMaxSize(options.MaxWidth, options.MaxHeight) - } - //w.setZoom(options.Zoom) - w.enableDevTools() - - w.setBackgroundColour(options.BackgroundColour) - - switch macOptions.Backdrop { - case MacBackdropTransparent: - C.windowSetTransparent(w.nsWindow) - C.webviewSetTransparent(w.nsWindow) - case MacBackdropTranslucent: - C.windowSetTranslucent(w.nsWindow) - C.webviewSetTransparent(w.nsWindow) - case MacBackdropNormal: - } - // Initialise the window buttons - w.setMinimiseButtonState(options.MinimiseButtonState) - w.setMaximiseButtonState(options.MaximiseButtonState) - w.setCloseButtonState(options.CloseButtonState) + w.setup(&options, &macOptions) + }) +} - if options.IgnoreMouseEvents { - C.windowIgnoreMouseEvents(w.nsWindow, C.bool(true)) - } +func (w *macosWebviewWindow) setup(options *WebviewWindowOptions, macOptions *MacWindow) { + w.setTitle(options.Title) + w.setAlwaysOnTop(options.AlwaysOnTop) + w.setResizable(!options.DisableResize) + if options.MinWidth != 0 || options.MinHeight != 0 { + w.setMinSize(options.MinWidth, options.MinHeight) + } + if options.MaxWidth != 0 || options.MaxHeight != 0 { + w.setMaxSize(options.MaxWidth, options.MaxHeight) + } + //w.setZoom(options.Zoom) + w.enableDevTools() - titleBarOptions := macOptions.TitleBar - if !w.parent.options.Frameless { - C.windowSetTitleBarAppearsTransparent(w.nsWindow, C.bool(titleBarOptions.AppearsTransparent)) - C.windowSetHideTitleBar(w.nsWindow, C.bool(titleBarOptions.Hide)) - C.windowSetHideTitle(w.nsWindow, C.bool(titleBarOptions.HideTitle)) - C.windowSetFullSizeContent(w.nsWindow, C.bool(titleBarOptions.FullSizeContent)) - C.windowSetUseToolbar(w.nsWindow, C.bool(titleBarOptions.UseToolbar)) - C.windowSetToolbarStyle(w.nsWindow, C.int(titleBarOptions.ToolbarStyle)) - C.windowSetShowToolbarWhenFullscreen(w.nsWindow, C.bool(titleBarOptions.ShowToolbarWhenFullscreen)) - C.windowSetHideToolbarSeparator(w.nsWindow, C.bool(titleBarOptions.HideToolbarSeparator)) - } + w.setBackgroundColour(options.BackgroundColour) - if macOptions.Appearance != "" { - C.windowSetAppearanceTypeByName(w.nsWindow, C.CString(string(macOptions.Appearance))) - } + switch macOptions.Backdrop { + case MacBackdropTransparent: + C.windowSetTransparent(w.nsWindow) + C.webviewSetTransparent(w.nsWindow) + case MacBackdropTranslucent: + C.windowSetTranslucent(w.nsWindow) + C.webviewSetTransparent(w.nsWindow) + case MacBackdropNormal: + } - if macOptions.InvisibleTitleBarHeight != 0 { - C.windowSetInvisibleTitleBar(w.nsWindow, C.uint(macOptions.InvisibleTitleBarHeight)) - } + // Initialise the window buttons + w.setMinimiseButtonState(options.MinimiseButtonState) + w.setMaximiseButtonState(options.MaximiseButtonState) + w.setCloseButtonState(options.CloseButtonState) - switch w.parent.options.StartState { - case WindowStateMaximised: - w.maximise() - case WindowStateMinimised: - w.minimise() - case WindowStateFullscreen: - w.fullscreen() - case WindowStateNormal: - } - C.windowCenter(w.nsWindow) + if options.IgnoreMouseEvents { + C.windowIgnoreMouseEvents(w.nsWindow, C.bool(true)) + } - startURL, err := assetserver.GetStartURL(options.URL) - if err != nil { - globalApplication.fatal(err.Error()) - } + titleBarOptions := macOptions.TitleBar + if !w.parent.options.Frameless { + C.windowSetTitleBarAppearsTransparent(w.nsWindow, C.bool(titleBarOptions.AppearsTransparent)) + C.windowSetHideTitleBar(w.nsWindow, C.bool(titleBarOptions.Hide)) + C.windowSetHideTitle(w.nsWindow, C.bool(titleBarOptions.HideTitle)) + C.windowSetFullSizeContent(w.nsWindow, C.bool(titleBarOptions.FullSizeContent)) + C.windowSetUseToolbar(w.nsWindow, C.bool(titleBarOptions.UseToolbar)) + C.windowSetToolbarStyle(w.nsWindow, C.int(titleBarOptions.ToolbarStyle)) + C.windowSetShowToolbarWhenFullscreen(w.nsWindow, C.bool(titleBarOptions.ShowToolbarWhenFullscreen)) + C.windowSetHideToolbarSeparator(w.nsWindow, C.bool(titleBarOptions.HideToolbarSeparator)) + } - w.setURL(startURL) - - // We need to wait for the HTML to load before we can execute the javascript - w.parent.On(events.Mac.WebViewDidFinishNavigation, func(_ *WindowEvent) { - InvokeAsync(func() { - if options.JS != "" { - w.execJS(options.JS) - } - if options.CSS != "" { - C.windowInjectCSS(w.nsWindow, C.CString(options.CSS)) - } - if !options.Hidden { - C.windowShow(w.nsWindow) - w.setHasShadow(!options.Mac.DisableShadow) - } else { - // We have to wait until the window is shown before we can remove the shadow - var cancel func() - cancel = w.parent.On(events.Mac.WindowDidBecomeKey, func(_ *WindowEvent) { - w.setHasShadow(!options.Mac.DisableShadow) - cancel() - }) - } - }) - }) + if macOptions.Appearance != "" { + C.windowSetAppearanceTypeByName(w.nsWindow, C.CString(string(macOptions.Appearance))) + } - // Translate ShouldClose to common WindowClosing event - w.parent.On(events.Mac.WindowShouldClose, func(_ *WindowEvent) { - w.parent.emit(events.Common.WindowClosing) - }) + if macOptions.InvisibleTitleBarHeight != 0 { + C.windowSetInvisibleTitleBar(w.nsWindow, C.uint(macOptions.InvisibleTitleBarHeight)) + } - // Translate WindowDidResignKey to common WindowLostFocus event - w.parent.On(events.Mac.WindowDidResignKey, func(_ *WindowEvent) { - w.parent.emit(events.Common.WindowLostFocus) - }) - w.parent.On(events.Mac.WindowDidResignMain, func(_ *WindowEvent) { - w.parent.emit(events.Common.WindowLostFocus) - }) - w.parent.On(events.Mac.WindowDidResize, func(_ *WindowEvent) { - w.parent.emit(events.Common.WindowDidResize) + switch w.parent.options.StartState { + case WindowStateMaximised: + w.maximise() + case WindowStateMinimised: + w.minimise() + case WindowStateFullscreen: + w.fullscreen() + case WindowStateNormal: + } + C.windowCenter(w.nsWindow) + + startURL, err := assetserver.GetStartURL(options.URL) + if err != nil { + globalApplication.fatal(err.Error()) + } + + w.setURL(startURL) + + // We need to wait for the HTML to load before we can execute the javascript + w.parent.On(events.Mac.WebViewDidFinishNavigation, func(_ *WindowEvent) { + InvokeAsync(func() { + if options.JS != "" { + w.execJS(options.JS) + } + if options.CSS != "" { + C.windowInjectCSS(w.nsWindow, C.CString(options.CSS)) + } + if !options.Hidden { + C.windowShow(w.nsWindow) + w.setHasShadow(!options.Mac.DisableShadow) + } else { + // We have to wait until the window is shown before we can remove the shadow + var cancel func() + cancel = w.parent.On(events.Mac.WindowDidBecomeKey, func(_ *WindowEvent) { + w.setHasShadow(!options.Mac.DisableShadow) + cancel() + }) + } }) + }) - if options.HTML != "" { - w.setHTML(options.HTML) - } + // Translate ShouldClose to common WindowClosing event + w.parent.On(events.Mac.WindowShouldClose, func(_ *WindowEvent) { + w.parent.emit(events.Common.WindowClosing) + }) + // Translate WindowDidResignKey to common WindowLostFocus event + w.parent.On(events.Mac.WindowDidResignKey, func(_ *WindowEvent) { + w.parent.emit(events.Common.WindowLostFocus) + }) + w.parent.On(events.Mac.WindowDidResignMain, func(_ *WindowEvent) { + w.parent.emit(events.Common.WindowLostFocus) }) + w.parent.On(events.Mac.WindowDidResize, func(_ *WindowEvent) { + w.parent.emit(events.Common.WindowDidResize) + }) + + if options.HTML != "" { + w.setHTML(options.HTML) + } } func (w *macosWebviewWindow) nativeWindowHandle() uintptr { diff --git a/v3/pkg/application/webview_window_darwin.h b/v3/pkg/application/webview_window_darwin.h index 1dfab739594..c79780c3513 100644 --- a/v3/pkg/application/webview_window_darwin.h +++ b/v3/pkg/application/webview_window_darwin.h @@ -6,15 +6,17 @@ #import #import -@interface WebviewWindow : NSWindow +@interface WebviewWindow : NSObject - (BOOL) canBecomeKeyWindow; - (BOOL) canBecomeMainWindow; - (BOOL) acceptsFirstResponder; - (BOOL) becomeFirstResponder; - (BOOL) resignFirstResponder; -- (WebviewWindow*) initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +- (WebviewWindow*) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +- (WebviewWindow *)initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; -@property (assign) WKWebView* webView; // We already retain WKWebView since it's part of the Window. +@property(assign) NSWindow *w; +@property(assign) WKWebView *webView; // We already retain WKWebView since it's part of the Window. @end diff --git a/v3/pkg/application/webview_window_darwin.m b/v3/pkg/application/webview_window_darwin.m index 00f1eeb0be2..f4bb1c3a47e 100644 --- a/v3/pkg/application/webview_window_darwin.m +++ b/v3/pkg/application/webview_window_darwin.m @@ -8,13 +8,28 @@ extern void processWindowKeyDownEvent(unsigned int, const char*); extern bool hasListeners(unsigned int); @implementation WebviewWindow -- (WebviewWindow*) initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +- (WebviewWindow*) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; { - self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; - [self setAlphaValue:1.0]; - [self setBackgroundColor:[NSColor clearColor]]; - [self setOpaque:NO]; - [self setMovableByWindowBackground:YES]; + self = [super init]; + self.w = [[NSWindow alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + + [self.w setAlphaValue:1.0]; + [self.w setBackgroundColor:[NSColor clearColor]]; + [self.w setOpaque:NO]; + [self.w setMovableByWindowBackground:YES]; + + return self; +} +- (WebviewWindow*) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +{ + self = [super init]; + self.w = (NSWindow *) [[NSPanel alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + + [self.w setAlphaValue:1.0]; + [self.w setBackgroundColor:[NSColor clearColor]]; + [self.w setOpaque:NO]; + [self.w setMovableByWindowBackground:YES]; + return self; } - (void)keyDown:(NSEvent *)event { @@ -41,7 +56,7 @@ - (void)keyDown:(NSEvent *)event { // Combine the modifier strings with the key character NSString *keyEventString = [modifierStrings componentsJoinedByString:@"+"]; const char* utf8String = [keyEventString UTF8String]; - WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)self.delegate; + WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)self.w.delegate; processWindowKeyDownEvent(delegate.windowId, utf8String); } - (NSString *)keyStringFromEvent:(NSEvent *)event { @@ -182,15 +197,16 @@ - (BOOL) resignFirstResponder { } - (void) setDelegate:(id) delegate { [delegate retain]; - [super setDelegate: delegate]; + [self.w setDelegate: delegate]; } - (void) dealloc { // Remove the script handler, otherwise WebviewWindowDelegate won't get deallocated // See: https://stackoverflow.com/questions/26383031/wkwebview-causes-my-view-controller-to-leak [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"external"]; - if (self.delegate) { - [self.delegate release]; + if (self.w.delegate) { + [self.w.delegate release]; } + [self.w dealloc]; [super dealloc]; } @end @@ -205,7 +221,7 @@ - (void) dealloc { [super dealloc]; } - (void) startDrag:(WebviewWindow*)window { - [window performWindowDragWithEvent:self.leftMouseEvent]; + [window.w performWindowDragWithEvent:self.leftMouseEvent]; } // Handle script messages from the external bridge - (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message { diff --git a/v3/pkg/application/webview_window_darwin_dev.go b/v3/pkg/application/webview_window_darwin_dev.go index 6ae5fa9981a..6ceb716c90d 100644 --- a/v3/pkg/application/webview_window_darwin_dev.go +++ b/v3/pkg/application/webview_window_darwin_dev.go @@ -55,3 +55,11 @@ func (w *macosWebviewWindow) openDevTools() { func (w *macosWebviewWindow) enableDevTools() { C.windowEnableDevTools(w.nsWindow) } + +func (w *macosWebviewPanel) openDevTools() { + C.openDevTools(w.nsPanel) +} + +func (w *macosWebviewPanel) enableDevTools() { + C.windowEnableDevTools(w.nsPanel) +} diff --git a/v3/pkg/application/webview_window_darwin_go.h b/v3/pkg/application/webview_window_darwin_go.h new file mode 100644 index 00000000000..e191a2ef094 --- /dev/null +++ b/v3/pkg/application/webview_window_darwin_go.h @@ -0,0 +1,124 @@ +#ifndef WEBVIEW_WINDOW_DARWIN_GO +#define WEBVIEW_WINDOW_DARWIN_GO + +#include "application_darwin.h" +#include "webview_window_darwin.h" +#include +#include "Cocoa/Cocoa.h" +#import +#import +#import "webview_window_darwin_drag.h" + +struct WebviewPreferences +{ + bool *TabFocusesLinks; + bool *TextInteractionEnabled; + bool *FullscreenEnabled; +}; + +extern void registerListener(unsigned int event); + +void *windowNew( + unsigned int id, + int width, + int height, + bool fraudulentWebsiteWarningEnabled, + bool frameless, + bool enableDragAndDrop, + struct WebviewPreferences preferences); + +void *panelNew( + unsigned int id, + int width, + int height, + bool fraudulentWebsiteWarningEnabled, + bool frameless, + bool enableDragAndDrop, + struct WebviewPreferences preferences); + +void *windowOrPanelNew( + bool isWindow, + unsigned int id, + int width, + int height, + bool fraudulentWebsiteWarningEnabled, + bool frameless, + bool enableDragAndDrop, + struct WebviewPreferences preferences); + +void printWindowStyle(void *window); +void setInvisibleTitleBarHeight(void *window, unsigned int height); +void windowSetTransparent(void *nsWindow); +void windowSetInvisibleTitleBar(void *nsWindow, unsigned int height); +void windowSetTitle(void *nsWindow, char *title); +void windowSetSize(void *nsWindow, int width, int height); +void windowSetAlwaysOnTop(void *nsWindow, bool alwaysOnTop); +void navigationLoadURL(void *nsWindow, char *url); +void windowSetResizable(void *nsWindow, bool resizable); +void windowSetMinSize(void *nsWindow, int width, int height); +void windowSetMaxSize(void *nsWindow, int width, int height); +void windowZoomReset(void *nsWindow); +void windowZoomSet(void *nsWindow, double zoom); +float windowZoomGet(void *nsWindow); +void windowZoomIn(void *nsWindow); +void windowZoomOut(void *nsWindow); +void windowSetRelativePosition(void *nsWindow, int x, int y); +void windowExecJS(void *nsWindow, const char *js); +void windowSetTranslucent(void *nsWindow); +void webviewSetTransparent(void *nsWindow); +void webviewSetBackgroundColour(void *nsWindow, int r, int g, int b, int alpha); +void windowSetBackgroundColour(void *nsWindow, int r, int g, int b, int alpha); +bool windowIsMaximised(void *nsWindow); +bool windowIsFullscreen(void *nsWindow); +bool windowIsMinimised(void *nsWindow); +bool windowIsFocused(void *nsWindow); +void windowFullscreen(void *nsWindow); +void windowUnFullscreen(void *nsWindow); +void windowRestore(void *nsWindow); +void setFullscreenButtonEnabled(void *nsWindow, bool enabled); +void windowSetTitleBarAppearsTransparent(void *nsWindow, bool transparent); +void windowSetFullSizeContent(void *nsWindow, bool fullSize); +void windowSetHideTitleBar(void *nsWindow, bool hideTitlebar); +void windowSetHideTitle(void *nsWindow, bool hideTitle); +void windowSetUseToolbar(void *nsWindow, bool useToolbar); +void windowSetToolbarStyle(void *nsWindow, int style); +void windowSetHideToolbarSeparator(void *nsWindow, bool hideSeparator); +void windowSetShowToolbarWhenFullscreen(void *window, bool setting); +void windowSetAppearanceTypeByName(void *nsWindow, const char *appearanceName); +void windowCenter(void *nsWindow); +void windowGetSize(void *nsWindow, int *width, int *height); +int windowGetWidth(void *nsWindow); +int windowGetHeight(void *nsWindow); +void windowGetRelativePosition(void *nsWindow, int *x, int *y); +void windowGetPosition(void *nsWindow, int *x, int *y); +void windowSetPosition(void *nsWindow, int x, int y); +void windowDestroy(void *nsWindow); +void windowSetShadow(void *nsWindow, bool hasShadow); +void windowFocus(void *window); +void windowSetEnabled(void *window, bool enabled); + +void windowClose(void *window); +void windowZoom(void *window); +void windowRenderHTML(void *window, const char *html); +void windowInjectCSS(void *window, const char *css); +void windowMinimise(void *window); +void windowMaximise(void *window); +bool isFullScreen(void *window); +bool isVisible(void *window); +void windowSetFullScreen(void *window, bool fullscreen); +void windowUnminimise(void *window); +void windowUnmaximise(void *window); +void windowDisableSizeConstraints(void *window); +void windowShow(void *window); +void windowHide(void *window); +void setButtonState(void *button, int state); +void setMinimiseButtonState(void *window, int state); +void setMaximiseButtonState(void *window, int state); +void setCloseButtonState(void *window, int state); +void windowShowMenu(void *window, void *menu, int x, int y); +void windowIgnoreMouseEvents(void *window, bool ignore); +void windowSetFrameless(void *window, bool frameless); +void startDrag(void *window); +void windowPrint(void *window); + +#endif // WEBVIEW_WINDOW_DARWIN_GO \ No newline at end of file diff --git a/v3/pkg/application/webview_window_darwin_go.m b/v3/pkg/application/webview_window_darwin_go.m new file mode 100644 index 00000000000..33b454b3398 --- /dev/null +++ b/v3/pkg/application/webview_window_darwin_go.m @@ -0,0 +1,770 @@ +#include "webview_window_darwin_go.h" + +// Create a new Window +void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { + return windowOrPanelNew(true, id, width, height, fraudulentWebsiteWarningEnabled, frameless, enableDragAndDrop, preferences); +} + +// Create a new Panel +void* panelNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { + return windowOrPanelNew(false, id, width, height, fraudulentWebsiteWarningEnabled, frameless, enableDragAndDrop, preferences); +} + +void* windowOrPanelNew(bool isWindow, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { + NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; + if (frameless) { + styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable; + } + + WebviewWindow* webviewWindow; + if (isWindow) { + webviewWindow = [[WebviewWindow alloc] initAsWindow:NSMakeRect(0, 0, width-1, height-1) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + } else { + webviewWindow = [[WebviewWindow alloc] initAsPanel:NSMakeRect(0, 0, width-1, height-1) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + } + + NSWindow *window = webviewWindow.w; + + // Create delegate + WebviewWindowDelegate* delegate = [[WebviewWindowDelegate alloc] init]; + [delegate autorelease]; + + // Set delegate + [window setDelegate:delegate]; + delegate.windowId = id; + + // Add NSView to window + NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, width-1, height-1)]; + [view autorelease]; + + [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + if( frameless ) { + [view setWantsLayer:YES]; + view.layer.cornerRadius = 8.0; + } + [window setContentView:view]; + + // Embed wkwebview in window + NSRect frame = NSMakeRect(0, 0, width, height); + WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init]; + [config autorelease]; + + // Set preferences + if (preferences.TabFocusesLinks != NULL) { + config.preferences.tabFocusesLinks = *preferences.TabFocusesLinks; + } + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110300 + if (@available(macOS 11.3, *)) { + if (preferences.TextInteractionEnabled != NULL) { + config.preferences.textInteractionEnabled = *preferences.TextInteractionEnabled; + } + } +#endif + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 120300 + if (@available(macOS 12.3, *)) { + if (preferences.FullscreenEnabled != NULL) { + config.preferences.elementFullscreenEnabled = *preferences.FullscreenEnabled; + } + } +#endif + + config.suppressesIncrementalRendering = true; + config.applicationNameForUserAgent = @"wails.io"; + [config setURLSchemeHandler:delegate forURLScheme:@"wails"]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 + if (@available(macOS 10.15, *)) { + config.preferences.fraudulentWebsiteWarningEnabled = fraudulentWebsiteWarningEnabled; + } +#endif + + // Setup user content controller + WKUserContentController* userContentController = [WKUserContentController new]; + [userContentController autorelease]; + + [userContentController addScriptMessageHandler:delegate name:@"external"]; + config.userContentController = userContentController; + + WKWebView* webView = [[WKWebView alloc] initWithFrame:frame configuration:config]; + [webView autorelease]; + + [view addSubview:webView]; + + // support webview events + [webView setNavigationDelegate:delegate]; + + // Ensure webview resizes with the window + [webView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + + if( enableDragAndDrop ) { + WebviewDrag* dragView = [[WebviewDrag alloc] initWithFrame:NSMakeRect(0, 0, width-1, height-1)]; + [dragView autorelease]; + + [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [view addSubview:dragView]; + dragView.windowId = id; + } + + webviewWindow.webView = webView; + return webviewWindow; +} + +void printWindowStyle(void *window) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindowStyleMask styleMask = [nsWindow styleMask]; + // Get delegate + WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; + + printf("Window %d style mask: ", windowDelegate.windowId); + + if (styleMask & NSWindowStyleMaskTitled) + { + printf("NSWindowStyleMaskTitled "); + } + + if (styleMask & NSWindowStyleMaskClosable) + { + printf("NSWindowStyleMaskClosable "); + } + + if (styleMask & NSWindowStyleMaskMiniaturizable) + { + printf("NSWindowStyleMaskMiniaturizable "); + } + + if (styleMask & NSWindowStyleMaskResizable) + { + printf("NSWindowStyleMaskResizable "); + } + + if (styleMask & NSWindowStyleMaskFullSizeContentView) + { + printf("NSWindowStyleMaskFullSizeContentView "); + } + + if (styleMask & NSWindowStyleMaskNonactivatingPanel) + { + printf("NSWindowStyleMaskNonactivatingPanel "); + } + + if (styleMask & NSWindowStyleMaskFullScreen) + { + printf("NSWindowStyleMaskFullScreen "); + } + + if (styleMask & NSWindowStyleMaskBorderless) + { + printf("MSWindowStyleMaskBorderless "); + } + + printf("\n"); +} + + +// setInvisibleTitleBarHeight sets the invisible title bar height +void setInvisibleTitleBarHeight(void* window, unsigned int height) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + // Get delegate + WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; + // Set height + delegate.invisibleTitleBarHeight = height; +} + +// Make NSWindow transparent +void windowSetTransparent(void* nsWindow) { + [((WebviewWindow*)nsWindow).w setOpaque:NO]; + [((WebviewWindow*)nsWindow).w setBackgroundColor:[NSColor clearColor]]; +} + +void windowSetInvisibleTitleBar(void* nsWindow, unsigned int height) { + NSWindow* window = ((WebviewWindow*)nsWindow).w; + WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[window delegate]; + delegate.invisibleTitleBarHeight = height; +} + + +// Set the title of the NSWindow +void windowSetTitle(void* nsWindow, char* title) { + NSString* nsTitle = [NSString stringWithUTF8String:title]; + [((WebviewWindow*)nsWindow).w setTitle:nsTitle]; + free(title); +} + +// Set the size of the NSWindow +void windowSetSize(void* nsWindow, int width, int height) { + // Set window size on main thread + NSWindow* window = ((WebviewWindow*)nsWindow).w; + NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; + [window setContentSize:contentSize]; + [window setFrame:NSMakeRect(window.frame.origin.x, window.frame.origin.y, width, height) display:YES animate:YES]; +} + +// Set NSWindow always on top +void windowSetAlwaysOnTop(void* nsWindow, bool alwaysOnTop) { + // Set window always on top on main thread + [((WebviewWindow*)nsWindow).w setLevel:alwaysOnTop ? NSFloatingWindowLevel : NSNormalWindowLevel]; +} + +// Load URL in NSWindow +void navigationLoadURL(void* nsWindow, char* url) { + // Load URL on main thread + NSURL* nsURL = [NSURL URLWithString:[NSString stringWithUTF8String:url]]; + NSURLRequest* request = [NSURLRequest requestWithURL:nsURL]; + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + [webviewWindow.webView loadRequest:request]; + free(url); +} + +// Set NSWindow resizable +void windowSetResizable(void* nsWindow, bool resizable) { + // Set window resizable on main thread + NSWindow* window = ((WebviewWindow*)nsWindow).w; + if (resizable) { + NSWindowStyleMask styleMask = [window styleMask] | NSWindowStyleMaskResizable; + [window setStyleMask:styleMask]; + } else { + NSWindowStyleMask styleMask = [window styleMask] & ~NSWindowStyleMaskResizable; + [window setStyleMask:styleMask]; + } +} + +// Set NSWindow min size +void windowSetMinSize(void* nsWindow, int width, int height) { + // Set window min size on main thread + NSWindow* window = ((WebviewWindow*)nsWindow).w; + NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; + [window setContentMinSize:contentSize]; + NSSize size = { width, height }; + [window setMinSize:size]; +} + +// Set NSWindow max size +void windowSetMaxSize(void* nsWindow, int width, int height) { + // Set window max size on main thread + NSSize size = { FLT_MAX, FLT_MAX }; + size.width = width > 0 ? width : FLT_MAX; + size.height = height > 0 ? height : FLT_MAX; + NSWindow* window = ((WebviewWindow*)nsWindow).w; + NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, size.width, size.height)].size; + [window setContentMaxSize:contentSize]; + [window setMaxSize:size]; +} + +// windowZoomReset +void windowZoomReset(void* nsWindow) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + [webviewWindow.webView setMagnification:1.0]; +} + +// windowZoomSet +void windowZoomSet(void* nsWindow, double zoom) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + // Reset zoom + [webviewWindow.webView setMagnification:zoom]; +} + +// windowZoomGet +float windowZoomGet(void* nsWindow) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + // Get zoom + return [webviewWindow.webView magnification]; +} + +// windowZoomIn +void windowZoomIn(void* nsWindow) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + // Zoom in + [webviewWindow.webView setMagnification:webviewWindow.webView.magnification + 0.05]; +} + +// windowZoomOut +void windowZoomOut(void* nsWindow) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + // Zoom out + if( webviewWindow.webView.magnification > 1.05 ) { + [webviewWindow.webView setMagnification:webviewWindow.webView.magnification - 0.05]; + } else { + [webviewWindow.webView setMagnification:1.0]; + } +} + +// set the window position relative to the screen +void windowSetRelativePosition(void* nsWindow, int x, int y) { + NSWindow* window = ((WebviewWindow*)nsWindow).w; + NSScreen* screen = [window screen]; + if( screen == NULL ) { + screen = [NSScreen mainScreen]; + } + NSRect windowFrame = [window frame]; + NSRect screenFrame = [screen frame]; + windowFrame.origin.x = screenFrame.origin.x + (float)x; + windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y; + + [window setFrame:windowFrame display:TRUE animate:FALSE]; +} + +// Execute JS in NSWindow +void windowExecJS(void* nsWindow, const char* js) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + [webviewWindow.webView evaluateJavaScript:[NSString stringWithUTF8String:js] completionHandler:nil]; + free((void*)js); +} + +// Make NSWindow backdrop translucent +void windowSetTranslucent(void* nsWindow) { + // Get window + NSWindow* window = ((WebviewWindow*)nsWindow).w; + + id contentView = [window contentView]; + NSVisualEffectView *effectView = [NSVisualEffectView alloc]; + NSRect bounds = [contentView bounds]; + [effectView initWithFrame:bounds]; + [effectView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [effectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; + [effectView setState:NSVisualEffectStateActive]; + [contentView addSubview:effectView positioned:NSWindowBelow relativeTo:nil]; +} + +// Make webview background transparent +void webviewSetTransparent(void* nsWindow) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + // Set webview background transparent + [webviewWindow.webView setValue:@NO forKey:@"drawsBackground"]; +} + +// Set webview background colour +void webviewSetBackgroundColour(void* nsWindow, int r, int g, int b, int alpha) { + WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + // Set webview background color + [webviewWindow.webView setValue:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0] forKey:@"backgroundColor"]; +} + +// Set the window background colour +void windowSetBackgroundColour(void* nsWindow, int r, int g, int b, int alpha) { + [((WebviewWindow*)nsWindow).w setBackgroundColor:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0]]; +} + +bool windowIsMaximised(void* nsWindow) { + return [((WebviewWindow*)nsWindow).w isZoomed]; +} + +bool windowIsFullscreen(void* nsWindow) { + return [((WebviewWindow*)nsWindow).w styleMask] & NSWindowStyleMaskFullScreen; +} + +bool windowIsMinimised(void* nsWindow) { + return [((WebviewWindow*)nsWindow).w isMiniaturized]; +} + +bool windowIsFocused(void* nsWindow) { + return [((WebviewWindow*)nsWindow).w isKeyWindow]; +} + +// Set Window fullscreen +void windowFullscreen(void* nsWindow) { + if( windowIsFullscreen(nsWindow) ) { + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [((WebviewWindow*)nsWindow).w toggleFullScreen:nil]; + });} + +void windowUnFullscreen(void* nsWindow) { + if( !windowIsFullscreen(nsWindow) ) { + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [((WebviewWindow*)nsWindow).w toggleFullScreen:nil]; + }); +} + +// restore window to normal size +void windowRestore(void* nsWindow) { + // If window is fullscreen + if([((WebviewWindow*)nsWindow).w styleMask] & NSWindowStyleMaskFullScreen) { + [((WebviewWindow*)nsWindow).w toggleFullScreen:nil]; + } + // If window is maximised + if([((WebviewWindow*)nsWindow).w isZoomed]) { + [((WebviewWindow*)nsWindow).w zoom:nil]; + } + // If window in minimised + if([((WebviewWindow*)nsWindow).w isMiniaturized]) { + [((WebviewWindow*)nsWindow).w deminiaturize:nil]; + } +} + +// disable window fullscreen button +void setFullscreenButtonEnabled(void* nsWindow, bool enabled) { + NSButton *fullscreenButton = [((WebviewWindow*)nsWindow).w standardWindowButton:NSWindowZoomButton]; + fullscreenButton.enabled = enabled; +} + +// Set the titlebar style +void windowSetTitleBarAppearsTransparent(void* nsWindow, bool transparent) { + if( transparent ) { + [((WebviewWindow*)nsWindow).w setTitlebarAppearsTransparent:true]; + } else { + [((WebviewWindow*)nsWindow).w setTitlebarAppearsTransparent:false]; + } +} + +// Set window fullsize content view +void windowSetFullSizeContent(void* nsWindow, bool fullSize) { + if( fullSize ) { + [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] | NSWindowStyleMaskFullSizeContentView]; + } else { + [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] & ~NSWindowStyleMaskFullSizeContentView]; + } +} + +// Set Hide Titlebar +void windowSetHideTitleBar(void* nsWindow, bool hideTitlebar) { + if( hideTitlebar ) { + [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] & ~NSWindowStyleMaskTitled]; + } else { + [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] | NSWindowStyleMaskTitled]; + } +} + +// Set Hide Title in Titlebar +void windowSetHideTitle(void* nsWindow, bool hideTitle) { + if( hideTitle ) { + [((WebviewWindow*)nsWindow).w setTitleVisibility:NSWindowTitleHidden]; + } else { + [((WebviewWindow*)nsWindow).w setTitleVisibility:NSWindowTitleVisible]; + } +} + +// Set Window use toolbar +void windowSetUseToolbar(void* nsWindow, bool useToolbar) { + NSWindow* window = ((WebviewWindow*)nsWindow).w; + if( useToolbar ) { + NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"]; + [toolbar autorelease]; + [window setToolbar:toolbar]; + } else { + [window setToolbar:nil]; + } +} + +// Set window toolbar style +void windowSetToolbarStyle(void* nsWindow, int style) { + NSWindow* window = ((WebviewWindow*)nsWindow).w; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 + if (@available(macOS 11.0, *)) { + NSToolbar* toolbar = [window toolbar]; + if ( toolbar == nil ) { + return; + } + [window setToolbarStyle:style]; + } +#endif + +} +// Set Hide Toolbar Separator +void windowSetHideToolbarSeparator(void* nsWindow, bool hideSeparator) { + NSToolbar* toolbar = [((WebviewWindow*)nsWindow).w toolbar]; + if( toolbar == nil ) { + return; + } + [toolbar setShowsBaselineSeparator:!hideSeparator]; +} + +// Configure the toolbar auto-hide feature +void windowSetShowToolbarWhenFullscreen(void* window, bool setting) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + // Get delegate + WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; + // Set height + delegate.showToolbarWhenFullscreen = setting; +} + +// Set Window appearance type +void windowSetAppearanceTypeByName(void* nsWindow, const char *appearanceName) { + // set window appearance type by name + // Convert appearance name to NSString + NSString* appearanceNameString = [NSString stringWithUTF8String:appearanceName]; + // Set appearance + [((WebviewWindow*)nsWindow).w setAppearance:[NSAppearance appearanceNamed:appearanceNameString]]; + + free((void*)appearanceName); +} + +// Center window on current monitor +void windowCenter(void* nsWindow) { + [((WebviewWindow*)nsWindow).w center]; +} + +// Get the current size of the window +void windowGetSize(void* nsWindow, int* width, int* height) { + NSRect frame = [((WebviewWindow*)nsWindow).w frame]; + *width = frame.size.width; + *height = frame.size.height; +} + +// Get window width +int windowGetWidth(void* nsWindow) { + return [((WebviewWindow*)nsWindow).w frame].size.width; +} + +// Get window height +int windowGetHeight(void* nsWindow) { + return [((WebviewWindow*)nsWindow).w frame].size.height; +} + +// Get window position +void windowGetRelativePosition(void* nsWindow, int* x, int* y) { + NSWindow* window = ((WebviewWindow*)nsWindow).w; + NSRect frame = [window frame]; + *x = frame.origin.x; + + // Translate to screen coordinates so Y=0 is the top of the screen + NSScreen* screen = [window screen]; + if( screen == NULL ) { + screen = [NSScreen mainScreen]; + } + NSRect screenFrame = [screen frame]; + *y = screenFrame.size.height - frame.origin.y - frame.size.height; +} + +// Get absolute window position +void windowGetPosition(void* nsWindow, int* x, int* y) { + NSRect frame = [((WebviewWindow*)nsWindow).w frame]; + *x = frame.origin.x; + *y = frame.origin.y; +} + +void windowSetPosition(void* nsWindow, int x, int y) { + NSRect frame = [((WebviewWindow*)nsWindow).w frame]; + frame.origin.x = x; + frame.origin.y = y; + [((WebviewWindow*)nsWindow).w setFrame:frame display:YES]; +} + +// Destroy window +void windowDestroy(void* nsWindow) { + [((WebviewWindow*)nsWindow).w close]; +} + +// Remove drop shadow from window +void windowSetShadow(void* nsWindow, bool hasShadow) { + [((WebviewWindow*)nsWindow).w setHasShadow:hasShadow]; +} + + +// windowClose closes the current window +void windowClose(void *window) { + [((WebviewWindow*)window).w close]; +} + +// windowZoom +void windowZoom(void *window) { + [((WebviewWindow*)window).w zoom:nil]; +} + +// webviewRenderHTML renders the given HTML +void windowRenderHTML(void *window, const char *html) { + WebviewWindow *webviewWindow = (WebviewWindow *)window; + NSWindow* nsWindow = webviewWindow.w; + // get window delegate + WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; + // render html + [webviewWindow.webView loadHTMLString:[NSString stringWithUTF8String:html] baseURL:nil]; +} + +void windowInjectCSS(void *window, const char *css) { + WebviewWindow *webviewWindow = (WebviewWindow *)window; + // inject css + [webviewWindow.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); +} + +void windowMinimise(void *window) { + [((WebviewWindow*)window).w miniaturize:nil]; +} + +// zoom maximizes the window to the screen dimensions +void windowMaximise(void *window) { + [((WebviewWindow*)window).w zoom:nil]; +} + +bool isFullScreen(void *window) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + long mask = [nsWindow styleMask]; + return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; +} + +bool isVisible(void *window) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + return (nsWindow.occlusionState & NSWindowOcclusionStateVisible) == NSWindowOcclusionStateVisible; +} + +// windowSetFullScreen +void windowSetFullScreen(void *window, bool fullscreen) { + if (isFullScreen(window)) { + return; + } + NSWindow* nsWindow = ((WebviewWindow *)window).w; + windowSetMaxSize(nsWindow, 0, 0); + windowSetMinSize(nsWindow, 0, 0); + [nsWindow toggleFullScreen:nil]; +} + +// windowUnminimise +void windowUnminimise(void *window) { + [((WebviewWindow*)window).w deminiaturize:nil]; +} + +// windowUnmaximise +void windowUnmaximise(void *window) { + [((WebviewWindow*)window).w zoom:nil]; +} + +void windowDisableSizeConstraints(void *window) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + // disable size constraints + [nsWindow setContentMinSize:CGSizeZero]; + [nsWindow setContentMaxSize:CGSizeZero]; +} + +void windowShow(void *window) { + [((WebviewWindow*)window).w makeKeyAndOrderFront:nil]; +} + +void windowHide(void *window) { + [((WebviewWindow*)window).w orderOut:nil]; +} + +// setButtonState sets the state of the given button +// 0 = enabled +// 1 = disabled +// 2 = hidden +void setButtonState(void *button, int state) { + if (button == nil) { + return; + } + NSButton *nsbutton = (NSButton*)button; + nsbutton.hidden = state == 2; + nsbutton.enabled = state != 1; +} + +// setMinimiseButtonState sets the minimise button state +void setMinimiseButtonState(void *window, int state) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSButton *minimiseButton = [nsWindow standardWindowButton:NSWindowMiniaturizeButton]; + setButtonState(minimiseButton, state); +} + +// setMaximiseButtonState sets the maximise button state +void setMaximiseButtonState(void *window, int state) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSButton *maximiseButton = [nsWindow standardWindowButton:NSWindowZoomButton]; + setButtonState(maximiseButton, state); +} + +// setCloseButtonState sets the close button state +void setCloseButtonState(void *window, int state) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSButton *closeButton = [nsWindow standardWindowButton:NSWindowCloseButton]; + setButtonState(closeButton, state); +} + +// windowShowMenu opens an NSMenu at the given coordinates +void windowShowMenu(void *window, void *menu, int x, int y) { + NSMenu* nsMenu = (NSMenu*)menu; + WKWebView* webView = ((WebviewWindow*)window).webView; + NSPoint point = NSMakePoint(x, y); + [nsMenu popUpMenuPositioningItem:nil atLocation:point inView:webView]; +} + +// windowIgnoreMouseEvents makes the window ignore mouse events +void windowIgnoreMouseEvents(void *window, bool ignore) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + [nsWindow setIgnoresMouseEvents:ignore]; +} + +// Make the given window frameless +void windowSetFrameless(void *window, bool frameless) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + // set the window style to be frameless + if (frameless) { + [nsWindow setStyleMask:([nsWindow styleMask] | NSWindowStyleMaskFullSizeContentView)]; + } else { + [nsWindow setStyleMask:([nsWindow styleMask] & ~NSWindowStyleMaskFullSizeContentView)]; + } +} + +void startDrag(void *window) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; + NSWindow* nsWindow = webviewWindow.w; + + // Get delegate + WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; + + // start drag + [windowDelegate startDrag:webviewWindow]; +} + +// Credit: https://stackoverflow.com/q/33319295 +void windowPrint(void *window) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 + // Check if macOS 11.0 or newer + if (@available(macOS 11.0, *)) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; + NSWindow* nsWindow = webviewWindow.w; + + WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; + WKWebView* webView = webviewWindow.webView; + + // TODO: Think about whether to expose this as config + NSPrintInfo *pInfo = [NSPrintInfo sharedPrintInfo]; + pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic; + pInfo.verticalPagination = NSPrintingPaginationModeAutomatic; + pInfo.verticallyCentered = YES; + pInfo.horizontallyCentered = YES; + pInfo.orientation = NSPaperOrientationLandscape; + pInfo.leftMargin = 30; + pInfo.rightMargin = 30; + pInfo.topMargin = 30; + pInfo.bottomMargin = 30; + + NSPrintOperation *po = [webView printOperationWithPrintInfo:pInfo]; + po.showsPrintPanel = YES; + po.showsProgressPanel = YES; + + // Without the next line you get an exception. Also it seems to + // completely ignore the values in the rect. I tried changing them + // in both x and y direction to include content scrolled off screen. + // It had no effect whatsoever in either direction. + po.view.frame = webView.bounds; + + // [printOperation runOperation] DOES NOT WORK WITH WKWEBVIEW, use + [po runOperationModalForWindow:window delegate:windowDelegate didRunSelector:nil contextInfo:nil]; + } +#endif +} + +void windowSetEnabled(void *window, bool enabled) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + [nsWindow setIgnoresMouseEvents:!enabled]; +} + +void windowFocus(void *window) { + NSWindow* nsWindow = ((WebviewWindow *)window).w; + // If the current application is not active, activate it + if (![[NSApplication sharedApplication] isActive]) { + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; + } + [nsWindow makeKeyAndOrderFront:nil]; + [nsWindow makeKeyWindow]; +} \ No newline at end of file From 5b5b12bfd88da6f4f1df3fb6c26b666f8cdcfc06 Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Thu, 19 Sep 2024 19:57:55 +0200 Subject: [PATCH 02/20] MacOS NSPanel implemented with every existing feature --- v3/pkg/application/application.go | 23 ++- v3/pkg/application/application_options.go | 2 +- v3/pkg/application/webview_panel_darwin.go | 4 +- .../webview_panel_options_darwin.go | 15 +- v3/pkg/application/webview_responder_darwin.h | 15 ++ v3/pkg/application/webview_responder_darwin.m | 169 ++++++++++++++++ v3/pkg/application/webview_window.go | 4 +- v3/pkg/application/webview_window_darwin.h | 21 +- v3/pkg/application/webview_window_darwin.m | 190 ++---------------- 9 files changed, 246 insertions(+), 197 deletions(-) create mode 100644 v3/pkg/application/webview_responder_darwin.h create mode 100644 v3/pkg/application/webview_responder_darwin.m diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index 33d409471b6..590d4ff3d7f 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -161,6 +161,21 @@ func New(appOptions Options) *App { return result } +func processKeyBindingOptions(keyBindings map[string]func(window Window)) map[string]func(window Window) { + result := make(map[string]func(window Window)) + for key, callback := range keyBindings { + // Parse the key to an accelerator + acc, err := parseAccelerator(key) + if err != nil { + globalApplication.error("Invalid keybinding: %s", err.Error()) + continue + } + result[acc.String()] = callback + globalApplication.debug("Added Keybinding", "accelerator", acc.String()) + } + return result +} + func mergeApplicationDefaults(o *Options) { if o.Name == "" { o.Name = "My Wails Application" @@ -317,7 +332,7 @@ type App struct { isDebugMode bool // Keybindings - keyBindings map[string]func(window *WebviewWindow) + keyBindings map[string]func(window Window) keyBindingsLock sync.RWMutex // Shutdown @@ -363,7 +378,7 @@ func (a *App) init() { a.windows = make(map[uint]Window) a.systemTrays = make(map[uint]*SystemTray) a.contextMenus = make(map[string]*Menu) - a.keyBindings = make(map[string]func(window *WebviewWindow)) + a.keyBindings = make(map[string]func(window Window)) a.Logger = a.options.Logger a.pid = os.Getpid() a.wailsEventListeners = make([]WailsEventListener, 0) @@ -879,7 +894,7 @@ func (a *App) runOrDeferToAppRun(r runnable) { } } -func (a *App) processKeyBinding(acceleratorString string, window *WebviewWindow) bool { +func (a *App) processKeyBinding(acceleratorString string, window Window) bool { if len(a.keyBindings) == 0 { return false } @@ -899,7 +914,7 @@ func (a *App) processKeyBinding(acceleratorString string, window *WebviewWindow) return true } -func (a *App) addKeyBinding(acceleratorString string, callback func(window *WebviewWindow)) { +func (a *App) addKeyBinding(acceleratorString string, callback func(window Window)) { a.keyBindingsLock.Lock() defer a.keyBindingsLock.Unlock() a.keyBindings[acceleratorString] = callback diff --git a/v3/pkg/application/application_options.go b/v3/pkg/application/application_options.go index c9580f158ae..0a52a1e9760 100644 --- a/v3/pkg/application/application_options.go +++ b/v3/pkg/application/application_options.go @@ -76,7 +76,7 @@ type Options struct { DisableDefaultSignalHandler bool // KeyBindings is a map of key bindings to functions - KeyBindings map[string]func(window *WebviewWindow) + KeyBindings map[string]func(window Window) // OnShutdown is called when the application is about to terminate. // This is useful for cleanup tasks. diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go index fc9d4527f13..016e4c36b82 100644 --- a/v3/pkg/application/webview_panel_darwin.go +++ b/v3/pkg/application/webview_panel_darwin.go @@ -75,8 +75,8 @@ func NewPanel(options WebviewPanelOptions) *WebviewPanel { }) // Process keybindings - if result.options.KeyBindings != nil { - result.keyBindings = processKeyBindingOptionsForPanel(result.options.KeyBindings) + if result.options.KeyBindings != nil || result.options.WebviewWindowOptions.KeyBindings != nil { + result.keyBindings = processKeyBindingOptionsForPanel(result.options.KeyBindings, result.options.WebviewWindowOptions.KeyBindings) } return result diff --git a/v3/pkg/application/webview_panel_options_darwin.go b/v3/pkg/application/webview_panel_options_darwin.go index 004de093648..406b8355eab 100644 --- a/v3/pkg/application/webview_panel_options_darwin.go +++ b/v3/pkg/application/webview_panel_options_darwin.go @@ -18,8 +18,21 @@ var WebviewPanelDefaults = &WebviewPanelOptions{ WebviewWindowOptions: *WebviewWindowDefaults, } -func processKeyBindingOptionsForPanel(keyBindings map[string]func(panel *WebviewPanel)) map[string]func(panel *WebviewPanel) { +func processKeyBindingOptionsForPanel(keyBindings map[string]func(panel *WebviewPanel), windowKeyBindings map[string]func(panel *WebviewWindow)) map[string]func(panel *WebviewPanel) { result := make(map[string]func(panel *WebviewPanel)) + + for key, callback := range windowKeyBindings { + acc, err := parseAccelerator(key) + if err != nil { + globalApplication.error("Invalid keybinding: %s", err.Error()) + continue + } + result[acc.String()] = func(panel *WebviewPanel) { + callback(&panel.WebviewWindow) + } + globalApplication.debug("Added Keybinding", "accelerator", acc.String()) + } + for key, callback := range keyBindings { // Parse the key to an accelerator acc, err := parseAccelerator(key) diff --git a/v3/pkg/application/webview_responder_darwin.h b/v3/pkg/application/webview_responder_darwin.h new file mode 100644 index 00000000000..fb0c9179b7b --- /dev/null +++ b/v3/pkg/application/webview_responder_darwin.h @@ -0,0 +1,15 @@ +#ifndef WEBVIEW_RESPONDER_DARWIN +#define WEBVIEW_RESPONDER_DARWIN + +#import + +@interface WebviewResponder : NSResponder +@property(assign) NSWindow *w; + +- (WebviewResponder *) initAttachToWindow:(NSWindow *)window; +- (void)keyDown:(NSEvent *)event; +- (NSString *)keyStringFromEvent:(NSEvent *)event; +- (NSString *)specialKeyStringFromEvent:(NSEvent *)event; +@end + +#endif /* WEBVIEW_RESPONDER_DARWIN */ diff --git a/v3/pkg/application/webview_responder_darwin.m b/v3/pkg/application/webview_responder_darwin.m new file mode 100644 index 00000000000..fe42508b7f2 --- /dev/null +++ b/v3/pkg/application/webview_responder_darwin.m @@ -0,0 +1,169 @@ +#include "webview_responder_darwin.h" +#include "webview_window_darwin.h" + +extern void processWindowKeyDownEvent(unsigned int, const char*); + +@implementation WebviewResponder +- (WebviewResponder *) initAttachToWindow:(NSWindow *)window { + self = [super init]; + + self.w = window; + [window setNextResponder:self]; + + return self; +} +- (void)keyDown:(NSEvent *)event { + // TODO: FIX: ctrl+l never reaches this function + NSUInteger modifierFlags = event.modifierFlags; + // Create an array to hold the modifier strings + NSMutableArray *modifierStrings = [NSMutableArray array]; + // Check for modifier flags and add corresponding strings to the array + if (modifierFlags & NSEventModifierFlagShift) { + [modifierStrings addObject:@"shift"]; + } + if (modifierFlags & NSEventModifierFlagControl) { + [modifierStrings addObject:@"ctrl"]; + } + if (modifierFlags & NSEventModifierFlagOption) { + [modifierStrings addObject:@"option"]; + } + if (modifierFlags & NSEventModifierFlagCommand) { + [modifierStrings addObject:@"cmd"]; + } + NSString *keyString = [self keyStringFromEvent:event]; + if (keyString.length > 0) { + [modifierStrings addObject:keyString]; + } + // Combine the modifier strings with the key character + NSString *keyEventString = [modifierStrings componentsJoinedByString:@"+"]; + const char* utf8String = [keyEventString UTF8String]; + WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)self.w.delegate; + processWindowKeyDownEvent(delegate.windowId, utf8String); +} +- (NSString *)keyStringFromEvent:(NSEvent *)event { + // Get the pressed key + switch ([event keyCode]) { + // Function keys + case 122: return @"f1"; + case 120: return @"f2"; + case 99: return @"f3"; + case 118: return @"f4"; + case 96: return @"f5"; + case 97: return @"f6"; + case 98: return @"f7"; + case 100: return @"f8"; + case 101: return @"f9"; + case 109: return @"f10"; + case 103: return @"f11"; + case 111: return @"f12"; + case 105: return @"f13"; + case 107: return @"f14"; + case 113: return @"f15"; + case 106: return @"f16"; + case 64: return @"f17"; + case 79: return @"f18"; + case 80: return @"f19"; + case 90: return @"f20"; + // Letter keys + case 0: return @"a"; + case 11: return @"b"; + case 8: return @"c"; + case 2: return @"d"; + case 14: return @"e"; + case 3: return @"f"; + case 5: return @"g"; + case 4: return @"h"; + case 34: return @"i"; + case 38: return @"j"; + case 40: return @"k"; + case 37: return @"l"; + case 46: return @"m"; + case 45: return @"n"; + case 31: return @"o"; + case 35: return @"p"; + case 12: return @"q"; + case 15: return @"r"; + case 1: return @"s"; + case 17: return @"t"; + case 32: return @"u"; + case 9: return @"v"; + case 13: return @"w"; + case 7: return @"x"; + case 16: return @"y"; + case 6: return @"z"; + // Number keys + case 29: return @"0"; + case 18: return @"1"; + case 19: return @"2"; + case 20: return @"3"; + case 21: return @"4"; + case 23: return @"5"; + case 22: return @"6"; + case 26: return @"7"; + case 28: return @"8"; + case 25: return @"9"; + // Other special keys + case 51: return @"delete"; + case 117: return @"forward delete"; + case 123: return @"left"; + case 124: return @"right"; + case 126: return @"up"; + case 125: return @"down"; + case 48: return @"tab"; + case 53: return @"escape"; + case 49: return @"space"; + // Punctuation and other keys (for a standard US layout) + case 33: return @"["; + case 30: return @"]"; + case 43: return @","; + case 27: return @"-"; + case 39: return @"'"; + case 44: return @"/"; + case 47: return @"."; + case 41: return @";"; + case 24: return @"="; + case 50: return @"`"; + case 42: return @"\\"; + default: return [self specialKeyStringFromEvent:event]; + } +} +- (NSString *)specialKeyStringFromEvent:(NSEvent *)event { + // Check for special keys like escape and tab + NSString *characters = [event characters]; + if (characters.length == 0) { + return @""; + } + + if ([characters isEqualToString:@"\r"]) { + return @"enter"; + } + if ([characters isEqualToString:@"\b"]) { + return @"backspace"; + } + if ([characters isEqualToString:@"\e"]) { + return @"escape"; + } + // page down + if ([characters isEqualToString:@"\x0B"]) { + return @"page down"; + } + // page up + if ([characters isEqualToString:@"\x0E"]) { + return @"page up"; + } + // home + if ([characters isEqualToString:@"\x01"]) { + return @"home"; + } + // end + if ([characters isEqualToString:@"\x04"]) { + return @"end"; + } + // clear + if ([characters isEqualToString:@"\x0C"]) { + return @"clear"; + } + // default + return @""; +} +@end \ No newline at end of file diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 3ecb19f9001..47e38f2b506 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -235,13 +235,13 @@ func NewWindow(options WebviewWindowOptions) *WebviewWindow { // Process keybindings if result.options.KeyBindings != nil { - result.keyBindings = processKeyBindingOptions(result.options.KeyBindings) + result.keyBindings = windowProcessKeyBindingOptions(result.options.KeyBindings) } return result } -func processKeyBindingOptions(keyBindings map[string]func(window *WebviewWindow)) map[string]func(window *WebviewWindow) { +func windowProcessKeyBindingOptions(keyBindings map[string]func(window *WebviewWindow)) map[string]func(window *WebviewWindow) { result := make(map[string]func(window *WebviewWindow)) for key, callback := range keyBindings { // Parse the key to an accelerator diff --git a/v3/pkg/application/webview_window_darwin.h b/v3/pkg/application/webview_window_darwin.h index c79780c3513..9474fbdae4b 100644 --- a/v3/pkg/application/webview_window_darwin.h +++ b/v3/pkg/application/webview_window_darwin.h @@ -1,22 +1,18 @@ -//go:build darwin - -#ifndef WebviewWindowDelegate_h -#define WebviewWindowDelegate_h +#ifndef WEBVIEW_WINDOW_DARWIN +#define WEBVIEW_WINDOW_DARWIN #import #import +#include "webview_responder_darwin.h" @interface WebviewWindow : NSObject -- (BOOL) canBecomeKeyWindow; -- (BOOL) canBecomeMainWindow; -- (BOOL) acceptsFirstResponder; -- (BOOL) becomeFirstResponder; -- (BOOL) resignFirstResponder; -- (WebviewWindow*) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; -- (WebviewWindow *)initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; @property(assign) NSWindow *w; @property(assign) WKWebView *webView; // We already retain WKWebView since it's part of the Window. +@property(assign) WebviewResponder *responder; + +- (WebviewWindow *) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +- (WebviewWindow *) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; @end @@ -34,5 +30,4 @@ @end - -#endif /* WebviewWindowDelegate_h */ +#endif /* WEBVIEW_WINDOW_DARWIN */ diff --git a/v3/pkg/application/webview_window_darwin.m b/v3/pkg/application/webview_window_darwin.m index f4bb1c3a47e..1fc498d3042 100644 --- a/v3/pkg/application/webview_window_darwin.m +++ b/v3/pkg/application/webview_window_darwin.m @@ -3,26 +3,30 @@ #import #import "webview_window_darwin.h" #import "../events/events_darwin.h" + extern void processMessage(unsigned int, const char*); extern void processURLRequest(unsigned int, void *); -extern void processWindowKeyDownEvent(unsigned int, const char*); extern bool hasListeners(unsigned int); + @implementation WebviewWindow -- (WebviewWindow*) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +- (WebviewWindow *) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; { self = [super init]; - self.w = [[NSWindow alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + self.w = [[NSWindow alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; [self.w setAlphaValue:1.0]; [self.w setBackgroundColor:[NSColor clearColor]]; [self.w setOpaque:NO]; [self.w setMovableByWindowBackground:YES]; + + self.responder = [[WebviewResponder alloc] initAttachToWindow:self.w]; return self; } -- (WebviewWindow*) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; +- (WebviewWindow *) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; { self = [super init]; + self.w = (NSWindow *) [[NSPanel alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; [self.w setAlphaValue:1.0]; @@ -30,186 +34,24 @@ - (WebviewWindow*) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowS [self.w setOpaque:NO]; [self.w setMovableByWindowBackground:YES]; + self.responder = [[WebviewResponder alloc] initAttachToWindow:self.w]; + return self; } -- (void)keyDown:(NSEvent *)event { - NSUInteger modifierFlags = event.modifierFlags; - // Create an array to hold the modifier strings - NSMutableArray *modifierStrings = [NSMutableArray array]; - // Check for modifier flags and add corresponding strings to the array - if (modifierFlags & NSEventModifierFlagShift) { - [modifierStrings addObject:@"shift"]; - } - if (modifierFlags & NSEventModifierFlagControl) { - [modifierStrings addObject:@"ctrl"]; - } - if (modifierFlags & NSEventModifierFlagOption) { - [modifierStrings addObject:@"option"]; - } - if (modifierFlags & NSEventModifierFlagCommand) { - [modifierStrings addObject:@"cmd"]; - } - NSString *keyString = [self keyStringFromEvent:event]; - if (keyString.length > 0) { - [modifierStrings addObject:keyString]; - } - // Combine the modifier strings with the key character - NSString *keyEventString = [modifierStrings componentsJoinedByString:@"+"]; - const char* utf8String = [keyEventString UTF8String]; - WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)self.w.delegate; - processWindowKeyDownEvent(delegate.windowId, utf8String); -} -- (NSString *)keyStringFromEvent:(NSEvent *)event { - // Get the pressed key - // Check for special keys like escape and tab - NSString *characters = [event characters]; - if (characters.length == 0) { - return @""; - } - if ([characters isEqualToString:@"\r"]) { - return @"enter"; - } - if ([characters isEqualToString:@"\b"]) { - return @"backspace"; - } - if ([characters isEqualToString:@"\e"]) { - return @"escape"; - } - // page down - if ([characters isEqualToString:@"\x0B"]) { - return @"page down"; - } - // page up - if ([characters isEqualToString:@"\x0E"]) { - return @"page up"; - } - // home - if ([characters isEqualToString:@"\x01"]) { - return @"home"; - } - // end - if ([characters isEqualToString:@"\x04"]) { - return @"end"; - } - // clear - if ([characters isEqualToString:@"\x0C"]) { - return @"clear"; - } - switch ([event keyCode]) { - // Function keys - case 122: return @"f1"; - case 120: return @"f2"; - case 99: return @"f3"; - case 118: return @"f4"; - case 96: return @"f5"; - case 97: return @"f6"; - case 98: return @"f7"; - case 100: return @"f8"; - case 101: return @"f9"; - case 109: return @"f10"; - case 103: return @"f11"; - case 111: return @"f12"; - case 105: return @"f13"; - case 107: return @"f14"; - case 113: return @"f15"; - case 106: return @"f16"; - case 64: return @"f17"; - case 79: return @"f18"; - case 80: return @"f19"; - case 90: return @"f20"; - // Letter keys - case 0: return @"a"; - case 11: return @"b"; - case 8: return @"c"; - case 2: return @"d"; - case 14: return @"e"; - case 3: return @"f"; - case 5: return @"g"; - case 4: return @"h"; - case 34: return @"i"; - case 38: return @"j"; - case 40: return @"k"; - case 37: return @"l"; - case 46: return @"m"; - case 45: return @"n"; - case 31: return @"o"; - case 35: return @"p"; - case 12: return @"q"; - case 15: return @"r"; - case 1: return @"s"; - case 17: return @"t"; - case 32: return @"u"; - case 9: return @"v"; - case 13: return @"w"; - case 7: return @"x"; - case 16: return @"y"; - case 6: return @"z"; - // Number keys - case 29: return @"0"; - case 18: return @"1"; - case 19: return @"2"; - case 20: return @"3"; - case 21: return @"4"; - case 23: return @"5"; - case 22: return @"6"; - case 26: return @"7"; - case 28: return @"8"; - case 25: return @"9"; - // Other special keys - case 51: return @"delete"; - case 117: return @"forward delete"; - case 123: return @"left"; - case 124: return @"right"; - case 126: return @"up"; - case 125: return @"down"; - case 48: return @"tab"; - case 53: return @"escape"; - case 49: return @"space"; - // Punctuation and other keys (for a standard US layout) - case 33: return @"["; - case 30: return @"]"; - case 43: return @","; - case 27: return @"-"; - case 39: return @"'"; - case 44: return @"/"; - case 47: return @"."; - case 41: return @";"; - case 24: return @"="; - case 50: return @"`"; - case 42: return @"\\"; - default: return @""; - } -} -- (BOOL)canBecomeKeyWindow { - return YES; -} -- (BOOL) canBecomeMainWindow { - return YES; -} -- (BOOL) acceptsFirstResponder { - return YES; -} -- (BOOL) becomeFirstResponder { - return YES; -} -- (BOOL) resignFirstResponder { - return YES; -} -- (void) setDelegate:(id) delegate { - [delegate retain]; - [self.w setDelegate: delegate]; -} - (void) dealloc { // Remove the script handler, otherwise WebviewWindowDelegate won't get deallocated // See: https://stackoverflow.com/questions/26383031/wkwebview-causes-my-view-controller-to-leak [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"external"]; - if (self.w.delegate) { - [self.w.delegate release]; - } + [self.webView dealloc]; + [self.w dealloc]; + + [self.responder dealloc]; + [super dealloc]; } @end + @implementation WebviewWindowDelegate - (BOOL)windowShouldClose:(NSWindow *)sender { processWindowEvent(self.windowId, EventWindowShouldClose); From 83721203f4329446c51a7a1428737a3d9586b78c Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Thu, 19 Sep 2024 21:28:33 +0200 Subject: [PATCH 03/20] Fixed WebviewWindow dealloc function --- v3/pkg/application/webview_window_darwin.m | 6 ------ 1 file changed, 6 deletions(-) diff --git a/v3/pkg/application/webview_window_darwin.m b/v3/pkg/application/webview_window_darwin.m index 1fc498d3042..e94ea08c0d1 100644 --- a/v3/pkg/application/webview_window_darwin.m +++ b/v3/pkg/application/webview_window_darwin.m @@ -42,12 +42,6 @@ - (void) dealloc { // Remove the script handler, otherwise WebviewWindowDelegate won't get deallocated // See: https://stackoverflow.com/questions/26383031/wkwebview-causes-my-view-controller-to-leak [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"external"]; - [self.webView dealloc]; - - [self.w dealloc]; - - [self.responder dealloc]; - [super dealloc]; } @end From 71327ca69dedb32b7cbb488165c27e507baf93b7 Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Thu, 19 Sep 2024 23:57:50 +0200 Subject: [PATCH 04/20] Improved event error logs --- v3/pkg/application/application.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index 7585927d849..5d603c51612 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -683,7 +683,7 @@ func (a *App) handleDragAndDropMessage(event *dragAndDropMessage) { window, ok := a.windows[event.windowId] a.windowsLock.Unlock() if !ok { - log.Printf("WebviewWindow #%d not found", event.windowId) + a.error("DragAndDropMessage: WebviewWindow #%d not found", event.windowId) return } // Get callback from window @@ -696,7 +696,7 @@ func (a *App) handleWindowMessage(event *windowMessage) { window, ok := a.windows[event.windowId] a.windowsLock.RUnlock() if !ok { - log.Printf("WebviewWindow #%d not found", event.windowId) + a.error("WindowMessage: WebviewWindow #%d not found", event.windowId) return } // Check if the message starts with "wails:" @@ -719,7 +719,7 @@ func (a *App) handleWindowEvent(event *windowEvent) { window, ok := a.windows[event.WindowID] a.windowsLock.RUnlock() if !ok { - log.Printf("Window #%d not found", event.WindowID) + a.error("WindowEvent %d: Window #%d not found", event.EventID, event.WindowID) return } window.HandleWindowEvent(event.EventID) @@ -982,7 +982,7 @@ func (a *App) handleWindowKeyEvent(event *windowKeyEvent) { window, ok := a.windows[event.windowId] a.windowsLock.RUnlock() if !ok { - log.Printf("WebviewWindow #%d not found", event.windowId) + a.error("WindowKeyEvent: WebviewWindow #%d not found", event.windowId) return } // Get callback from window From 1a9b1b19d0d3bfab2ce5f3c619d4e79832624c43 Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Fri, 20 Sep 2024 10:07:53 +0200 Subject: [PATCH 05/20] Proper file rename --- v3/pkg/application/webview_panel_darwin.go | 2 +- ..._window_darwin_go.h => webview_window_bindings_darwin.h} | 6 +++--- ..._window_darwin_go.m => webview_window_bindings_darwin.m} | 2 +- v3/pkg/application/webview_window_darwin.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename v3/pkg/application/{webview_window_darwin_go.h => webview_window_bindings_darwin.h} (97%) rename v3/pkg/application/{webview_window_darwin_go.m => webview_window_bindings_darwin.m} (99%) diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go index 8d9fd372c9b..b667479588f 100644 --- a/v3/pkg/application/webview_panel_darwin.go +++ b/v3/pkg/application/webview_panel_darwin.go @@ -4,7 +4,7 @@ package application #cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c #cgo LDFLAGS: -framework Cocoa -framework WebKit -#include "webview_window_darwin_go.h" +#include "webview_window_bindings_darwin.h" // Set NSPanel floating void panelSetFloating(void* nsPanel, bool floating) { diff --git a/v3/pkg/application/webview_window_darwin_go.h b/v3/pkg/application/webview_window_bindings_darwin.h similarity index 97% rename from v3/pkg/application/webview_window_darwin_go.h rename to v3/pkg/application/webview_window_bindings_darwin.h index 141ace0e95d..99074823eec 100644 --- a/v3/pkg/application/webview_window_darwin_go.h +++ b/v3/pkg/application/webview_window_bindings_darwin.h @@ -1,5 +1,5 @@ -#ifndef WEBVIEW_WINDOW_DARWIN_GO -#define WEBVIEW_WINDOW_DARWIN_GO +#ifndef WEBVIEW_WINDOW_BINDINGS_DARWIN +#define WEBVIEW_WINDOW_BINDINGS_DARWIN #include "application_darwin.h" #include "webview_window_darwin.h" @@ -104,4 +104,4 @@ void windowFocus(void *window); bool isIgnoreMouseEvents(void *nsWindow); void setIgnoreMouseEvents(void *nsWindow, bool ignore); -#endif // WEBVIEW_WINDOW_DARWIN_GO \ No newline at end of file +#endif // WEBVIEW_WINDOW_BINDINGS_DARWIN \ No newline at end of file diff --git a/v3/pkg/application/webview_window_darwin_go.m b/v3/pkg/application/webview_window_bindings_darwin.m similarity index 99% rename from v3/pkg/application/webview_window_darwin_go.m rename to v3/pkg/application/webview_window_bindings_darwin.m index 11e67e54824..2aff0ee1de9 100644 --- a/v3/pkg/application/webview_window_darwin_go.m +++ b/v3/pkg/application/webview_window_bindings_darwin.m @@ -1,4 +1,4 @@ -#include "webview_window_darwin_go.h" +#include "webview_window_bindings_darwin.h" // Create a new Window void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index 17b7262b87d..7ec63697995 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -6,7 +6,7 @@ package application #cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c #cgo LDFLAGS: -framework Cocoa -framework WebKit -#include "webview_window_darwin_go.h" +#include "webview_window_bindings_darwin.h" */ import "C" import ( From 7797e2e01feffc0078c9e47ab561b07ca8600af9 Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Fri, 20 Sep 2024 10:38:51 +0200 Subject: [PATCH 06/20] Prepared multi-os support and fixed examples --- v3/examples/build/main.go | 46 +++---- v3/examples/events-bug/main.go | 4 +- v3/examples/keybindings/main.go | 4 +- v3/examples/window/main.go | 84 ++++++------ .../commands/appimage_testfiles/main.go | 64 ++++----- v3/pkg/application/menu_windows.go | 2 +- v3/pkg/application/popupmenu_windows.go | 2 +- v3/pkg/application/webview_panel.go | 120 +++++++++++++++++ v3/pkg/application/webview_panel_darwin.go | 125 ++---------------- v3/pkg/application/webview_panel_linux.go | 5 + ...ons_darwin.go => webview_panel_options.go} | 0 v3/pkg/application/webview_panel_windows.go | 5 + v3/pkg/application/window.go | 3 + 13 files changed, 245 insertions(+), 219 deletions(-) create mode 100644 v3/pkg/application/webview_panel.go create mode 100644 v3/pkg/application/webview_panel_linux.go rename v3/pkg/application/{webview_panel_options_darwin.go => webview_panel_options.go} (100%) create mode 100644 v3/pkg/application/webview_panel_windows.go diff --git a/v3/examples/build/main.go b/v3/examples/build/main.go index b8a0db3078f..cebeb467f3c 100755 --- a/v3/examples/build/main.go +++ b/v3/examples/build/main.go @@ -29,7 +29,7 @@ func main() { log.Println("ApplicationDidFinishLaunching") }) - currentWindow := func(fn func(window *application.WebviewWindow)) { + currentWindow := func(fn func(window application.Window)) { if app.CurrentWindow() != nil { fn(app.CurrentWindow()) } else { @@ -118,122 +118,122 @@ func main() { sizeMenu := menu.AddSubmenu("Size") sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetSize(800, 600) }) }) sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200) }) }) sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinSize(200, 200) }) }) sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaximiseButtonState(application.ButtonDisabled) w.SetMaxSize(600, 600) }) }) sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { width, height := w.Size() application.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show() }) }) sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinSize(0, 0) }) }) sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaxSize(0, 0) w.SetMaximiseButtonState(application.ButtonEnabled) }) }) positionMenu := menu.AddSubmenu("Position") positionMenu.Add("Set Relative Position (0,0)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetRelativePosition(0, 0) }) }) positionMenu.Add("Set Relative Position (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetRelativePosition(rand.Intn(1000), rand.Intn(800)) }) }) positionMenu.Add("Get Relative Position").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { x, y := w.RelativePosition() application.InfoDialog().SetTitle("Current WebviewWindow Relative Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() }) }) positionMenu.Add("Center").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Center() }) }) stateMenu := menu.AddSubmenu("State") stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Minimise() time.Sleep(2 * time.Second) w.Restore() }) }) stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Maximise() }) }) stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Fullscreen() }) }) stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.UnFullscreen() }) }) stateMenu.Add("Restore").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Restore() }) }) stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Hide() time.Sleep(2 * time.Second) w.Show() }) }) stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetAlwaysOnTop(true) }) }) stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetAlwaysOnTop(false) }) }) stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetURL("https://google.com") }) }) stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetURL("https://wails.io") }) }) @@ -258,7 +258,7 @@ func main() { } }) stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { screen, err := w.GetScreen() if err != nil { application.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() diff --git a/v3/examples/events-bug/main.go b/v3/examples/events-bug/main.go index 02af2385678..88130ddf0f8 100644 --- a/v3/examples/events-bug/main.go +++ b/v3/examples/events-bug/main.go @@ -13,8 +13,8 @@ func main() { Mac: application.MacOptions{ ApplicationShouldTerminateAfterLastWindowClosed: true, }, - KeyBindings: map[string]func(window *application.WebviewWindow){ - "shift+ctrl+c": func(window *application.WebviewWindow) { + KeyBindings: map[string]func(window application.Window){ + "shift+ctrl+c": func(window application.Window) { selection, err := application.OpenFileDialog(). CanChooseFiles(true). CanCreateDirectories(true). diff --git a/v3/examples/keybindings/main.go b/v3/examples/keybindings/main.go index ee9dee82568..c816e6bbf17 100644 --- a/v3/examples/keybindings/main.go +++ b/v3/examples/keybindings/main.go @@ -13,8 +13,8 @@ func main() { Mac: application.MacOptions{ ApplicationShouldTerminateAfterLastWindowClosed: true, }, - KeyBindings: map[string]func(window *application.WebviewWindow){ - "shift+ctrl+c": func(window *application.WebviewWindow) { + KeyBindings: map[string]func(window application.Window){ + "shift+ctrl+c": func(window application.Window) { window.Center() }, }, diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go index 3ed305a3c64..9709cbddad9 100644 --- a/v3/examples/window/main.go +++ b/v3/examples/window/main.go @@ -33,9 +33,9 @@ func main() { log.Println("ApplicationDidFinishLaunching") }) - var hiddenWindows []*application.WebviewWindow + var hiddenWindows []application.Window - currentWindow := func(fn func(window *application.WebviewWindow)) { + currentWindow := func(fn func(window application.Window)) { if app.CurrentWindow() != nil { fn(app.CurrentWindow()) } else { @@ -197,7 +197,7 @@ func main() { // If the user clicks the close button again, the window will // close. ShouldClose: func(window *application.WebviewWindow) bool { - if !lo.Contains(hiddenWindows, window) { + if !lo.Contains(hiddenWindows, application.Window(window)) { hiddenWindows = append(hiddenWindows, window) go func() { time.Sleep(5 * time.Second) @@ -207,7 +207,7 @@ func main() { return false } // Remove the window from the hiddenWindows list - hiddenWindows = lo.Without(hiddenWindows, window) + hiddenWindows = lo.Without(hiddenWindows, application.Window(window)) return true }, }). @@ -338,41 +338,41 @@ func main() { sizeMenu := menu.AddSubmenu("Size") sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetSize(800, 600) }) }) sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200) }) }) sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinSize(200, 200) }) }) sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaxSize(600, 600) w.SetMaximiseButtonState(application.ButtonDisabled) }) }) sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { width, height := w.Size() application.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show() }) }) sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinSize(0, 0) }) }) sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaxSize(0, 0) w.SetMaximiseButtonState(application.ButtonEnabled) }) @@ -380,145 +380,145 @@ func main() { positionMenu := menu.AddSubmenu("Position") positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetPosition(0, 0) }) }) positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetPosition(rand.Intn(1000), rand.Intn(800)) }) }) positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { x, y := w.Position() application.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() }) }) positionMenu.Add("Set Relative Position (0,0)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetRelativePosition(0, 0) }) }) positionMenu.Add("Set Relative Position (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetRelativePosition(rand.Intn(1000), rand.Intn(800)) }) }) positionMenu.Add("Get Relative Position").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { x, y := w.RelativePosition() application.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() }) }) positionMenu.Add("Center").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Center() }) }) titleBarMenu := menu.AddSubmenu("Controls") titleBarMenu.Add("Disable Minimise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinimiseButtonState(application.ButtonDisabled) }) }) titleBarMenu.Add("Enable Minimise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinimiseButtonState(application.ButtonEnabled) }) }) titleBarMenu.Add("Hide Minimise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinimiseButtonState(application.ButtonHidden) }) }) titleBarMenu.Add("Disable Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaximiseButtonState(application.ButtonDisabled) }) }) titleBarMenu.Add("Enable Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaximiseButtonState(application.ButtonEnabled) }) }) titleBarMenu.Add("Hide Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaximiseButtonState(application.ButtonHidden) }) }) titleBarMenu.Add("Disable Close").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetCloseButtonState(application.ButtonDisabled) }) }) titleBarMenu.Add("Enable Close").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetCloseButtonState(application.ButtonEnabled) }) }) titleBarMenu.Add("Hide Close").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetCloseButtonState(application.ButtonHidden) }) }) stateMenu := menu.AddSubmenu("State") stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Minimise() time.Sleep(2 * time.Second) w.Restore() }) }) stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Maximise() }) }) stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Fullscreen() }) }) stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.UnFullscreen() }) }) stateMenu.Add("Restore").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Restore() }) }) stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Hide() time.Sleep(2 * time.Second) w.Show() }) }) stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetAlwaysOnTop(true) }) }) stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetAlwaysOnTop(false) }) }) stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetURL("https://google.com") }) }) stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetURL("https://wails.io") }) }) @@ -543,7 +543,7 @@ func main() { } }) stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { screen, err := w.GetScreen() if err != nil { application.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() @@ -554,21 +554,21 @@ func main() { }) }) stateMenu.Add("Disable for 5s").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetEnabled(false) time.Sleep(5 * time.Second) w.SetEnabled(true) }) }) stateMenu.Add("Open Dev Tools").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.OpenDevTools() }) }) if runtime.GOOS != "darwin" { stateMenu.Add("Flash for 5s").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { time.Sleep(2 * time.Second) w.Flash(true) time.Sleep(5 * time.Second) @@ -579,7 +579,7 @@ func main() { printMenu := menu.AddSubmenu("Print") printMenu.Add("Print").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { _ = w.Print() }) }) diff --git a/v3/internal/commands/appimage_testfiles/main.go b/v3/internal/commands/appimage_testfiles/main.go index e63f9f4d5d0..f0df3300787 100644 --- a/v3/internal/commands/appimage_testfiles/main.go +++ b/v3/internal/commands/appimage_testfiles/main.go @@ -28,9 +28,9 @@ func main() { log.Println("ApplicationDidFinishLaunching") }) - var hiddenWindows []*application.WebviewWindow + var hiddenWindows []application.Window - currentWindow := func(fn func(window *application.WebviewWindow)) { + currentWindow := func(fn func(window application.Window)) { if app.CurrentWindow() != nil { fn(app.CurrentWindow()) } else { @@ -66,7 +66,7 @@ func main() { // If the user clicks the close button again, the window will // close. ShouldClose: func(window *application.WebviewWindow) bool { - if !lo.Contains(hiddenWindows, window) { + if !lo.Contains(hiddenWindows, application.Window(window)) { hiddenWindows = append(hiddenWindows, window) go func() { time.Sleep(5 * time.Second) @@ -76,7 +76,7 @@ func main() { return false } // Remove the window from the hiddenWindows list - hiddenWindows = lo.Without(hiddenWindows, window) + hiddenWindows = lo.Without(hiddenWindows, application.Window(window)) return true }, }). @@ -207,141 +207,141 @@ func main() { sizeMenu := menu.AddSubmenu("Size") sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetSize(800, 600) }) }) sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200) }) }) sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinSize(200, 200) }) }) sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaximiseButtonState(application.ButtonDisabled) w.SetMaxSize(600, 600) }) }) sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { width, height := w.Size() application.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show() }) }) sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMinSize(0, 0) }) }) sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetMaxSize(0, 0) w.SetMaximiseButtonState(application.ButtonEnabled) }) }) positionMenu := menu.AddSubmenu("Position") positionMenu.Add("Set Relative Position (0,0)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetRelativePosition(0, 0) }) }) positionMenu.Add("Set Relative Position (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetRelativePosition(rand.Intn(1000), rand.Intn(800)) }) }) positionMenu.Add("Get Relative Position").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { x, y := w.RelativePosition() application.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() }) }) positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetPosition(0, 0) }) }) positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetPosition(rand.Intn(1000), rand.Intn(800)) }) }) positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { x, y := w.Position() application.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() }) }) positionMenu.Add("Center").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Center() }) }) stateMenu := menu.AddSubmenu("State") stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Minimise() time.Sleep(2 * time.Second) w.Restore() }) }) stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Maximise() }) }) stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Fullscreen() }) }) stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.UnFullscreen() }) }) stateMenu.Add("Restore").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Restore() }) }) stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.Hide() time.Sleep(2 * time.Second) w.Show() }) }) stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetAlwaysOnTop(true) }) }) stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetAlwaysOnTop(false) }) }) stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetURL("https://google.com") }) }) stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetURL("https://wails.io") }) }) @@ -366,7 +366,7 @@ func main() { } }) stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { screen, err := w.GetScreen() if err != nil { application.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() @@ -377,7 +377,7 @@ func main() { }) }) stateMenu.Add("Disable for 5s").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { w.SetEnabled(false) time.Sleep(5 * time.Second) w.SetEnabled(true) @@ -386,7 +386,7 @@ func main() { if runtime.GOOS == "windows" { stateMenu.Add("Flash Start").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { time.Sleep(2 * time.Second) w.Flash(true) }) @@ -395,7 +395,7 @@ func main() { printMenu := menu.AddSubmenu("Print") printMenu.Add("Print").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { _ = w.Print() }) }) diff --git a/v3/pkg/application/menu_windows.go b/v3/pkg/application/menu_windows.go index e0d3d8a0cc2..525454fc47b 100644 --- a/v3/pkg/application/menu_windows.go +++ b/v3/pkg/application/menu_windows.go @@ -73,7 +73,7 @@ func (w *windowsMenu) processMenu(parentMenu w32.HMENU, inputMenu *Menu) { if w.parentWindow != nil { w.parentWindow.parent.addMenuBinding(item.accelerator, item) } else { - globalApplication.addKeyBinding(item.accelerator.String(), func(w *WebviewWindow) { + globalApplication.addKeyBinding(item.accelerator.String(), func(w Window) { item.handleClick() }) } diff --git a/v3/pkg/application/popupmenu_windows.go b/v3/pkg/application/popupmenu_windows.go index 11a155b4401..1e7c156a601 100644 --- a/v3/pkg/application/popupmenu_windows.go +++ b/v3/pkg/application/popupmenu_windows.go @@ -123,7 +123,7 @@ func (p *Win32Menu) buildMenu(parentMenu w32.HMENU, inputMenu *Menu) { if p.parentWindow != nil { p.parentWindow.parent.addMenuBinding(item.accelerator, item) } else { - globalApplication.addKeyBinding(item.accelerator.String(), func(w *WebviewWindow) { + globalApplication.addKeyBinding(item.accelerator.String(), func(w Window) { item.handleClick() }) } diff --git a/v3/pkg/application/webview_panel.go b/v3/pkg/application/webview_panel.go new file mode 100644 index 00000000000..3a6e748da48 --- /dev/null +++ b/v3/pkg/application/webview_panel.go @@ -0,0 +1,120 @@ +package application + +import "github.com/wailsapp/wails/v3/pkg/events" + +type webviewPanelImpl interface { + webviewWindowImpl + getWebviewWindowImpl() webviewWindowImpl + setFloating(floating bool) +} + +type WebviewPanel struct { + WebviewWindow + + options WebviewPanelOptions + impl webviewPanelImpl + // keyBindings holds the keybindings for the panel + keyBindings map[string]func(*WebviewPanel) +} + +// NewPanel creates a new panel with the given options +func NewPanel(options WebviewPanelOptions) *WebviewPanel { + if options.Width == 0 { + options.Width = 800 + } + if options.Height == 0 { + options.Height = 600 + } + if options.URL == "" { + options.URL = "/" + } + + result := &WebviewPanel{ + WebviewWindow: WebviewWindow{ + id: getWindowID(), + options: options.WebviewWindowOptions, + eventListeners: make(map[uint][]*WindowEventListener), + contextMenus: make(map[string]*Menu), + eventHooks: make(map[uint][]*WindowEventListener), + menuBindings: make(map[string]*MenuItem), + }, + options: options, + } + + result.setupEventMapping() + + // Listen for window closing events and de + result.OnWindowEvent(events.Common.WindowClosing, func(event *WindowEvent) { + shouldClose := true + if result.options.ShouldClose != nil { + shouldClose = result.options.ShouldClose(result) + } + if shouldClose { + globalApplication.deleteWindowByID(result.id) + InvokeSync(result.impl.close) + } + }) + + // Process keybindings + if result.options.KeyBindings != nil || result.options.WebviewWindowOptions.KeyBindings != nil { + result.keyBindings = processKeyBindingOptionsForPanel(result.options.KeyBindings, result.options.WebviewWindowOptions.KeyBindings) + } + + return result +} + +func (p *WebviewPanel) Run() { + if p.impl != nil { + return + } + + p.impl = newPanelImpl(p) + p.WebviewWindow.impl = p.impl.getWebviewWindowImpl() + + InvokeSync(p.impl.run) +} + +// SetFloating makes the panel float above other application in every workspace. +func (p *WebviewPanel) SetFloating(b bool) Window { + p.options.Floating = b + if p.impl != nil { + InvokeSync(func() { + p.impl.setFloating(b) + }) + } + return p +} + +func (p *WebviewPanel) HandleKeyEvent(acceleratorString string) { + if p.impl == nil && !p.isDestroyed() { + return + } + InvokeSync(func() { + p.impl.handleKeyEvent(acceleratorString) + }) +} + +func (p *WebviewPanel) processKeyBinding(acceleratorString string) bool { + // Check menu bindings + if p.menuBindings != nil { + p.menuBindingsLock.RLock() + defer p.menuBindingsLock.RUnlock() + if menuItem := p.menuBindings[acceleratorString]; menuItem != nil { + menuItem.handleClick() + return true + } + } + + // Check key bindings + if p.keyBindings != nil { + p.keyBindingsLock.RLock() + defer p.keyBindingsLock.RUnlock() + if callback := p.keyBindings[acceleratorString]; callback != nil { + // Execute callback + go callback(p) + return true + } + } + + return globalApplication.processKeyBinding(acceleratorString, &p.WebviewWindow) +} diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go index b667479588f..c1ef8408027 100644 --- a/v3/pkg/application/webview_panel_darwin.go +++ b/v3/pkg/application/webview_panel_darwin.go @@ -27,117 +27,6 @@ import ( "github.com/wailsapp/wails/v3/pkg/events" ) -type WebviewPanel struct { - WebviewWindow - - options WebviewPanelOptions - impl *macosWebviewPanel - // keyBindings holds the keybindings for the panel - keyBindings map[string]func(*WebviewPanel) -} - -// NewPanel creates a new panel with the given options -func NewPanel(options WebviewPanelOptions) *WebviewPanel { - if options.Width == 0 { - options.Width = 800 - } - if options.Height == 0 { - options.Height = 600 - } - if options.URL == "" { - options.URL = "/" - } - - result := &WebviewPanel{ - WebviewWindow: WebviewWindow{ - id: getWindowID(), - options: options.WebviewWindowOptions, - eventListeners: make(map[uint][]*WindowEventListener), - contextMenus: make(map[string]*Menu), - eventHooks: make(map[uint][]*WindowEventListener), - menuBindings: make(map[string]*MenuItem), - }, - options: options, - } - - result.setupEventMapping() - - // Listen for window closing events and de - result.OnWindowEvent(events.Common.WindowClosing, func(event *WindowEvent) { - shouldClose := true - if result.options.ShouldClose != nil { - shouldClose = result.options.ShouldClose(result) - } - if shouldClose { - globalApplication.deleteWindowByID(result.id) - InvokeSync(result.impl.close) - } - }) - - // Process keybindings - if result.options.KeyBindings != nil || result.options.WebviewWindowOptions.KeyBindings != nil { - result.keyBindings = processKeyBindingOptionsForPanel(result.options.KeyBindings, result.options.WebviewWindowOptions.KeyBindings) - } - - return result -} - -func (p *WebviewPanel) Run() { - if p.impl != nil { - return - } - - p.impl = newPanel(p) - p.WebviewWindow.impl = &p.impl.macosWebviewWindow - - InvokeSync(p.impl.run) -} - -// SetFloating makes the panel float above other application in every workspace. -func (p *WebviewPanel) SetFloating(b bool) Window { - p.options.Floating = b - if p.impl != nil { - InvokeSync(func() { - p.impl.setFloating(b) - }) - } - return p -} - -func (p *WebviewPanel) HandleKeyEvent(acceleratorString string) { - if p.impl == nil && !p.isDestroyed() { - return - } - InvokeSync(func() { - p.impl.handleKeyEvent(acceleratorString) - }) -} - -func (p *WebviewPanel) processKeyBinding(acceleratorString string) bool { - // Check menu bindings - if p.menuBindings != nil { - p.menuBindingsLock.RLock() - defer p.menuBindingsLock.RUnlock() - if menuItem := p.menuBindings[acceleratorString]; menuItem != nil { - menuItem.handleClick() - return true - } - } - - // Check key bindings - if p.keyBindings != nil { - p.keyBindingsLock.RLock() - defer p.keyBindingsLock.RUnlock() - if callback := p.keyBindings[acceleratorString]; callback != nil { - // Execute callback - go callback(p) - return true - } - } - - return globalApplication.processKeyBinding(acceleratorString, &p.WebviewWindow) -} - type macosWebviewPanel struct { macosWebviewWindow @@ -145,11 +34,7 @@ type macosWebviewPanel struct { parent *WebviewPanel } -func (p *macosWebviewPanel) setFloating(floating bool) { - C.panelSetFloating(p.nsPanel, C.bool(floating)) -} - -func newPanel(parent *WebviewPanel) *macosWebviewPanel { +func newPanelImpl(parent *WebviewPanel) *macosWebviewPanel { result := &macosWebviewPanel{ macosWebviewWindow: macosWebviewWindow{ parent: &parent.WebviewWindow, @@ -162,6 +47,10 @@ func newPanel(parent *WebviewPanel) *macosWebviewPanel { return result } +func (p *macosWebviewPanel) getWebviewWindowImpl() webviewWindowImpl { + return &p.macosWebviewWindow +} + func (p *macosWebviewPanel) run() { for eventId := range p.parent.eventListeners { p.on(eventId) @@ -194,3 +83,7 @@ func (p *macosWebviewPanel) handleKeyEvent(acceleratorString string) { } p.parent.processKeyBinding(accelerator.String()) } + +func (p *macosWebviewPanel) setFloating(floating bool) { + C.panelSetFloating(p.nsPanel, C.bool(floating)) +} diff --git a/v3/pkg/application/webview_panel_linux.go b/v3/pkg/application/webview_panel_linux.go new file mode 100644 index 00000000000..26e45b66747 --- /dev/null +++ b/v3/pkg/application/webview_panel_linux.go @@ -0,0 +1,5 @@ +package application + +func newPanelImpl(parent *WebviewPanel) webviewPanelImpl { + panic("Linux Panel not implemented") +} diff --git a/v3/pkg/application/webview_panel_options_darwin.go b/v3/pkg/application/webview_panel_options.go similarity index 100% rename from v3/pkg/application/webview_panel_options_darwin.go rename to v3/pkg/application/webview_panel_options.go diff --git a/v3/pkg/application/webview_panel_windows.go b/v3/pkg/application/webview_panel_windows.go new file mode 100644 index 00000000000..da2af6019f1 --- /dev/null +++ b/v3/pkg/application/webview_panel_windows.go @@ -0,0 +1,5 @@ +package application + +func newPanelImpl(parent *WebviewPanel) webviewPanelImpl { + panic("Windows Panel not implemented") +} diff --git a/v3/pkg/application/window.go b/v3/pkg/application/window.go index 797380e0c74..f3fe06cf415 100644 --- a/v3/pkg/application/window.go +++ b/v3/pkg/application/window.go @@ -22,6 +22,7 @@ type Window interface { EnableSizeConstraints() Error(message string, args ...any) ExecJS(js string) + Flash(enabled bool) Focus() ForceReload() Fullscreen() Window @@ -47,12 +48,14 @@ type Window interface { OnWindowEvent(eventType events.WindowEventType, callback func(event *WindowEvent)) func() OpenContextMenu(data *ContextMenuData) Position() (int, int) + Print() error RegisterContextMenu(name string, menu *Menu) RelativePosition() (int, int) Reload() Resizable() bool Restore() Run() + SetEnabled(enabled bool) SetPosition(x, y int) SetAlwaysOnTop(b bool) Window SetBackgroundColour(colour RGBA) Window From 76558b9467a872d8e08f5100775c46dc712dee37 Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Fri, 20 Sep 2024 14:13:10 +0200 Subject: [PATCH 07/20] App method to create panel exposed to every OS --- v3/pkg/application/application.go | 18 ++++++++++++++++++ v3/pkg/application/application_darwin.go | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index 5d603c51612..f40e7ef273e 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -543,6 +543,24 @@ func (a *App) NewWebviewWindowWithOptions(windowOptions WebviewWindowOptions) *W return newWindow } +func (a *App) NewWebviewPanelWithOptions(panelOptions WebviewPanelOptions) *WebviewPanel { + newPanel := NewPanel(panelOptions) + id := newPanel.ID() + + a.windowsLock.Lock() + a.windows[id] = newPanel + a.windowsLock.Unlock() + + // Call hooks + for _, hook := range a.windowCreatedCallbacks { + hook(newPanel) + } + + a.runOrDeferToAppRun(newPanel) + + return newPanel +} + func (a *App) NewSystemTray() *SystemTray { id := a.getSystemTrayID() newSystemTray := newSystemTray(id) diff --git a/v3/pkg/application/application_darwin.go b/v3/pkg/application/application_darwin.go index b9a06eee1ed..69de385072d 100644 --- a/v3/pkg/application/application_darwin.go +++ b/v3/pkg/application/application_darwin.go @@ -363,21 +363,3 @@ func (a *App) platformEnvironment() map[string]any { func fatalHandler(errFunc func(error)) { return } - -func (a *App) NewWebviewPanelWithOptions(panelOptions WebviewPanelOptions) *WebviewPanel { - newPanel := NewPanel(panelOptions) - id := newPanel.ID() - - a.windowsLock.Lock() - a.windows[id] = newPanel - a.windowsLock.Unlock() - - // Call hooks - for _, hook := range a.windowCreatedCallbacks { - hook(newPanel) - } - - a.runOrDeferToAppRun(newPanel) - - return newPanel -} From 2ede8e214e64c616fcbf04424588b87baabed24f Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Sat, 21 Sep 2024 13:00:13 +0200 Subject: [PATCH 08/20] Fixed some issues pointed out in the PR by rabbit --- v3/pkg/application/application.go | 6 +- v3/pkg/application/application_options.go | 5 +- v3/pkg/application/webview_panel.go | 8 ++- v3/pkg/application/webview_panel_darwin.go | 4 ++ v3/pkg/application/webview_panel_options.go | 5 +- v3/pkg/application/webview_window.go | 2 +- .../webview_window_bindings_darwin.h | 15 ++--- .../webview_window_bindings_darwin.m | 60 +++++++------------ v3/pkg/application/webview_window_darwin.go | 8 ++- v3/pkg/application/webview_window_darwin.m | 21 +++---- 10 files changed, 66 insertions(+), 68 deletions(-) diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index f40e7ef273e..9cc60cb4edb 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -701,7 +701,7 @@ func (a *App) handleDragAndDropMessage(event *dragAndDropMessage) { window, ok := a.windows[event.windowId] a.windowsLock.Unlock() if !ok { - a.error("DragAndDropMessage: WebviewWindow #%d not found", event.windowId) + a.error("DragAndDropMessage: Window #%d not found", event.windowId) return } // Get callback from window @@ -714,7 +714,7 @@ func (a *App) handleWindowMessage(event *windowMessage) { window, ok := a.windows[event.windowId] a.windowsLock.RUnlock() if !ok { - a.error("WindowMessage: WebviewWindow #%d not found", event.windowId) + a.error("WindowMessage: Window #%d not found", event.windowId) return } // Check if the message starts with "wails:" @@ -1000,7 +1000,7 @@ func (a *App) handleWindowKeyEvent(event *windowKeyEvent) { window, ok := a.windows[event.windowId] a.windowsLock.RUnlock() if !ok { - a.error("WindowKeyEvent: WebviewWindow #%d not found", event.windowId) + a.error("WindowKeyEvent: Window #%d not found", event.windowId) return } // Get callback from window diff --git a/v3/pkg/application/application_options.go b/v3/pkg/application/application_options.go index 1aff97418e8..e34a4fc7224 100644 --- a/v3/pkg/application/application_options.go +++ b/v3/pkg/application/application_options.go @@ -89,7 +89,10 @@ type Options struct { // DisableDefaultSignalHandler disables the default signal handler DisableDefaultSignalHandler bool - // KeyBindings is a map of key bindings to functions + // KeyBindings is a map of key bindings to functions. The function provides the [Window] + // interface, so if you need more granular control over the window (e.g. [*WebviewWindow]), it's possible + // to declare the key binding directly in the specific window options or switch over + // the types that implement the [Window] interface KeyBindings map[string]func(window Window) // OnShutdown is called when the application is about to terminate. diff --git a/v3/pkg/application/webview_panel.go b/v3/pkg/application/webview_panel.go index 3a6e748da48..2aa5cf6c74e 100644 --- a/v3/pkg/application/webview_panel.go +++ b/v3/pkg/application/webview_panel.go @@ -43,7 +43,7 @@ func NewPanel(options WebviewPanelOptions) *WebviewPanel { result.setupEventMapping() - // Listen for window closing events and de + // Listen for window closing events and delete it result.OnWindowEvent(events.Common.WindowClosing, func(event *WindowEvent) { shouldClose := true if result.options.ShouldClose != nil { @@ -51,7 +51,9 @@ func NewPanel(options WebviewPanelOptions) *WebviewPanel { } if shouldClose { globalApplication.deleteWindowByID(result.id) - InvokeSync(result.impl.close) + if result.impl != nil { + InvokeSync(result.impl.close) + } } }) @@ -86,7 +88,7 @@ func (p *WebviewPanel) SetFloating(b bool) Window { } func (p *WebviewPanel) HandleKeyEvent(acceleratorString string) { - if p.impl == nil && !p.isDestroyed() { + if p.impl == nil || p.isDestroyed() { return } InvokeSync(func() { diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go index c1ef8408027..205b5b95327 100644 --- a/v3/pkg/application/webview_panel_darwin.go +++ b/v3/pkg/application/webview_panel_darwin.go @@ -6,6 +6,10 @@ package application #include "webview_window_bindings_darwin.h" +void *panelNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { + return createWindow(WindowTypePanel, id, width, height, fraudulentWebsiteWarningEnabled, frameless, enableDragAndDrop, preferences); +} + // Set NSPanel floating void panelSetFloating(void* nsPanel, bool floating) { // Set panel floating on main thread diff --git a/v3/pkg/application/webview_panel_options.go b/v3/pkg/application/webview_panel_options.go index 406b8355eab..0d618db8649 100644 --- a/v3/pkg/application/webview_panel_options.go +++ b/v3/pkg/application/webview_panel_options.go @@ -10,7 +10,10 @@ type WebviewPanelOptions struct { // Return true to allow the panel to close, or false to prevent it from closing. ShouldClose func(panel *WebviewPanel) bool - // KeyBindings is a map of key bindings to functions + // KeyBindings is a map of key bindings to functions. Other key bindings provided from + // the embedded field [WebviewWindowOptions] are still valid and the two maps are merged + // together, with the [WebviewPanelOptions] values overriding the others if they have the + // same key. KeyBindings map[string]func(panel *WebviewPanel) } diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 0b25d226b64..2e9b1f9c01c 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -1229,7 +1229,7 @@ func (w *WebviewWindow) processKeyBinding(acceleratorString string) bool { } func (w *WebviewWindow) HandleKeyEvent(acceleratorString string) { - if w.impl == nil && !w.isDestroyed() { + if w.impl == nil || w.isDestroyed() { return } InvokeSync(func() { diff --git a/v3/pkg/application/webview_window_bindings_darwin.h b/v3/pkg/application/webview_window_bindings_darwin.h index 99074823eec..869a34d9836 100644 --- a/v3/pkg/application/webview_window_bindings_darwin.h +++ b/v3/pkg/application/webview_window_bindings_darwin.h @@ -15,11 +15,14 @@ struct WebviewPreferences { bool *FullscreenEnabled; }; +typedef enum { + WindowTypeWindow, + WindowTypePanel +} WindowType; + extern void registerListener(unsigned int event); -void *windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences); -void *panelNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences); -void *windowOrPanelNew(bool isWindow, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences); +void *createWindow(WindowType windowType, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences); void printWindowStyle(void *window); void setInvisibleTitleBarHeight(void *window, unsigned int height); void windowSetTransparent(void *nsWindow); @@ -51,7 +54,7 @@ void webviewSetTransparent(void *nsWindow); void webviewSetBackgroundColour(void *nsWindow, int r, int g, int b, int alpha); void windowSetBackgroundColour(void *nsWindow, int r, int g, int b, int alpha); bool windowIsMaximised(void *nsWindow); -bool windowIsFullscreen(void *nsWindow); +bool windowIsFullScreen (void *nsWindow); bool windowIsMinimised(void *nsWindow); bool windowIsFocused(void *nsWindow); void windowFullscreen(void *nsWindow); @@ -82,8 +85,7 @@ void windowRenderHTML(void *window, const char *html); void windowInjectCSS(void *window, const char *css); void windowMinimise(void *window); void windowMaximise(void *window); -bool isFullScreen(void *window); -bool isVisible(void *window); +bool windowIsVisible(void *window); void windowSetFullScreen(void *window, bool fullscreen); void windowUnminimise(void *window); void windowUnmaximise(void *window); @@ -98,7 +100,6 @@ void windowShowMenu(void *window, void *menu, int x, int y); void windowSetFrameless(void *window, bool frameless); void startDrag(void *window); void windowPrint(void *window); -void setWindowEnabled(void *window, bool enabled); void windowSetEnabled(void *window, bool enabled); void windowFocus(void *window); bool isIgnoreMouseEvents(void *nsWindow); diff --git a/v3/pkg/application/webview_window_bindings_darwin.m b/v3/pkg/application/webview_window_bindings_darwin.m index 2aff0ee1de9..c1a279511cc 100644 --- a/v3/pkg/application/webview_window_bindings_darwin.m +++ b/v3/pkg/application/webview_window_bindings_darwin.m @@ -1,32 +1,28 @@ #include "webview_window_bindings_darwin.h" -// Create a new Window -void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { - return windowOrPanelNew(true, id, width, height, fraudulentWebsiteWarningEnabled, frameless, enableDragAndDrop, preferences); -} - -// Create a new Panel -void* panelNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { - return windowOrPanelNew(false, id, width, height, fraudulentWebsiteWarningEnabled, frameless, enableDragAndDrop, preferences); -} - -void* windowOrPanelNew(bool isWindow, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { +void *createWindow(WindowType windowType, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; if (frameless) { styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable; } WebviewWindow* webviewWindow; - if (isWindow) { - webviewWindow = [[WebviewWindow alloc] initAsWindow:NSMakeRect(0, 0, width-1, height-1) - styleMask:styleMask - backing:NSBackingStoreBuffered - defer:NO]; - } else { - webviewWindow = [[WebviewWindow alloc] initAsPanel:NSMakeRect(0, 0, width-1, height-1) - styleMask:styleMask - backing:NSBackingStoreBuffered - defer:NO]; + switch (windowType) { + case WindowTypeWindow: + webviewWindow = [[WebviewWindow alloc] initAsWindow:NSMakeRect(0, 0, width-1, height-1) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + break; + case WindowTypePanel: + webviewWindow = [[WebviewWindow alloc] initAsPanel:NSMakeRect(0, 0, width-1, height-1) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + break; + default: + NSLog(@"Invalid WindowType"); + return nil; } NSWindow *window = webviewWindow.w; @@ -365,7 +361,7 @@ bool windowIsMaximised(void* nsWindow) { return [((WebviewWindow*)nsWindow).w isZoomed]; } -bool windowIsFullscreen(void* nsWindow) { +bool windowIsFullScreen (void* nsWindow) { return [((WebviewWindow*)nsWindow).w styleMask] & NSWindowStyleMaskFullScreen; } @@ -379,7 +375,7 @@ bool windowIsFocused(void* nsWindow) { // Set Window fullscreen void windowFullscreen(void* nsWindow) { - if( windowIsFullscreen(nsWindow) ) { + if( windowIsFullScreen (nsWindow) ) { return; } dispatch_async(dispatch_get_main_queue(), ^{ @@ -387,7 +383,7 @@ void windowFullscreen(void* nsWindow) { });} void windowUnFullscreen(void* nsWindow) { - if( !windowIsFullscreen(nsWindow) ) { + if( !windowIsFullScreen (nsWindow) ) { return; } dispatch_async(dispatch_get_main_queue(), ^{ @@ -608,20 +604,14 @@ void windowMaximise(void *window) { [((WebviewWindow*)window).w zoom:nil]; } -bool isFullScreen(void *window) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; - long mask = [nsWindow styleMask]; - return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; -} - -bool isVisible(void *window) { +bool windowIsVisible(void *window) { NSWindow* nsWindow = ((WebviewWindow *)window).w; return (nsWindow.occlusionState & NSWindowOcclusionStateVisible) == NSWindowOcclusionStateVisible; } // windowSetFullScreen void windowSetFullScreen(void *window, bool fullscreen) { - if (isFullScreen(window)) { + if (windowIsFullScreen (window)) { return; } NSWindow* nsWindow = ((WebviewWindow *)window).w; @@ -755,15 +745,11 @@ void windowPrint(void *window) { #endif } -void setWindowEnabled(void *window, bool enabled) { +void windowSetEnabled(void *window, bool enabled) { NSWindow* nsWindow = ((WebviewWindow*)window).w; [nsWindow setIgnoresMouseEvents:!enabled]; } -void windowSetEnabled(void *window, bool enabled) { - // TODO: Implement -} - void windowFocus(void *window) { NSWindow* nsWindow = ((WebviewWindow *)window).w; // If the current application is not active, activate it diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index 7ec63697995..91cad1a084b 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -7,6 +7,10 @@ package application #cgo LDFLAGS: -framework Cocoa -framework WebKit #include "webview_window_bindings_darwin.h" + +void *windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { + return createWindow(WindowTypeWindow, id, width, height, fraudulentWebsiteWarningEnabled, frameless, enableDragAndDrop, preferences); +} */ import "C" import ( @@ -194,7 +198,7 @@ func (w *macosWebviewWindow) isMaximised() bool { func (w *macosWebviewWindow) isFullscreen() bool { return w.syncMainThreadReturningBool(func() bool { - return bool(C.windowIsFullscreen(w.nsWindow)) + return bool(C.windowIsFullScreen(w.nsWindow)) }) } @@ -203,7 +207,7 @@ func (w *macosWebviewWindow) isNormal() bool { } func (w *macosWebviewWindow) isVisible() bool { - return bool(C.isVisible(w.nsWindow)) + return bool(C.windowIsVisible(w.nsWindow)) } func (w *macosWebviewWindow) syncMainThreadReturningBool(fn func() bool) bool { diff --git a/v3/pkg/application/webview_window_darwin.m b/v3/pkg/application/webview_window_darwin.m index e94ea08c0d1..01edcdfc7c3 100644 --- a/v3/pkg/application/webview_window_darwin.m +++ b/v3/pkg/application/webview_window_darwin.m @@ -9,34 +9,29 @@ extern bool hasListeners(unsigned int); @implementation WebviewWindow -- (WebviewWindow *) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; -{ +- (WebviewWindow *) initAsWindow:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation { self = [super init]; self.w = [[NSWindow alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; - [self.w setAlphaValue:1.0]; - [self.w setBackgroundColor:[NSColor clearColor]]; - [self.w setOpaque:NO]; - [self.w setMovableByWindowBackground:YES]; - - self.responder = [[WebviewResponder alloc] initAttachToWindow:self.w]; + [self commonInitialization]; return self; } -- (WebviewWindow *) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation; -{ +- (WebviewWindow *) initAsPanel:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation { self = [super init]; - + self.w = (NSWindow *) [[NSPanel alloc] initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + [self commonInitialization]; + return self; +} +- (void) commonInitialization { [self.w setAlphaValue:1.0]; [self.w setBackgroundColor:[NSColor clearColor]]; [self.w setOpaque:NO]; [self.w setMovableByWindowBackground:YES]; self.responder = [[WebviewResponder alloc] initAttachToWindow:self.w]; - - return self; } - (void) dealloc { // Remove the script handler, otherwise WebviewWindowDelegate won't get deallocated From c1427527d80d9e0d83e1816e1f6770f66a2e8137 Mon Sep 17 00:00:00 2001 From: "Alessio Pareto (MacBook Pro di Pare)" Date: Sat, 21 Sep 2024 15:26:13 +0200 Subject: [PATCH 09/20] Reduced code duplication and magic numbers, improved code style consistency --- v3/pkg/application/application.go | 37 +- v3/pkg/application/webview_panel.go | 46 +-- v3/pkg/application/webview_panel_darwin.go | 14 +- v3/pkg/application/webview_panel_options.go | 2 +- v3/pkg/application/webview_responder_darwin.h | 1 + v3/pkg/application/webview_responder_darwin.m | 152 +++---- v3/pkg/application/webview_window.go | 6 +- .../webview_window_bindings_darwin.h | 110 ++--- .../webview_window_bindings_darwin.m | 380 +++++++++--------- 9 files changed, 348 insertions(+), 400 deletions(-) diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index 9cc60cb4edb..765d0408ec6 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -527,38 +527,31 @@ func (a *App) error(message string, args ...any) { func (a *App) NewWebviewWindowWithOptions(windowOptions WebviewWindowOptions) *WebviewWindow { newWindow := NewWindow(windowOptions) - id := newWindow.ID() - - a.windowsLock.Lock() - a.windows[id] = newWindow - a.windowsLock.Unlock() - - // Call hooks - for _, hook := range a.windowCreatedCallbacks { - hook(newWindow) - } - - a.runOrDeferToAppRun(newWindow) + a.addNewWindow(newWindow) return newWindow } func (a *App) NewWebviewPanelWithOptions(panelOptions WebviewPanelOptions) *WebviewPanel { newPanel := NewPanel(panelOptions) - id := newPanel.ID() + a.addNewWindow(newPanel) - a.windowsLock.Lock() - a.windows[id] = newPanel - a.windowsLock.Unlock() + return newPanel +} - // Call hooks - for _, hook := range a.windowCreatedCallbacks { - hook(newPanel) - } +func (a *App) addNewWindow(newWindow Window) { + id := newWindow.ID() - a.runOrDeferToAppRun(newPanel) + a.windowsLock.Lock() + a.windows[id] = newWindow + a.windowsLock.Unlock() - return newPanel + // Call hooks + for _, hook := range a.windowCreatedCallbacks { + hook(newWindow) + } + + a.runOrDeferToAppRun(newWindow) } func (a *App) NewSystemTray() *SystemTray { diff --git a/v3/pkg/application/webview_panel.go b/v3/pkg/application/webview_panel.go index 2aa5cf6c74e..7779c351681 100644 --- a/v3/pkg/application/webview_panel.go +++ b/v3/pkg/application/webview_panel.go @@ -1,7 +1,5 @@ package application -import "github.com/wailsapp/wails/v3/pkg/events" - type webviewPanelImpl interface { webviewWindowImpl getWebviewWindowImpl() webviewWindowImpl @@ -9,7 +7,7 @@ type webviewPanelImpl interface { } type WebviewPanel struct { - WebviewWindow + *WebviewWindow options WebviewPanelOptions impl webviewPanelImpl @@ -19,45 +17,15 @@ type WebviewPanel struct { // NewPanel creates a new panel with the given options func NewPanel(options WebviewPanelOptions) *WebviewPanel { - if options.Width == 0 { - options.Width = 800 - } - if options.Height == 0 { - options.Height = 600 - } - if options.URL == "" { - options.URL = "/" - } + window := NewWindow(options.WebviewWindowOptions) + options.WebviewWindowOptions = window.options result := &WebviewPanel{ - WebviewWindow: WebviewWindow{ - id: getWindowID(), - options: options.WebviewWindowOptions, - eventListeners: make(map[uint][]*WindowEventListener), - contextMenus: make(map[string]*Menu), - eventHooks: make(map[uint][]*WindowEventListener), - menuBindings: make(map[string]*MenuItem), - }, - options: options, + WebviewWindow: window, + options: options, } - result.setupEventMapping() - - // Listen for window closing events and delete it - result.OnWindowEvent(events.Common.WindowClosing, func(event *WindowEvent) { - shouldClose := true - if result.options.ShouldClose != nil { - shouldClose = result.options.ShouldClose(result) - } - if shouldClose { - globalApplication.deleteWindowByID(result.id) - if result.impl != nil { - InvokeSync(result.impl.close) - } - } - }) - - // Process keybindings + // Process keybindings specific to the WebviewPanel if result.options.KeyBindings != nil || result.options.WebviewWindowOptions.KeyBindings != nil { result.keyBindings = processKeyBindingOptionsForPanel(result.options.KeyBindings, result.options.WebviewWindowOptions.KeyBindings) } @@ -118,5 +86,5 @@ func (p *WebviewPanel) processKeyBinding(acceleratorString string) bool { } } - return globalApplication.processKeyBinding(acceleratorString, &p.WebviewWindow) + return globalApplication.processKeyBinding(acceleratorString, p.WebviewWindow) } diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go index 205b5b95327..dc04db27b32 100644 --- a/v3/pkg/application/webview_panel_darwin.go +++ b/v3/pkg/application/webview_panel_darwin.go @@ -26,13 +26,10 @@ void panelSetFloating(void* nsPanel, bool floating) { import "C" import ( "unsafe" - - "github.com/wailsapp/wails/v3/internal/runtime" - "github.com/wailsapp/wails/v3/pkg/events" ) type macosWebviewPanel struct { - macosWebviewWindow + *macosWebviewWindow nsPanel unsafe.Pointer parent *WebviewPanel @@ -40,19 +37,14 @@ type macosWebviewPanel struct { func newPanelImpl(parent *WebviewPanel) *macosWebviewPanel { result := &macosWebviewPanel{ - macosWebviewWindow: macosWebviewWindow{ - parent: &parent.WebviewWindow, - }, + macosWebviewWindow: newWindowImpl(parent.WebviewWindow), parent: parent, } - result.parent.RegisterHook(events.Mac.WebViewDidFinishNavigation, func(event *WindowEvent) { - result.execJS(runtime.Core()) - }) return result } func (p *macosWebviewPanel) getWebviewWindowImpl() webviewWindowImpl { - return &p.macosWebviewWindow + return p.macosWebviewWindow } func (p *macosWebviewPanel) run() { diff --git a/v3/pkg/application/webview_panel_options.go b/v3/pkg/application/webview_panel_options.go index 0d618db8649..23ce1528c6c 100644 --- a/v3/pkg/application/webview_panel_options.go +++ b/v3/pkg/application/webview_panel_options.go @@ -31,7 +31,7 @@ func processKeyBindingOptionsForPanel(keyBindings map[string]func(panel *Webview continue } result[acc.String()] = func(panel *WebviewPanel) { - callback(&panel.WebviewWindow) + callback(panel.WebviewWindow) } globalApplication.debug("Added Keybinding", "accelerator", acc.String()) } diff --git a/v3/pkg/application/webview_responder_darwin.h b/v3/pkg/application/webview_responder_darwin.h index fb0c9179b7b..19cab3e2cd4 100644 --- a/v3/pkg/application/webview_responder_darwin.h +++ b/v3/pkg/application/webview_responder_darwin.h @@ -2,6 +2,7 @@ #define WEBVIEW_RESPONDER_DARWIN #import +#import @interface WebviewResponder : NSResponder @property(assign) NSWindow *w; diff --git a/v3/pkg/application/webview_responder_darwin.m b/v3/pkg/application/webview_responder_darwin.m index fe42508b7f2..f5b861766d4 100644 --- a/v3/pkg/application/webview_responder_darwin.m +++ b/v3/pkg/application/webview_responder_darwin.m @@ -44,86 +44,86 @@ - (NSString *)keyStringFromEvent:(NSEvent *)event { // Get the pressed key switch ([event keyCode]) { // Function keys - case 122: return @"f1"; - case 120: return @"f2"; - case 99: return @"f3"; - case 118: return @"f4"; - case 96: return @"f5"; - case 97: return @"f6"; - case 98: return @"f7"; - case 100: return @"f8"; - case 101: return @"f9"; - case 109: return @"f10"; - case 103: return @"f11"; - case 111: return @"f12"; - case 105: return @"f13"; - case 107: return @"f14"; - case 113: return @"f15"; - case 106: return @"f16"; - case 64: return @"f17"; - case 79: return @"f18"; - case 80: return @"f19"; - case 90: return @"f20"; + case kVK_F1: return @"f1"; + case kVK_F2: return @"f2"; + case kVK_F3: return @"f3"; + case kVK_F4: return @"f4"; + case kVK_F5: return @"f5"; + case kVK_F6: return @"f6"; + case kVK_F7: return @"f7"; + case kVK_F8: return @"f8"; + case kVK_F9: return @"f9"; + case kVK_F10: return @"f10"; + case kVK_F11: return @"f11"; + case kVK_F12: return @"f12"; + case kVK_F13: return @"f13"; + case kVK_F14: return @"f14"; + case kVK_F15: return @"f15"; + case kVK_F16: return @"f16"; + case kVK_F17: return @"f17"; + case kVK_F18: return @"f18"; + case kVK_F19: return @"f19"; + case kVK_F20: return @"f20"; // Letter keys - case 0: return @"a"; - case 11: return @"b"; - case 8: return @"c"; - case 2: return @"d"; - case 14: return @"e"; - case 3: return @"f"; - case 5: return @"g"; - case 4: return @"h"; - case 34: return @"i"; - case 38: return @"j"; - case 40: return @"k"; - case 37: return @"l"; - case 46: return @"m"; - case 45: return @"n"; - case 31: return @"o"; - case 35: return @"p"; - case 12: return @"q"; - case 15: return @"r"; - case 1: return @"s"; - case 17: return @"t"; - case 32: return @"u"; - case 9: return @"v"; - case 13: return @"w"; - case 7: return @"x"; - case 16: return @"y"; - case 6: return @"z"; + case kVK_ANSI_A: return @"a"; + case kVK_ANSI_B: return @"b"; + case kVK_ANSI_C: return @"c"; + case kVK_ANSI_D: return @"d"; + case kVK_ANSI_E: return @"e"; + case kVK_ANSI_F: return @"f"; + case kVK_ANSI_G: return @"g"; + case kVK_ANSI_H: return @"h"; + case kVK_ANSI_I: return @"i"; + case kVK_ANSI_J: return @"j"; + case kVK_ANSI_K: return @"k"; + case kVK_ANSI_L: return @"l"; + case kVK_ANSI_M: return @"m"; + case kVK_ANSI_N: return @"n"; + case kVK_ANSI_O: return @"o"; + case kVK_ANSI_P: return @"p"; + case kVK_ANSI_Q: return @"q"; + case kVK_ANSI_R: return @"r"; + case kVK_ANSI_S: return @"s"; + case kVK_ANSI_T: return @"t"; + case kVK_ANSI_U: return @"u"; + case kVK_ANSI_V: return @"v"; + case kVK_ANSI_W: return @"w"; + case kVK_ANSI_X: return @"x"; + case kVK_ANSI_Y: return @"y"; + case kVK_ANSI_Z: return @"z"; // Number keys - case 29: return @"0"; - case 18: return @"1"; - case 19: return @"2"; - case 20: return @"3"; - case 21: return @"4"; - case 23: return @"5"; - case 22: return @"6"; - case 26: return @"7"; - case 28: return @"8"; - case 25: return @"9"; + case kVK_ANSI_0: return @"0"; + case kVK_ANSI_1: return @"1"; + case kVK_ANSI_2: return @"2"; + case kVK_ANSI_3: return @"3"; + case kVK_ANSI_4: return @"4"; + case kVK_ANSI_5: return @"5"; + case kVK_ANSI_6: return @"6"; + case kVK_ANSI_7: return @"7"; + case kVK_ANSI_8: return @"8"; + case kVK_ANSI_9: return @"9"; // Other special keys - case 51: return @"delete"; - case 117: return @"forward delete"; - case 123: return @"left"; - case 124: return @"right"; - case 126: return @"up"; - case 125: return @"down"; - case 48: return @"tab"; - case 53: return @"escape"; - case 49: return @"space"; + case kVK_Delete: return @"delete"; + case kVK_ForwardDelete: return @"forward delete"; + case kVK_LeftArrow: return @"left"; + case kVK_RightArrow: return @"right"; + case kVK_UpArrow: return @"up"; + case kVK_DownArrow: return @"down"; + case kVK_Tab: return @"tab"; + case kVK_Escape: return @"escape"; + case kVK_Space: return @"space"; // Punctuation and other keys (for a standard US layout) - case 33: return @"["; - case 30: return @"]"; - case 43: return @","; - case 27: return @"-"; - case 39: return @"'"; - case 44: return @"/"; - case 47: return @"."; - case 41: return @";"; - case 24: return @"="; - case 50: return @"`"; - case 42: return @"\\"; + case kVK_ANSI_LeftBracket: return @"["; + case kVK_ANSI_RightBracket: return @"]"; + case kVK_ANSI_Comma: return @","; + case kVK_ANSI_Minus: return @"-"; + case kVK_ANSI_Quote: return @"'"; + case kVK_ANSI_Slash: return @"/"; + case kVK_ANSI_Period: return @"."; + case kVK_ANSI_Semicolon: return @";"; + case kVK_ANSI_Equal: return @"="; + case kVK_ANSI_Grave: return @"`"; + case kVK_ANSI_Backslash: return @"\\"; default: return [self specialKeyStringFromEvent:event]; } } diff --git a/v3/pkg/application/webview_window.go b/v3/pkg/application/webview_window.go index 2e9b1f9c01c..4049cc0b117 100644 --- a/v3/pkg/application/webview_window.go +++ b/v3/pkg/application/webview_window.go @@ -218,6 +218,8 @@ func (w *WebviewWindow) setupEventMapping() { // NewWindow creates a new window with the given options func NewWindow(options WebviewWindowOptions) *WebviewWindow { + id := getWindowID() + if options.Width == 0 { options.Width = 800 } @@ -229,11 +231,11 @@ func NewWindow(options WebviewWindowOptions) *WebviewWindow { } if options.Name == "" { - options.Name = fmt.Sprintf("window-%d", getWindowID()) + options.Name = fmt.Sprintf("Window %d", id) } result := &WebviewWindow{ - id: getWindowID(), + id: id, options: options, eventListeners: make(map[uint][]*WindowEventListener), contextMenus: make(map[string]*Menu), diff --git a/v3/pkg/application/webview_window_bindings_darwin.h b/v3/pkg/application/webview_window_bindings_darwin.h index 869a34d9836..529ca7eca75 100644 --- a/v3/pkg/application/webview_window_bindings_darwin.h +++ b/v3/pkg/application/webview_window_bindings_darwin.h @@ -25,60 +25,60 @@ extern void registerListener(unsigned int event); void *createWindow(WindowType windowType, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences); void printWindowStyle(void *window); void setInvisibleTitleBarHeight(void *window, unsigned int height); -void windowSetTransparent(void *nsWindow); -void windowSetInvisibleTitleBar(void *nsWindow, unsigned int height); -void windowSetTitle(void *nsWindow, char *title); -void windowSetSize(void *nsWindow, int width, int height); -void windowSetAlwaysOnTop(void *nsWindow, bool alwaysOnTop); -void setNormalWindowLevel(void *nsWindow); -void setFloatingWindowLevel(void *nsWindow); -void setPopUpMenuWindowLevel(void *nsWindow); -void setMainMenuWindowLevel(void *nsWindow); -void setStatusWindowLevel(void *nsWindow); -void setModalPanelWindowLevel(void *nsWindow); -void setScreenSaverWindowLevel(void *nsWindow); -void setTornOffMenuWindowLevel(void *nsWindow); -void navigationLoadURL(void *nsWindow, char *url); -void windowSetResizable(void *nsWindow, bool resizable); -void windowSetMinSize(void *nsWindow, int width, int height); -void windowSetMaxSize(void *nsWindow, int width, int height); -void windowZoomReset(void *nsWindow); -void windowZoomSet(void *nsWindow, double zoom); -float windowZoomGet(void *nsWindow); -void windowZoomIn(void *nsWindow); -void windowZoomOut(void *nsWindow); -void windowSetRelativePosition(void *nsWindow, int x, int y); -void windowExecJS(void *nsWindow, const char *js); -void windowSetTranslucent(void *nsWindow); -void webviewSetTransparent(void *nsWindow); -void webviewSetBackgroundColour(void *nsWindow, int r, int g, int b, int alpha); -void windowSetBackgroundColour(void *nsWindow, int r, int g, int b, int alpha); -bool windowIsMaximised(void *nsWindow); -bool windowIsFullScreen (void *nsWindow); -bool windowIsMinimised(void *nsWindow); -bool windowIsFocused(void *nsWindow); -void windowFullscreen(void *nsWindow); -void windowUnFullscreen(void *nsWindow); -void windowRestore(void *nsWindow); -void setFullscreenButtonEnabled(void *nsWindow, bool enabled); -void windowSetTitleBarAppearsTransparent(void *nsWindow, bool transparent); -void windowSetFullSizeContent(void *nsWindow, bool fullSize); -void windowSetHideTitleBar(void *nsWindow, bool hideTitlebar); -void windowSetHideTitle(void *nsWindow, bool hideTitle); -void windowSetUseToolbar(void *nsWindow, bool useToolbar); -void windowSetToolbarStyle(void *nsWindow, int style); -void windowSetHideToolbarSeparator(void *nsWindow, bool hideSeparator); +void windowSetTransparent(void *window); +void windowSetInvisibleTitleBar(void *window, unsigned int height); +void windowSetTitle(void *window, char *title); +void windowSetSize(void *window, int width, int height); +void windowSetAlwaysOnTop(void *window, bool alwaysOnTop); +void setNormalWindowLevel(void *window); +void setFloatingWindowLevel(void *window); +void setPopUpMenuWindowLevel(void *window); +void setMainMenuWindowLevel(void *window); +void setStatusWindowLevel(void *window); +void setModalPanelWindowLevel(void *window); +void setScreenSaverWindowLevel(void *window); +void setTornOffMenuWindowLevel(void *window); +void navigationLoadURL(void *window, char *url); +void windowSetResizable(void *window, bool resizable); +void windowSetMinSize(void *window, int width, int height); +void windowSetMaxSize(void *window, int width, int height); +void windowZoomReset(void *window); +void windowZoomSet(void *window, double zoom); +float windowZoomGet(void *window); +void windowZoomIn(void *window); +void windowZoomOut(void *window); +void windowSetRelativePosition(void *window, int x, int y); +void windowExecJS(void *window, const char *js); +void windowSetTranslucent(void *window); +void webviewSetTransparent(void *window); +void webviewSetBackgroundColour(void *window, int r, int g, int b, int alpha); +void windowSetBackgroundColour(void *window, int r, int g, int b, int alpha); +bool windowIsMaximised(void *window); +bool windowIsFullScreen (void *window); +bool windowIsMinimised(void *window); +bool windowIsFocused(void *window); +void windowFullscreen(void *window); +void windowUnFullscreen(void *window); +void windowRestore(void *window); +void setFullscreenButtonEnabled(void *window, bool enabled); +void windowSetTitleBarAppearsTransparent(void *window, bool transparent); +void windowSetFullSizeContent(void *window, bool fullSize); +void windowSetHideTitleBar(void *window, bool hideTitlebar); +void windowSetHideTitle(void *window, bool hideTitle); +void windowSetUseToolbar(void *window, bool useToolbar); +void windowSetToolbarStyle(void *window, int style); +void windowSetHideToolbarSeparator(void *window, bool hideSeparator); void windowSetShowToolbarWhenFullscreen(void *window, bool setting); -void windowSetAppearanceTypeByName(void *nsWindow, const char *appearanceName); -void windowCenter(void *nsWindow); -void windowGetSize(void *nsWindow, int *width, int *height); -int windowGetWidth(void *nsWindow); -int windowGetHeight(void *nsWindow); -void windowGetRelativePosition(void *nsWindow, int *x, int *y); -void windowGetPosition(void *nsWindow, int *x, int *y); -void windowSetPosition(void *nsWindow, int x, int y); -void windowDestroy(void *nsWindow); -void windowSetShadow(void *nsWindow, bool hasShadow); +void windowSetAppearanceTypeByName(void *window, const char *appearanceName); +void windowCenter(void *window); +void windowGetSize(void *window, int *width, int *height); +int windowGetWidth(void *window); +int windowGetHeight(void *window); +void windowGetRelativePosition(void *window, int *x, int *y); +void windowGetPosition(void *window, int *x, int *y); +void windowSetPosition(void *window, int x, int y); +void windowDestroy(void *window); +void windowSetShadow(void *window, bool hasShadow); void windowClose(void *window); void windowZoom(void *window); void windowRenderHTML(void *window, const char *html); @@ -102,7 +102,7 @@ void startDrag(void *window); void windowPrint(void *window); void windowSetEnabled(void *window, bool enabled); void windowFocus(void *window); -bool isIgnoreMouseEvents(void *nsWindow); -void setIgnoreMouseEvents(void *nsWindow, bool ignore); +bool isIgnoreMouseEvents(void *window); +void setIgnoreMouseEvents(void *window, bool ignore); #endif // WEBVIEW_WINDOW_BINDINGS_DARWIN \ No newline at end of file diff --git a/v3/pkg/application/webview_window_bindings_darwin.m b/v3/pkg/application/webview_window_bindings_darwin.m index c1a279511cc..7cfc4579d44 100644 --- a/v3/pkg/application/webview_window_bindings_darwin.m +++ b/v3/pkg/application/webview_window_bindings_darwin.m @@ -2,12 +2,12 @@ void *createWindow(WindowType windowType, unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop, struct WebviewPreferences preferences) { NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - if (frameless) { + if( frameless ) { styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable; } WebviewWindow* webviewWindow; - switch (windowType) { + switch( windowType ) { case WindowTypeWindow: webviewWindow = [[WebviewWindow alloc] initAsWindow:NSMakeRect(0, 0, width-1, height-1) styleMask:styleMask @@ -52,24 +52,24 @@ [config autorelease]; // Set preferences - if (preferences.TabFocusesLinks != NULL) { + if( preferences.TabFocusesLinks != NULL ) { config.preferences.tabFocusesLinks = *preferences.TabFocusesLinks; } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 110300 - if (@available(macOS 11.3, *)) { - if (preferences.TextInteractionEnabled != NULL) { + if( @available(macOS 11.3, *) ) { + if( preferences.TextInteractionEnabled != NULL ) { config.preferences.textInteractionEnabled = *preferences.TextInteractionEnabled; } } #endif #if MAC_OS_X_VERSION_MAX_ALLOWED >= 120300 - if (@available(macOS 12.3, *)) { - if (preferences.FullscreenEnabled != NULL) { - config.preferences.elementFullscreenEnabled = *preferences.FullscreenEnabled; - } - } + if( @available(macOS 12.3, *) ) { + if( preferences.FullscreenEnabled != NULL ) { + config.preferences.elementFullscreenEnabled = *preferences.FullscreenEnabled; + } + } #endif config.suppressesIncrementalRendering = true; @@ -77,8 +77,8 @@ [config setURLSchemeHandler:delegate forURLScheme:@"wails"]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 - if (@available(macOS 10.15, *)) { - config.preferences.fraudulentWebsiteWarningEnabled = fraudulentWebsiteWarningEnabled; + if( @available(macOS 10.15, *) ) { + config.preferences.fraudulentWebsiteWarningEnabled = fraudulentWebsiteWarningEnabled; } #endif @@ -114,50 +114,42 @@ } void printWindowStyle(void *window) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; NSWindowStyleMask styleMask = [nsWindow styleMask]; // Get delegate WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[nsWindow delegate]; printf("Window %d style mask: ", windowDelegate.windowId); - if (styleMask & NSWindowStyleMaskTitled) - { + if( styleMask & NSWindowStyleMaskTitled) { printf("NSWindowStyleMaskTitled "); } - if (styleMask & NSWindowStyleMaskClosable) - { + if( styleMask & NSWindowStyleMaskClosable) { printf("NSWindowStyleMaskClosable "); } - if (styleMask & NSWindowStyleMaskMiniaturizable) - { + if( styleMask & NSWindowStyleMaskMiniaturizable) { printf("NSWindowStyleMaskMiniaturizable "); } - if (styleMask & NSWindowStyleMaskResizable) - { + if( styleMask & NSWindowStyleMaskResizable) { printf("NSWindowStyleMaskResizable "); } - if (styleMask & NSWindowStyleMaskFullSizeContentView) - { + if( styleMask & NSWindowStyleMaskFullSizeContentView) { printf("NSWindowStyleMaskFullSizeContentView "); } - if (styleMask & NSWindowStyleMaskNonactivatingPanel) - { + if( styleMask & NSWindowStyleMaskNonactivatingPanel) { printf("NSWindowStyleMaskNonactivatingPanel "); } - if (styleMask & NSWindowStyleMaskFullScreen) - { + if( styleMask & NSWindowStyleMaskFullScreen) { printf("NSWindowStyleMaskFullScreen "); } - if (styleMask & NSWindowStyleMaskBorderless) - { + if( styleMask & NSWindowStyleMaskBorderless) { printf("MSWindowStyleMaskBorderless "); } @@ -167,7 +159,7 @@ void printWindowStyle(void *window) { // setInvisibleTitleBarHeight sets the invisible title bar height void setInvisibleTitleBarHeight(void* window, unsigned int height) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; // Get delegate WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; // Set height @@ -175,124 +167,123 @@ void setInvisibleTitleBarHeight(void* window, unsigned int height) { } // Make NSWindow transparent -void windowSetTransparent(void* nsWindow) { - [((WebviewWindow*)nsWindow).w setOpaque:NO]; - [((WebviewWindow*)nsWindow).w setBackgroundColor:[NSColor clearColor]]; +void windowSetTransparent(void* window) { + [((WebviewWindow*)window).w setOpaque:NO]; + [((WebviewWindow*)window).w setBackgroundColor:[NSColor clearColor]]; } -void windowSetInvisibleTitleBar(void* nsWindow, unsigned int height) { - NSWindow* window = ((WebviewWindow*)nsWindow).w; - WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[window delegate]; +void windowSetInvisibleTitleBar(void* window, unsigned int height) { + NSWindow* nsWindow = ((WebviewWindow*)window).w; + WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; delegate.invisibleTitleBarHeight = height; } - // Set the title of the NSWindow -void windowSetTitle(void* nsWindow, char* title) { +void windowSetTitle(void* window, char* title) { NSString* nsTitle = [NSString stringWithUTF8String:title]; - [((WebviewWindow*)nsWindow).w setTitle:nsTitle]; + [((WebviewWindow*)window).w setTitle:nsTitle]; free(title); } // Set the size of the NSWindow -void windowSetSize(void* nsWindow, int width, int height) { +void windowSetSize(void* window, int width, int height) { // Set window size on main thread - NSWindow* window = ((WebviewWindow*)nsWindow).w; - NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; - [window setContentSize:contentSize]; - [window setFrame:NSMakeRect(window.frame.origin.x, window.frame.origin.y, width, height) display:YES animate:YES]; + NSWindow* nsWindow = ((WebviewWindow*)window).w; + NSSize contentSize = [nsWindow contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; + [nsWindow setContentSize:contentSize]; + [nsWindow setFrame:NSMakeRect(nsWindow.frame.origin.x, nsWindow.frame.origin.y, width, height) display:YES animate:YES]; } // Set NSWindow always on top -void windowSetAlwaysOnTop(void* nsWindow, bool alwaysOnTop) { +void windowSetAlwaysOnTop(void* window, bool alwaysOnTop) { // Set window always on top on main thread - [((WebviewWindow*)nsWindow).w setLevel:alwaysOnTop ? NSFloatingWindowLevel : NSNormalWindowLevel]; + [((WebviewWindow*)window).w setLevel:alwaysOnTop ? NSFloatingWindowLevel : NSNormalWindowLevel]; } -void setNormalWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSNormalWindowLevel]; } -void setFloatingWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSFloatingWindowLevel];} -void setPopUpMenuWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSPopUpMenuWindowLevel]; } -void setMainMenuWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSMainMenuWindowLevel]; } -void setStatusWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSStatusWindowLevel]; } -void setModalPanelWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSModalPanelWindowLevel]; } -void setScreenSaverWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSScreenSaverWindowLevel]; } -void setTornOffMenuWindowLevel(void* nsWindow) { [((WebviewWindow*)nsWindow).w setLevel:NSTornOffMenuWindowLevel]; } +void setNormalWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSNormalWindowLevel]; } +void setFloatingWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSFloatingWindowLevel]; } +void setPopUpMenuWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSPopUpMenuWindowLevel]; } +void setMainMenuWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSMainMenuWindowLevel]; } +void setStatusWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSStatusWindowLevel]; } +void setModalPanelWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSModalPanelWindowLevel]; } +void setScreenSaverWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSScreenSaverWindowLevel]; } +void setTornOffMenuWindowLevel(void* window) { [((WebviewWindow*)window).w setLevel:NSTornOffMenuWindowLevel]; } // Load URL in NSWindow -void navigationLoadURL(void* nsWindow, char* url) { +void navigationLoadURL(void* window, char* url) { // Load URL on main thread NSURL* nsURL = [NSURL URLWithString:[NSString stringWithUTF8String:url]]; NSURLRequest* request = [NSURLRequest requestWithURL:nsURL]; - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; + WebviewWindow *webviewWindow = (WebviewWindow*)window; [webviewWindow.webView loadRequest:request]; free(url); } // Set NSWindow resizable -void windowSetResizable(void* nsWindow, bool resizable) { +void windowSetResizable(void* window, bool resizable) { // Set window resizable on main thread - NSWindow* window = ((WebviewWindow*)nsWindow).w; - if (resizable) { - NSWindowStyleMask styleMask = [window styleMask] | NSWindowStyleMaskResizable; - [window setStyleMask:styleMask]; + NSWindow* nsWindow = ((WebviewWindow*)window).w; + if( resizable ) { + NSWindowStyleMask styleMask = [nsWindow styleMask] | NSWindowStyleMaskResizable; + [nsWindow setStyleMask:styleMask]; } else { - NSWindowStyleMask styleMask = [window styleMask] & ~NSWindowStyleMaskResizable; - [window setStyleMask:styleMask]; + NSWindowStyleMask styleMask = [nsWindow styleMask] & ~NSWindowStyleMaskResizable; + [nsWindow setStyleMask:styleMask]; } } // Set NSWindow min size -void windowSetMinSize(void* nsWindow, int width, int height) { +void windowSetMinSize(void* window, int width, int height) { // Set window min size on main thread - NSWindow* window = ((WebviewWindow*)nsWindow).w; - NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; - [window setContentMinSize:contentSize]; + NSWindow* nsWindow = ((WebviewWindow*)window).w; + NSSize contentSize = [nsWindow contentRectForFrameRect:NSMakeRect(0, 0, width, height)].size; + [nsWindow setContentMinSize:contentSize]; NSSize size = { width, height }; - [window setMinSize:size]; + [nsWindow setMinSize:size]; } // Set NSWindow max size -void windowSetMaxSize(void* nsWindow, int width, int height) { +void windowSetMaxSize(void* window, int width, int height) { // Set window max size on main thread NSSize size = { FLT_MAX, FLT_MAX }; size.width = width > 0 ? width : FLT_MAX; size.height = height > 0 ? height : FLT_MAX; - NSWindow* window = ((WebviewWindow*)nsWindow).w; - NSSize contentSize = [window contentRectForFrameRect:NSMakeRect(0, 0, size.width, size.height)].size; - [window setContentMaxSize:contentSize]; - [window setMaxSize:size]; + NSWindow* nsWindow = ((WebviewWindow*)window).w; + NSSize contentSize = [nsWindow contentRectForFrameRect:NSMakeRect(0, 0, size.width, size.height)].size; + [nsWindow setContentMaxSize:contentSize]; + [nsWindow setMaxSize:size]; } // windowZoomReset -void windowZoomReset(void* nsWindow) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void windowZoomReset(void* window) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; [webviewWindow.webView setMagnification:1.0]; } // windowZoomSet -void windowZoomSet(void* nsWindow, double zoom) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void windowZoomSet(void* window, double zoom) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; // Reset zoom [webviewWindow.webView setMagnification:zoom]; } // windowZoomGet -float windowZoomGet(void* nsWindow) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +float windowZoomGet(void* window) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; // Get zoom return [webviewWindow.webView magnification]; } // windowZoomIn -void windowZoomIn(void* nsWindow) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void windowZoomIn(void* window) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; // Zoom in [webviewWindow.webView setMagnification:webviewWindow.webView.magnification + 0.05]; } // windowZoomOut -void windowZoomOut(void* nsWindow) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void windowZoomOut(void* window) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; // Zoom out if( webviewWindow.webView.magnification > 1.05 ) { [webviewWindow.webView setMagnification:webviewWindow.webView.magnification - 0.05]; @@ -302,33 +293,33 @@ void windowZoomOut(void* nsWindow) { } // set the window position relative to the screen -void windowSetRelativePosition(void* nsWindow, int x, int y) { - NSWindow* window = ((WebviewWindow*)nsWindow).w; - NSScreen* screen = [window screen]; +void windowSetRelativePosition(void* window, int x, int y) { + NSWindow* nsWindow = ((WebviewWindow*)window).w; + NSScreen* screen = [nsWindow screen]; if( screen == NULL ) { screen = [NSScreen mainScreen]; } - NSRect windowFrame = [window frame]; + NSRect windowFrame = [nsWindow frame]; NSRect screenFrame = [screen frame]; windowFrame.origin.x = screenFrame.origin.x + (float)x; windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y; - [window setFrame:windowFrame display:TRUE animate:FALSE]; + [nsWindow setFrame:windowFrame display:TRUE animate:FALSE]; } // Execute JS in NSWindow -void windowExecJS(void* nsWindow, const char* js) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void windowExecJS(void* window, const char* js) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; [webviewWindow.webView evaluateJavaScript:[NSString stringWithUTF8String:js] completionHandler:nil]; free((void*)js); } // Make NSWindow backdrop translucent -void windowSetTranslucent(void* nsWindow) { +void windowSetTranslucent(void* window) { // Get window - NSWindow* window = ((WebviewWindow*)nsWindow).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; - id contentView = [window contentView]; + id contentView = [nsWindow contentView]; NSVisualEffectView *effectView = [NSVisualEffectView alloc]; NSRect bounds = [contentView bounds]; [effectView initWithFrame:bounds]; @@ -339,146 +330,150 @@ void windowSetTranslucent(void* nsWindow) { } // Make webview background transparent -void webviewSetTransparent(void* nsWindow) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void webviewSetTransparent(void* window) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; // Set webview background transparent [webviewWindow.webView setValue:@NO forKey:@"drawsBackground"]; } // Set webview background colour -void webviewSetBackgroundColour(void* nsWindow, int r, int g, int b, int alpha) { - WebviewWindow *webviewWindow = (WebviewWindow*)nsWindow; +void webviewSetBackgroundColour(void* window, int r, int g, int b, int alpha) { + WebviewWindow *webviewWindow = (WebviewWindow*)window; // Set webview background color [webviewWindow.webView setValue:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0] forKey:@"backgroundColor"]; } // Set the window background colour -void windowSetBackgroundColour(void* nsWindow, int r, int g, int b, int alpha) { - [((WebviewWindow*)nsWindow).w setBackgroundColor:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0]]; +void windowSetBackgroundColour(void* window, int r, int g, int b, int alpha) { + [((WebviewWindow*)window).w setBackgroundColor:[NSColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:alpha/255.0]]; } -bool windowIsMaximised(void* nsWindow) { - return [((WebviewWindow*)nsWindow).w isZoomed]; +bool windowIsMaximised(void* window) { + return [((WebviewWindow*)window).w isZoomed]; } -bool windowIsFullScreen (void* nsWindow) { - return [((WebviewWindow*)nsWindow).w styleMask] & NSWindowStyleMaskFullScreen; +bool windowIsFullScreen (void* window) { + return [((WebviewWindow*)window).w styleMask] & NSWindowStyleMaskFullScreen; } -bool windowIsMinimised(void* nsWindow) { - return [((WebviewWindow*)nsWindow).w isMiniaturized]; +bool windowIsMinimised(void* window) { + return [((WebviewWindow*)window).w isMiniaturized]; } -bool windowIsFocused(void* nsWindow) { - return [((WebviewWindow*)nsWindow).w isKeyWindow]; +bool windowIsFocused(void* window) { + return [((WebviewWindow*)window).w isKeyWindow]; } // Set Window fullscreen -void windowFullscreen(void* nsWindow) { - if( windowIsFullScreen (nsWindow) ) { +void windowFullscreen(void* window) { + if( windowIsFullScreen(window) ) { return; } dispatch_async(dispatch_get_main_queue(), ^{ - [((WebviewWindow*)nsWindow).w toggleFullScreen:nil]; - });} + [((WebviewWindow*)window).w toggleFullScreen:nil]; + }); +} -void windowUnFullscreen(void* nsWindow) { - if( !windowIsFullScreen (nsWindow) ) { +void windowUnFullscreen(void* window) { + if( !windowIsFullScreen(window) ) { return; } dispatch_async(dispatch_get_main_queue(), ^{ - [((WebviewWindow*)nsWindow).w toggleFullScreen:nil]; + [((WebviewWindow*)window).w toggleFullScreen:nil]; }); } // restore window to normal size -void windowRestore(void* nsWindow) { +void windowRestore(void* window) { // If window is fullscreen - if([((WebviewWindow*)nsWindow).w styleMask] & NSWindowStyleMaskFullScreen) { - [((WebviewWindow*)nsWindow).w toggleFullScreen:nil]; + if([((WebviewWindow*)window).w styleMask] & NSWindowStyleMaskFullScreen) { + [((WebviewWindow*)window).w toggleFullScreen:nil]; } // If window is maximised - if([((WebviewWindow*)nsWindow).w isZoomed]) { - [((WebviewWindow*)nsWindow).w zoom:nil]; + if([((WebviewWindow*)window).w isZoomed]) { + [((WebviewWindow*)window).w zoom:nil]; } // If window in minimised - if([((WebviewWindow*)nsWindow).w isMiniaturized]) { - [((WebviewWindow*)nsWindow).w deminiaturize:nil]; + if([((WebviewWindow*)window).w isMiniaturized]) { + [((WebviewWindow*)window).w deminiaturize:nil]; } } // disable window fullscreen button -void setFullscreenButtonEnabled(void* nsWindow, bool enabled) { - NSButton *fullscreenButton = [((WebviewWindow*)nsWindow).w standardWindowButton:NSWindowZoomButton]; +void setFullscreenButtonEnabled(void* window, bool enabled) { + NSButton *fullscreenButton = [((WebviewWindow*)window).w standardWindowButton:NSWindowZoomButton]; fullscreenButton.enabled = enabled; } // Set the titlebar style -void windowSetTitleBarAppearsTransparent(void* nsWindow, bool transparent) { +void windowSetTitleBarAppearsTransparent(void* window, bool transparent) { if( transparent ) { - [((WebviewWindow*)nsWindow).w setTitlebarAppearsTransparent:true]; + [((WebviewWindow*)window).w setTitlebarAppearsTransparent:true]; } else { - [((WebviewWindow*)nsWindow).w setTitlebarAppearsTransparent:false]; + [((WebviewWindow*)window).w setTitlebarAppearsTransparent:false]; } } // Set window fullsize content view -void windowSetFullSizeContent(void* nsWindow, bool fullSize) { +void windowSetFullSizeContent(void* window, bool fullSize) { + NSWindow *nsWindow = ((WebviewWindow*)window).w; if( fullSize ) { - [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] | NSWindowStyleMaskFullSizeContentView]; + [nsWindow setStyleMask:[nsWindow styleMask] | NSWindowStyleMaskFullSizeContentView]; } else { - [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] & ~NSWindowStyleMaskFullSizeContentView]; + [nsWindow setStyleMask:[nsWindow styleMask] & ~NSWindowStyleMaskFullSizeContentView]; } } // Set Hide Titlebar -void windowSetHideTitleBar(void* nsWindow, bool hideTitlebar) { +void windowSetHideTitleBar(void* window, bool hideTitlebar) { + NSWindow *nsWindow = ((WebviewWindow*)window).w; if( hideTitlebar ) { - [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] & ~NSWindowStyleMaskTitled]; + [nsWindow setStyleMask:[nsWindow styleMask] & ~NSWindowStyleMaskTitled]; } else { - [((WebviewWindow*)nsWindow).w setStyleMask:[((WebviewWindow*)nsWindow).w styleMask] | NSWindowStyleMaskTitled]; + [nsWindow setStyleMask:[nsWindow styleMask] | NSWindowStyleMaskTitled]; } } // Set Hide Title in Titlebar -void windowSetHideTitle(void* nsWindow, bool hideTitle) { +void windowSetHideTitle(void* window, bool hideTitle) { + NSWindow *nsWindow = ((WebviewWindow*)window).w; if( hideTitle ) { - [((WebviewWindow*)nsWindow).w setTitleVisibility:NSWindowTitleHidden]; + [nsWindow setTitleVisibility:NSWindowTitleHidden]; } else { - [((WebviewWindow*)nsWindow).w setTitleVisibility:NSWindowTitleVisible]; + [nsWindow setTitleVisibility:NSWindowTitleVisible]; } } // Set Window use toolbar -void windowSetUseToolbar(void* nsWindow, bool useToolbar) { - NSWindow* window = ((WebviewWindow*)nsWindow).w; +void windowSetUseToolbar(void* window, bool useToolbar) { + NSWindow* nsWindow = ((WebviewWindow*)window).w; if( useToolbar ) { NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"]; [toolbar autorelease]; - [window setToolbar:toolbar]; + [nsWindow setToolbar:toolbar]; } else { - [window setToolbar:nil]; + [nsWindow setToolbar:nil]; } } // Set window toolbar style -void windowSetToolbarStyle(void* nsWindow, int style) { - NSWindow* window = ((WebviewWindow*)nsWindow).w; +void windowSetToolbarStyle(void* window, int style) { + NSWindow* nsWindow = ((WebviewWindow*)window).w; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 - if (@available(macOS 11.0, *)) { - NSToolbar* toolbar = [window toolbar]; - if ( toolbar == nil ) { + if( @available(macOS 11.0, *) ) { + NSToolbar* toolbar = [nsWindow toolbar]; + if( toolbar == nil ) { return; } - [window setToolbarStyle:style]; + [nsWindow setToolbarStyle:style]; } #endif } // Set Hide Toolbar Separator -void windowSetHideToolbarSeparator(void* nsWindow, bool hideSeparator) { - NSToolbar* toolbar = [((WebviewWindow*)nsWindow).w toolbar]; +void windowSetHideToolbarSeparator(void* window, bool hideSeparator) { + NSToolbar* toolbar = [((WebviewWindow*)window).w toolbar]; if( toolbar == nil ) { return; } @@ -487,7 +482,7 @@ void windowSetHideToolbarSeparator(void* nsWindow, bool hideSeparator) { // Configure the toolbar auto-hide feature void windowSetShowToolbarWhenFullscreen(void* window, bool setting) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; // Get delegate WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[nsWindow delegate]; // Set height @@ -495,46 +490,46 @@ void windowSetShowToolbarWhenFullscreen(void* window, bool setting) { } // Set Window appearance type -void windowSetAppearanceTypeByName(void* nsWindow, const char *appearanceName) { +void windowSetAppearanceTypeByName(void* window, const char *appearanceName) { // set window appearance type by name // Convert appearance name to NSString NSString* appearanceNameString = [NSString stringWithUTF8String:appearanceName]; // Set appearance - [((WebviewWindow*)nsWindow).w setAppearance:[NSAppearance appearanceNamed:appearanceNameString]]; + [((WebviewWindow*)window).w setAppearance:[NSAppearance appearanceNamed:appearanceNameString]]; free((void*)appearanceName); } // Center window on current monitor -void windowCenter(void* nsWindow) { - [((WebviewWindow*)nsWindow).w center]; +void windowCenter(void* window) { + [((WebviewWindow*)window).w center]; } // Get the current size of the window -void windowGetSize(void* nsWindow, int* width, int* height) { - NSRect frame = [((WebviewWindow*)nsWindow).w frame]; +void windowGetSize(void* window, int* width, int* height) { + NSRect frame = [((WebviewWindow*)window).w frame]; *width = frame.size.width; *height = frame.size.height; } // Get window width -int windowGetWidth(void* nsWindow) { - return [((WebviewWindow*)nsWindow).w frame].size.width; +int windowGetWidth(void* window) { + return [((WebviewWindow*)window).w frame].size.width; } // Get window height -int windowGetHeight(void* nsWindow) { - return [((WebviewWindow*)nsWindow).w frame].size.height; +int windowGetHeight(void* window) { + return [((WebviewWindow*)window).w frame].size.height; } // Get window position -void windowGetRelativePosition(void* nsWindow, int* x, int* y) { - NSWindow* window = ((WebviewWindow*)nsWindow).w; - NSRect frame = [window frame]; +void windowGetRelativePosition(void* window, int* x, int* y) { + NSWindow* nsWindow = ((WebviewWindow*)window).w; + NSRect frame = [nsWindow frame]; *x = frame.origin.x; // Translate to screen coordinates so Y=0 is the top of the screen - NSScreen* screen = [window screen]; + NSScreen* screen = [nsWindow screen]; if( screen == NULL ) { screen = [NSScreen mainScreen]; } @@ -543,32 +538,31 @@ void windowGetRelativePosition(void* nsWindow, int* x, int* y) { } // Get absolute window position -void windowGetPosition(void* nsWindow, int* x, int* y) { - NSRect frame = [((WebviewWindow*)nsWindow).w frame]; +void windowGetPosition(void* window, int* x, int* y) { + NSRect frame = [((WebviewWindow*)window).w frame]; *x = frame.origin.x; *y = frame.origin.y; } -void windowSetPosition(void* nsWindow, int x, int y) { - NSWindow *window = ((WebviewWindow*)nsWindow).w; +void windowSetPosition(void* window, int x, int y) { + NSWindow *nsWindow = ((WebviewWindow*)window).w; - NSRect frame = [window frame]; + NSRect frame = [nsWindow frame]; frame.origin.x = x; frame.origin.y = y; - [window setFrame:frame display:YES]; + [nsWindow setFrame:frame display:YES]; } // Destroy window -void windowDestroy(void* nsWindow) { - [((WebviewWindow*)nsWindow).w close]; +void windowDestroy(void* window) { + [((WebviewWindow*)window).w close]; } // Remove drop shadow from window -void windowSetShadow(void* nsWindow, bool hasShadow) { - [((WebviewWindow*)nsWindow).w setHasShadow:hasShadow]; +void windowSetShadow(void* window, bool hasShadow) { + [((WebviewWindow*)window).w setHasShadow:hasShadow]; } - // windowClose closes the current window void windowClose(void *window) { [((WebviewWindow*)window).w close]; @@ -581,7 +575,7 @@ void windowZoom(void *window) { // webviewRenderHTML renders the given HTML void windowRenderHTML(void *window, const char *html) { - WebviewWindow *webviewWindow = (WebviewWindow *)window; + WebviewWindow *webviewWindow = (WebviewWindow*)window; // get window delegate WebviewWindowDelegate* windowDelegate = (WebviewWindowDelegate*)[webviewWindow.w delegate]; // render html @@ -589,7 +583,7 @@ void windowRenderHTML(void *window, const char *html) { } void windowInjectCSS(void *window, const char *css) { - WebviewWindow *webviewWindow = (WebviewWindow *)window; + WebviewWindow *webviewWindow = (WebviewWindow*)window; // inject css [webviewWindow.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); @@ -605,16 +599,16 @@ void windowMaximise(void *window) { } bool windowIsVisible(void *window) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; return (nsWindow.occlusionState & NSWindowOcclusionStateVisible) == NSWindowOcclusionStateVisible; } // windowSetFullScreen void windowSetFullScreen(void *window, bool fullscreen) { - if (windowIsFullScreen (window)) { + if( windowIsFullScreen (window) ) { return; } - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; windowSetMaxSize(nsWindow, 0, 0); windowSetMinSize(nsWindow, 0, 0); [nsWindow toggleFullScreen:nil]; @@ -631,7 +625,7 @@ void windowUnmaximise(void *window) { } void windowDisableSizeConstraints(void *window) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; // disable size constraints [nsWindow setContentMinSize:CGSizeZero]; [nsWindow setContentMaxSize:CGSizeZero]; @@ -650,7 +644,7 @@ void windowHide(void *window) { // 1 = disabled // 2 = hidden void setButtonState(void *button, int state) { - if (button == nil) { + if( button == nil ) { return; } NSButton *nsbutton = (NSButton*)button; @@ -660,21 +654,21 @@ void setButtonState(void *button, int state) { // setMinimiseButtonState sets the minimise button state void setMinimiseButtonState(void *window, int state) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; NSButton *minimiseButton = [nsWindow standardWindowButton:NSWindowMiniaturizeButton]; setButtonState(minimiseButton, state); } // setMaximiseButtonState sets the maximise button state void setMaximiseButtonState(void *window, int state) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; NSButton *maximiseButton = [nsWindow standardWindowButton:NSWindowZoomButton]; setButtonState(maximiseButton, state); } // setCloseButtonState sets the close button state void setCloseButtonState(void *window, int state) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; NSButton *closeButton = [nsWindow standardWindowButton:NSWindowCloseButton]; setButtonState(closeButton, state); } @@ -689,9 +683,9 @@ void windowShowMenu(void *window, void *menu, int x, int y) { // Make the given window frameless void windowSetFrameless(void *window, bool frameless) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; // set the window style to be frameless - if (frameless) { + if( frameless ) { [nsWindow setStyleMask:([nsWindow styleMask] | NSWindowStyleMaskFullSizeContentView)]; } else { [nsWindow setStyleMask:([nsWindow styleMask] & ~NSWindowStyleMaskFullSizeContentView)]; @@ -710,7 +704,7 @@ void startDrag(void *window) { void windowPrint(void *window) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 110000 // Check if macOS 11.0 or newer - if (@available(macOS 11.0, *)) { + if( @available(macOS 11.0, *) ) { WebviewWindow *webviewWindow = (WebviewWindow*)window; NSWindow* nsWindow = webviewWindow.w; @@ -751,21 +745,19 @@ void windowSetEnabled(void *window, bool enabled) { } void windowFocus(void *window) { - NSWindow* nsWindow = ((WebviewWindow *)window).w; + NSWindow* nsWindow = ((WebviewWindow*)window).w; // If the current application is not active, activate it - if (![[NSApplication sharedApplication] isActive]) { + if( ![[NSApplication sharedApplication] isActive] ) { [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; } [nsWindow makeKeyAndOrderFront:nil]; [nsWindow makeKeyWindow]; } -bool isIgnoreMouseEvents(void *nsWindow) { - NSWindow* window = ((WebviewWindow *)nsWindow).w; - return [window ignoresMouseEvents]; +bool isIgnoreMouseEvents(void *window) { + return [((WebviewWindow*)window).w ignoresMouseEvents]; } -void setIgnoreMouseEvents(void *nsWindow, bool ignore) { - NSWindow* window = ((WebviewWindow *)nsWindow).w; - [window setIgnoresMouseEvents:ignore]; +void setIgnoreMouseEvents(void *window, bool ignore) { + [((WebviewWindow*)window).w setIgnoresMouseEvents:ignore]; } From 5b5aa4a48176f14d06ea09be0f8212c9411ea621 Mon Sep 17 00:00:00 2001 From: atterpac Date: Sat, 23 Nov 2024 16:40:21 -0700 Subject: [PATCH 10/20] Support for linux deb,rpm,arch linux packager packaging --- .../commands/build_assets/Taskfile.linux.yml | 45 +++++++++++++++++++ .../updatable_build_assets/nfpm.yaml.tmpl | 20 +++++++++ .../nfpm/nfpm.yaml.tmpl | 44 ++++++++++++++++++ .../nfpm/scripts/postinstall.sh | 1 + .../nfpm/scripts/postremove.sh | 1 + .../nfpm/scripts/preinstall.sh | 1 + .../nfpm/scripts/preremove.sh | 1 + v3/internal/doctor/doctor.go | 3 +- v3/internal/doctor/packagemanager/apt.go | 16 ++++--- v3/internal/doctor/packagemanager/dnf.go | 10 ++++- v3/internal/doctor/packagemanager/emerge.go | 5 ++- v3/internal/doctor/packagemanager/eopkg.go | 11 +++-- v3/internal/doctor/packagemanager/nixpkgs.go | 10 ++++- .../doctor/packagemanager/packagemanager.go | 21 +++++++++ v3/internal/doctor/packagemanager/pacman.go | 10 ++++- v3/internal/doctor/packagemanager/pm.go | 3 +- v3/internal/doctor/packagemanager/zypper.go | 10 ++++- 17 files changed, 193 insertions(+), 19 deletions(-) create mode 100644 v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl create mode 100644 v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl create mode 100644 v3/internal/commands/updatable_build_assets/nfpm/scripts/postinstall.sh create mode 100644 v3/internal/commands/updatable_build_assets/nfpm/scripts/postremove.sh create mode 100644 v3/internal/commands/updatable_build_assets/nfpm/scripts/preinstall.sh create mode 100644 v3/internal/commands/updatable_build_assets/nfpm/scripts/preremove.sh diff --git a/v3/internal/commands/build_assets/Taskfile.linux.yml b/v3/internal/commands/build_assets/Taskfile.linux.yml index 814ee0ae130..74ae5eaaef6 100644 --- a/v3/internal/commands/build_assets/Taskfile.linux.yml +++ b/v3/internal/commands/build_assets/Taskfile.linux.yml @@ -28,6 +28,9 @@ tasks: PRODUCTION: "true" cmds: - task: create:appimage + - task: create:deb + - task: create:rpm + - task: create:aur create:appimage: summary: Creates an AppImage @@ -48,6 +51,48 @@ tasks: DESKTOP_FILE: '{{.APP_NAME}}.desktop' OUTPUT_DIR: '../../bin' + create:deb: + summary: Creates a deb package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:deb + + create:rpm: + summary: Creates a rpm package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:rpm + + create:aur: + summary: Creates a arch linux packager package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:aur + + generate:deb: + summary: Creates a deb package + cmds: + - nfpm pkg -f ./build/nfpm/nfpm.yaml -p deb -t ./bin/{{.APP_NAME}}.deb + + generate:rpm: + summary: Creates a rpm package + cmds: + - nfpm pkg -f ./build/nfpm/nfpm.yaml -p rpm -t ./bin/{{.APP_NAME}}.rpm + + generate:aur: + summary: Creates a arch linux packager package + cmds: + - nfpm pkg -f ./build/nfpm/nfpm.yaml -p arch -t ./bin/{{.APP_NAME}}.pkg.tar.zst + generate:dotdesktop: summary: Generates a `.desktop` file dir: build diff --git a/v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl b/v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl new file mode 100644 index 00000000000..427ffaaaac9 --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl @@ -0,0 +1,20 @@ +name: "{{.BinaryName}}" +arch: "amd64" +platform: "linux" +version: "{{.ProductVersion}}" +section: "default" +priority: "extra" +maintainer: "{{.ProductCompany}}" +description: "{{.ProductDescription}}" +vendor: "{{.ProductCompany}}" +homepage: "https://wails.io" +license: "MIT" +release: "1" + +contents: + - src: "../../bin/{{.BinaryName}}" + dst: "/usr/bin/{{.BinaryName}}" + - src: "../appicon.png" + dst: "/usr/share/icons/hicolor/128x128/apps/{{.BinaryName}}.png" + - src: "{{.BinaryName}}.desktop" + dst: "/usr/share/applications/{{.BinaryName}}.desktop" diff --git a/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl b/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl new file mode 100644 index 00000000000..4c37eb6774e --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl @@ -0,0 +1,44 @@ +# Feel free to remove those if you don't want/need to use them. +# Make sure to check the documentation at https://nfpm.goreleaser.com +# +# The lines below are called `modelines`. See `:help modeline` + +name: "{{.BinaryName}}" +arch: ${GOARCH} +platform: "linux" +version: "{{.ProductVersion}}" +section: "default" +priority: "extra" +maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> +description: "{{.ProductDescription}}" +vendor: "{{.ProductCompany}}" +homepage: "https://wails.io" +license: "MIT" +release: "1" + +contents: + - src: "./bin/{{.BinaryName}}" + dst: "/usr/local/bin/{{.BinaryName}}" + - src: "./build/appicon.png" + dst: "/usr/share/icons/hicolor/128x128/apps/{{.BinaryName}}.png" + +# replaces: +# - foobar +# provides: +# - bar +# depends: +# - foo +# - bar +# recommends: +# - whatever +# suggests: +# - something-else +# conflicts: +# - not-foo +# - not-bar +# changelog: "changelog.yaml" +# scripts: +# preinstall: ./build/nfpm/scripts/preinstall.sh +# postinstall: ./build/nfpm/scripts/postinstall.sh +# preremove: ./build/nfpm/scripts/preremove.sh +# postremove: ./build/nfpm/scripts/postremove.sh diff --git a/v3/internal/commands/updatable_build_assets/nfpm/scripts/postinstall.sh b/v3/internal/commands/updatable_build_assets/nfpm/scripts/postinstall.sh new file mode 100644 index 00000000000..a9bf588e2f8 --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/nfpm/scripts/postinstall.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/internal/commands/updatable_build_assets/nfpm/scripts/postremove.sh b/v3/internal/commands/updatable_build_assets/nfpm/scripts/postremove.sh new file mode 100644 index 00000000000..a9bf588e2f8 --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/nfpm/scripts/postremove.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/internal/commands/updatable_build_assets/nfpm/scripts/preinstall.sh b/v3/internal/commands/updatable_build_assets/nfpm/scripts/preinstall.sh new file mode 100644 index 00000000000..a9bf588e2f8 --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/nfpm/scripts/preinstall.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/internal/commands/updatable_build_assets/nfpm/scripts/preremove.sh b/v3/internal/commands/updatable_build_assets/nfpm/scripts/preremove.sh new file mode 100644 index 00000000000..a9bf588e2f8 --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/nfpm/scripts/preremove.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/internal/doctor/doctor.go b/v3/internal/doctor/doctor.go index c6d3c0ca773..3e1fe948df1 100644 --- a/v3/internal/doctor/doctor.go +++ b/v3/internal/doctor/doctor.go @@ -2,7 +2,6 @@ package doctor import ( "fmt" - "github.com/wailsapp/wails/v3/internal/buildinfo" "path/filepath" "runtime" "runtime/debug" @@ -10,6 +9,8 @@ import ( "strconv" "strings" + "github.com/wailsapp/wails/v3/internal/buildinfo" + "github.com/go-git/go-git/v5" "github.com/jaypipes/ghw" "github.com/pterm/pterm" diff --git a/v3/internal/doctor/packagemanager/apt.go b/v3/internal/doctor/packagemanager/apt.go index 1a85b8376be..1f46db46970 100644 --- a/v3/internal/doctor/packagemanager/apt.go +++ b/v3/internal/doctor/packagemanager/apt.go @@ -40,6 +40,9 @@ func (a *Apt) Packages() Packagemap { "npm": []*Package{ {Name: "npm", SystemPackage: true}, }, + "nfpm": []*Package{ + {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -54,7 +57,10 @@ func (a *Apt) listPackage(name string) (string, error) { // PackageInstalled tests if the given package name is installed func (a *Apt) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { + if !pkg.SystemPackage { + if pkg.InstallCheck != nil { + return pkg.InstallCheck(), nil + } return false, nil } output, err := a.listPackage(pkg.Name) @@ -64,8 +70,8 @@ func (a *Apt) PackageInstalled(pkg *Package) (bool, error) { // PackageAvailable tests if the given package is available for installation func (a *Apt) PackageAvailable(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { - return false, nil + if !pkg.SystemPackage { + return true, nil } output, err := a.listPackage(pkg.Name) // We add a space to ensure we get a full match, not partial match @@ -78,8 +84,8 @@ func (a *Apt) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (a *Apt) InstallCommand(pkg *Package) string { - if pkg.SystemPackage == false { - return pkg.InstallCommand[a.osid] + if !pkg.SystemPackage { + return pkg.InstallCommand } return "sudo apt install " + pkg.Name } diff --git a/v3/internal/doctor/packagemanager/dnf.go b/v3/internal/doctor/packagemanager/dnf.go index a98ceac7038..223845dd0a6 100644 --- a/v3/internal/doctor/packagemanager/dnf.go +++ b/v3/internal/doctor/packagemanager/dnf.go @@ -43,6 +43,9 @@ func (y *Dnf) Packages() Packagemap { {Name: "npm", SystemPackage: true}, {Name: "nodejs-npm", SystemPackage: true}, }, + "nfpm*": []*Package{ + {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -53,7 +56,10 @@ func (y *Dnf) Name() string { // PackageInstalled tests if the given package name is installed func (y *Dnf) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { + if !pkg.SystemPackage { + if pkg.InstallCheck != nil { + return pkg.InstallCheck(), nil + } return false, nil } stdout, err := execCmd("dnf", "info", "installed", pkg.Name) @@ -103,7 +109,7 @@ func (y *Dnf) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (y *Dnf) InstallCommand(pkg *Package) string { if pkg.SystemPackage == false { - return pkg.InstallCommand[y.osid] + return pkg.InstallCommand } return "sudo dnf install " + pkg.Name } diff --git a/v3/internal/doctor/packagemanager/emerge.go b/v3/internal/doctor/packagemanager/emerge.go index 5ff21539a9a..aae18e8da06 100644 --- a/v3/internal/doctor/packagemanager/emerge.go +++ b/v3/internal/doctor/packagemanager/emerge.go @@ -41,6 +41,9 @@ func (e *Emerge) Packages() Packagemap { "npm": []*Package{ {Name: "net-libs/nodejs", SystemPackage: true}, }, + "nfpm": []*Package{ + {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -106,7 +109,7 @@ func (e *Emerge) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (e *Emerge) InstallCommand(pkg *Package) string { if pkg.SystemPackage == false { - return pkg.InstallCommand[e.osid] + return pkg.InstallCommand } return "sudo emerge " + pkg.Name } diff --git a/v3/internal/doctor/packagemanager/eopkg.go b/v3/internal/doctor/packagemanager/eopkg.go index a2dc7aa8cac..8f7d0df1d7f 100644 --- a/v3/internal/doctor/packagemanager/eopkg.go +++ b/v3/internal/doctor/packagemanager/eopkg.go @@ -7,7 +7,6 @@ import ( "strings" ) -// Eopkg represents the Eopkg manager type Eopkg struct { name string osid string @@ -42,6 +41,9 @@ func (e *Eopkg) Packages() Packagemap { "npm": []*Package{ {Name: "nodejs", SystemPackage: true}, }, + "nfpm": []*Package{ + {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -52,7 +54,10 @@ func (e *Eopkg) Name() string { // PackageInstalled tests if the given package is installed func (e *Eopkg) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { + if !pkg.SystemPackage { + if pkg.InstallCheck != nil { + return pkg.InstallCheck(), nil + } return false, nil } stdout, err := execCmd("eopkg", "info", pkg.Name) @@ -75,7 +80,7 @@ func (e *Eopkg) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (e *Eopkg) InstallCommand(pkg *Package) string { if pkg.SystemPackage == false { - return pkg.InstallCommand[e.osid] + return pkg.InstallCommand } return "sudo eopkg it " + pkg.Name } diff --git a/v3/internal/doctor/packagemanager/nixpkgs.go b/v3/internal/doctor/packagemanager/nixpkgs.go index 749860eba23..6d39a53a27c 100644 --- a/v3/internal/doctor/packagemanager/nixpkgs.go +++ b/v3/internal/doctor/packagemanager/nixpkgs.go @@ -55,6 +55,9 @@ func (n *Nixpkgs) Packages() Packagemap { "npm": []*Package{ {Name: channel + ".nodejs", SystemPackage: true}, }, + "nfpm": []*Package{ + {Name: channel + ".nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -65,7 +68,10 @@ func (n *Nixpkgs) Name() string { // PackageInstalled tests if the given package name is installed func (n *Nixpkgs) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { + if !pkg.SystemPackage { + if pkg.InstallCheck != nil { + return pkg.InstallCheck(), nil + } return false, nil } @@ -142,7 +148,7 @@ func (n *Nixpkgs) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (n *Nixpkgs) InstallCommand(pkg *Package) string { if pkg.SystemPackage == false { - return pkg.InstallCommand[n.osid] + return pkg.InstallCommand } return "nix-env -iA " + pkg.Name } diff --git a/v3/internal/doctor/packagemanager/packagemanager.go b/v3/internal/doctor/packagemanager/packagemanager.go index 800b05f7a93..3d95291613d 100644 --- a/v3/internal/doctor/packagemanager/packagemanager.go +++ b/v3/internal/doctor/packagemanager/packagemanager.go @@ -134,6 +134,10 @@ func AppVersion(name string) string { return npmVersion() } + if name == "nfpm" { + return nfpmVersion() + } + return "" } @@ -167,3 +171,20 @@ func npmVersion() string { version, _ := execCmd("npm", "--version") return strings.TrimSpace(version) } + +func nfpmVersion() string { + output, _ := execCmd("nfpm", "--version") + lines := strings.Split(output, "\n") + for _, line := range lines { + if strings.HasPrefix(line, "GitVersion:") { + version := strings.TrimSpace(strings.TrimPrefix(line, "GitVersion:")) + return version + } + } + return "unknown" +} + +func isNfpmInstalled() bool { + _, err := exec.LookPath("nfpm") + return err == nil +} diff --git a/v3/internal/doctor/packagemanager/pacman.go b/v3/internal/doctor/packagemanager/pacman.go index d585f94f770..131a6a8b685 100644 --- a/v3/internal/doctor/packagemanager/pacman.go +++ b/v3/internal/doctor/packagemanager/pacman.go @@ -41,6 +41,9 @@ func (p *Pacman) Packages() Packagemap { "npm": []*Package{ {Name: "npm", SystemPackage: true}, }, + "nfpm": []*Package{ + {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -51,7 +54,10 @@ func (p *Pacman) Name() string { // PackageInstalled tests if the given package name is installed func (p *Pacman) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { + if !pkg.SystemPackage { + if pkg.InstallCheck != nil { + return pkg.InstallCheck(), nil + } return false, nil } stdout, err := execCmd("pacman", "-Q", pkg.Name) @@ -103,7 +109,7 @@ func (p *Pacman) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (p *Pacman) InstallCommand(pkg *Package) string { if pkg.SystemPackage == false { - return pkg.InstallCommand[p.osid] + return pkg.InstallCommand } return "sudo pacman -S " + pkg.Name } diff --git a/v3/internal/doctor/packagemanager/pm.go b/v3/internal/doctor/packagemanager/pm.go index 0602e1e03fa..6b6ced9c003 100644 --- a/v3/internal/doctor/packagemanager/pm.go +++ b/v3/internal/doctor/packagemanager/pm.go @@ -6,7 +6,8 @@ package packagemanager type Package struct { Name string Version string - InstallCommand map[string]string + InstallCommand string + InstallCheck func() bool SystemPackage bool Library bool Optional bool diff --git a/v3/internal/doctor/packagemanager/zypper.go b/v3/internal/doctor/packagemanager/zypper.go index dec28acb252..3a350e89578 100644 --- a/v3/internal/doctor/packagemanager/zypper.go +++ b/v3/internal/doctor/packagemanager/zypper.go @@ -44,6 +44,9 @@ func (z *Zypper) Packages() Packagemap { "npm": []*Package{ {Name: "npm10", SystemPackage: true}, }, + "nfpm": []*Package{ + {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, + }, } } @@ -54,7 +57,10 @@ func (z *Zypper) Name() string { // PackageInstalled tests if the given package name is installed func (z *Zypper) PackageInstalled(pkg *Package) (bool, error) { - if pkg.SystemPackage == false { + if !pkg.SystemPackage { + if pkg.InstallCheck != nil { + return pkg.InstallCheck(), nil + } return false, nil } stdout, err := execCmd("zypper", "info", pkg.Name) @@ -101,7 +107,7 @@ func (z *Zypper) PackageAvailable(pkg *Package) (bool, error) { // InstallCommand returns the package manager specific command to install a package func (z *Zypper) InstallCommand(pkg *Package) string { if pkg.SystemPackage == false { - return pkg.InstallCommand[z.osid] + return pkg.InstallCommand } return "sudo zypper in " + pkg.Name } From 7f13ecaa8afa9462f89b4073ce1c66064ea8c441 Mon Sep 17 00:00:00 2001 From: atterpac Date: Sat, 23 Nov 2024 16:52:28 -0700 Subject: [PATCH 11/20] remove optional tasks from linux:package task CHANGELOG.md --- mkdocs-website/docs/en/changelog.md | 1 + v3/internal/commands/build_assets/Taskfile.linux.yml | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mkdocs-website/docs/en/changelog.md b/mkdocs-website/docs/en/changelog.md index 996ece43689..dc7d2479e90 100644 --- a/mkdocs-website/docs/en/changelog.md +++ b/mkdocs-website/docs/en/changelog.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Support of linux packaging of deb,rpm, and arch linux packager builds by @atterpac in [#3909](https://github.com/wailsapp/wails/3909) - Added Support for darwin universal builds and packages by [ansxuman](https://github.com/ansxuman) in [#3902](https://github.com/wailsapp/wails/pull/3902) - Events documentation to the mkdocs webite by [atterpac](https://github.com/atterpac) in [#3867](https://github.com/wailsapp/wails/pull/3867) - Templates for sveltekit and sveltekit-ts that are set for non-SSR development by [atterpac](https://github.com/atterpac) in [#3829](https://github.com/wailsapp/wails/pull/3829) diff --git a/v3/internal/commands/build_assets/Taskfile.linux.yml b/v3/internal/commands/build_assets/Taskfile.linux.yml index 74ae5eaaef6..535b11ca8ff 100644 --- a/v3/internal/commands/build_assets/Taskfile.linux.yml +++ b/v3/internal/commands/build_assets/Taskfile.linux.yml @@ -28,9 +28,10 @@ tasks: PRODUCTION: "true" cmds: - task: create:appimage - - task: create:deb - - task: create:rpm - - task: create:aur + # Requires nfpm to be installed + # - task: create:deb + # - task: create:rpm + # - task: create:aur create:appimage: summary: Creates an AppImage From 6e12413c4428aac10ba4d6cbbdc0855c47b1d87e Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 24 Nov 2024 12:04:01 +1100 Subject: [PATCH 12/20] Update Taskfile.linux.yml --- .../commands/build_assets/Taskfile.linux.yml | 15 ++++++++++++++ .../updatable_build_assets/nfpm.yaml.tmpl | 20 ------------------- 2 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl diff --git a/v3/internal/commands/build_assets/Taskfile.linux.yml b/v3/internal/commands/build_assets/Taskfile.linux.yml index 535b11ca8ff..bfd0250be04 100644 --- a/v3/internal/commands/build_assets/Taskfile.linux.yml +++ b/v3/internal/commands/build_assets/Taskfile.linux.yml @@ -81,18 +81,33 @@ tasks: generate:deb: summary: Creates a deb package + preconditions: + - sh: nfpm --version + msg: It appears nfpm is not installed. Please install using `go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest` cmds: - nfpm pkg -f ./build/nfpm/nfpm.yaml -p deb -t ./bin/{{.APP_NAME}}.deb + env: + GOARCH: '{{.ARCH | default ARCH}}' generate:rpm: summary: Creates a rpm package + preconditions: + - sh: nfpm --version + msg: It appears nfpm is not installed. Please install using `go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest` cmds: - nfpm pkg -f ./build/nfpm/nfpm.yaml -p rpm -t ./bin/{{.APP_NAME}}.rpm + env: + GOARCH: '{{.ARCH | default ARCH}}' generate:aur: summary: Creates a arch linux packager package + preconditions: + - sh: nfpm --version + msg: It appears nfpm is not installed. Please install using `go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest` cmds: - nfpm pkg -f ./build/nfpm/nfpm.yaml -p arch -t ./bin/{{.APP_NAME}}.pkg.tar.zst + env: + GOARCH: '{{.ARCH | default ARCH}}' generate:dotdesktop: summary: Generates a `.desktop` file diff --git a/v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl b/v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl deleted file mode 100644 index 427ffaaaac9..00000000000 --- a/v3/internal/commands/updatable_build_assets/nfpm.yaml.tmpl +++ /dev/null @@ -1,20 +0,0 @@ -name: "{{.BinaryName}}" -arch: "amd64" -platform: "linux" -version: "{{.ProductVersion}}" -section: "default" -priority: "extra" -maintainer: "{{.ProductCompany}}" -description: "{{.ProductDescription}}" -vendor: "{{.ProductCompany}}" -homepage: "https://wails.io" -license: "MIT" -release: "1" - -contents: - - src: "../../bin/{{.BinaryName}}" - dst: "/usr/bin/{{.BinaryName}}" - - src: "../appicon.png" - dst: "/usr/share/icons/hicolor/128x128/apps/{{.BinaryName}}.png" - - src: "{{.BinaryName}}.desktop" - dst: "/usr/share/applications/{{.BinaryName}}.desktop" From 475ba28b6f70e6276a60927988007b76945d1558 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 24 Nov 2024 13:09:25 +1100 Subject: [PATCH 13/20] Integrated nfpm into CLI. Fixed task update. --- v3/cmd/wails3/main.go | 1 + v3/go.mod | 60 ++++++++--- v3/go.sum | 117 ++++++++++++++++++++++ v3/internal/commands/task.go | 54 ++-------- v3/internal/commands/tool_package.go | 55 ++++++++++ v3/internal/commands/tool_package_test.go | 114 +++++++++++++++++++++ v3/internal/flags/package.go | 9 ++ v3/internal/packager/packager.go | 94 +++++++++++++++++ v3/internal/packager/packager_test.go | 100 ++++++++++++++++++ 9 files changed, 544 insertions(+), 60 deletions(-) create mode 100644 v3/internal/commands/tool_package.go create mode 100644 v3/internal/commands/tool_package_test.go create mode 100644 v3/internal/flags/package.go create mode 100644 v3/internal/packager/packager.go create mode 100644 v3/internal/packager/packager_test.go diff --git a/v3/cmd/wails3/main.go b/v3/cmd/wails3/main.go index 0d229117ab4..aa33799fb4d 100644 --- a/v3/cmd/wails3/main.go +++ b/v3/cmd/wails3/main.go @@ -72,6 +72,7 @@ func main() { tool.NewSubCommandFunction("watcher", "Watches files and runs a command when they change", commands.Watcher) tool.NewSubCommandFunction("cp", "Copy files", commands.Cp) tool.NewSubCommandFunction("buildinfo", "Show Build Info", commands.BuildInfo) + tool.NewSubCommandFunction("package", "Generate Linux packages (deb, rpm, archlinux)", commands.ToolPackage) app.NewSubCommandFunction("version", "Print the version", commands.Version) app.NewSubCommand("sponsor", "Sponsor the project").Action(openSponsor) diff --git a/v3/go.mod b/v3/go.mod index 53a1f38b322..88e87064376 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -7,13 +7,13 @@ require ( github.com/atterpac/refresh v0.8.3 github.com/bep/debounce v1.2.1 github.com/ebitengine/purego v0.4.0-alpha.4 - github.com/go-git/go-git/v5 v5.11.0 + github.com/go-git/go-git/v5 v5.12.0 github.com/go-ole/go-ole v1.2.6 - github.com/go-task/task/v3 v3.31.0 + github.com/go-task/task/v3 v3.35.1 github.com/godbus/dbus/v5 v5.1.0 github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.4.0 github.com/jackmordaunt/icns/v2 v2.2.7 github.com/jaypipes/ghw v0.12.0 github.com/leaanthony/clir v1.6.0 @@ -42,50 +42,86 @@ require ( require ( atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/keyboard v0.2.8 // indirect - dario.cat/mergo v1.0.0 // indirect + dario.cat/mergo v1.0.1 // indirect + github.com/AlekSi/pointer v1.2.0 // indirect github.com/BurntSushi/toml v1.3.2 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/caarlos0/go-version v0.1.1 // indirect + github.com/cavaliergopher/cpio v1.0.1 // indirect + github.com/cloudflare/circl v1.3.8 // indirect github.com/containerd/console v1.0.4 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a // indirect github.com/gookit/color v1.5.2 // indirect + github.com/goreleaser/chglog v0.6.1 // indirect + github.com/goreleaser/fileglob v1.3.0 // indirect + github.com/goreleaser/nfpm/v2 v2.41.1 // indirect + github.com/huandu/xstrings v1.3.3 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect github.com/jaypipes/pcidb v1.0.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.3 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect github.com/lithammer/fuzzysearch v1.1.5 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-zglob v0.0.4 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/muesli/mango v0.1.0 // indirect + github.com/muesli/mango-cobra v1.2.0 // indirect + github.com/muesli/mango-pflag v0.1.0 // indirect + github.com/muesli/roff v0.1.0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/radovskyb/watcher v1.0.7 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rjeczalik/notify v0.9.3 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sajari/fuzzy v1.0.0 // indirect - github.com/sergi/go-diff v1.2.0 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect + gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect + golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect golang.org/x/image v0.21.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.25.0 // indirect @@ -103,5 +139,5 @@ require ( modernc.org/opt v0.1.3 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.1 // indirect - mvdan.cc/sh/v3 v3.7.0 // indirect + mvdan.cc/sh/v3 v3.8.0 // indirect ) diff --git a/v3/go.sum b/v3/go.sum index 8b07497d1e1..42b8de7894c 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -6,8 +6,14 @@ atomicgo.dev/keyboard v0.2.8 h1:Di09BitwZgdTV1hPyX/b9Cqxi8HVuJQwWivnZUEqlj4= atomicgo.dev/keyboard v0.2.8/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= +github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= @@ -17,13 +23,26 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/ github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/MarvinJWendt/testza v0.5.1 h1:a9Fqx6vQrHQ4CyiaLhktfTTelwGotmFWy8MNhyaohw8= github.com/MarvinJWendt/testza v0.5.1/go.mod h1:L7csM8IBqCc0HH4TRYZSPCIRg6zJeqzM1pm3FSYZBso= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= +github.com/ProtonMail/gopenpgp/v2 v2.7.1 h1:Awsg7MPc2gD3I7IFac2qE3Gdls0lZW8SzrFZ3k1oz0s= +github.com/ProtonMail/gopenpgp/v2 v2.7.1/go.mod h1:/BU5gfAVwqyd8EfC3Eu7zmuhwYQpKs+cGD8M//iiaxs= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY= @@ -35,17 +54,33 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/atterpac/refresh v0.8.3 h1:Xj0rtd6Wfv/u03wZOdauASBOPxGZOJeik065S0wISNg= github.com/atterpac/refresh v0.8.3/go.mod h1:fJpWySLdpbANS8Ej5OvfZVZIVvi/9bmnhTjKS5EjQes= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/caarlos0/go-version v0.1.1 h1:1bikKHkGGVIIxqCmufhSSs3hpBScgHGacrvsi8FuIfc= +github.com/caarlos0/go-version v0.1.1/go.mod h1:Ze5Qx4TsBBi5FyrSKVg1Ibc44KGV/llAaKGp86oTwZ0= +github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk= +github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= +github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= +github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -61,6 +96,8 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -75,6 +112,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -82,6 +121,10 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-task/task/v3 v3.31.0 h1:o6iyj9gPJXxvxPi/u/l8e025PmM2BqKgtLNPS2i7hV4= github.com/go-task/task/v3 v3.31.0/go.mod h1:/CPDAu9nS3+soqY/e1tTrSo/zxk76lnljEV9aBTeKrg= +github.com/go-task/task/v3 v3.35.1 h1:zjQ3tLv+LIStDDTzOQx8F97NE/8FSTanjZuwgy/hwro= +github.com/go-task/task/v3 v3.35.1/go.mod h1:7F6HetCXjlBkgxNjXeTKQYpsA5Q34k4fV94fWXq8GTY= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -90,14 +133,34 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a h1:JJBdjSfqSy3mnDT0940ASQFghwcZ4y4cb6ttjAoXqwE= +github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= +github.com/goreleaser/chglog v0.6.1 h1:NZKiX8l0FTQPRzBgKST7knvNZmZ04f7PEGkN2wInfhE= +github.com/goreleaser/chglog v0.6.1/go.mod h1:Bnnfo07jMZkaAb0uRNASMZyOsX6ROW6X1qbXqN3guUo= +github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I= +github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU= +github.com/goreleaser/nfpm/v2 v2.41.1 h1:4tyZ9b817msLuyGKw53ed3suZNApkGHVZDekdGe8ZEE= +github.com/goreleaser/nfpm/v2 v2.41.1/go.mod h1:VPc5kF5OgfA+BosV/A2aB+Vg34honjWvp0Vt8ogsSi0= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/jackmordaunt/icns/v2 v2.2.7 h1:K/RbfvuzjmjVY5y4g+XENRs8ZZatwz4YnLHypa2KwQg= github.com/jackmordaunt/icns/v2 v2.2.7/go.mod h1:ovoTxGguSuoUGKMk5Nn3R7L7BgMQkylsO+bblBuI22A= github.com/jaypipes/ghw v0.12.0 h1:xU2/MDJfWmBhJnujHY9qwXQLs3DBsf0/Xa9vECY0Tho= @@ -111,15 +174,20 @@ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEE github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -145,6 +213,8 @@ github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMr github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q= github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -159,10 +229,24 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= +github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= +github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbYvWg= +github.com/muesli/mango-cobra v1.2.0/go.mod h1:vMJL54QytZAJhCT13LPVDfkvCUJ5/4jNUKF/8NC2UjA= +github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg= +github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0= +github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= +github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= @@ -196,21 +280,40 @@ github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZe github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= +github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -219,12 +322,18 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tc-hib/winres v0.3.1 h1:CwRjEGrKdbi5CvZ4ID+iyVhgyfatxFoizjPhzez9Io4= github.com/tc-hib/winres v0.3.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/wailsapp/go-webview2 v1.0.17 h1:DkLnUKqW7J///OBXkInMq1fzC88G6ZjHwKuHXThuaco= github.com/wailsapp/go-webview2 v1.0.17/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -232,15 +341,20 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8= +gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= @@ -322,6 +436,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -360,3 +475,5 @@ modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= +mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= +mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= diff --git a/v3/internal/commands/task.go b/v3/internal/commands/task.go index 7d13dc559b5..f72a405ff29 100644 --- a/v3/internal/commands/task.go +++ b/v3/internal/commands/task.go @@ -3,7 +3,6 @@ package commands import ( "context" "fmt" - "github.com/go-task/task/v3/errors" "os" "path/filepath" "strings" @@ -11,10 +10,8 @@ import ( "github.com/pterm/pterm" - "github.com/go-task/task/v3/args" - "github.com/go-task/task/v3" - "github.com/go-task/task/v3/taskfile" + "github.com/go-task/task/v3/taskfile/ast" ) // BuildSettings contains the CLI build settings @@ -81,7 +78,7 @@ func RunTask(options *RunTaskOptions, otherArgs []string) error { if options.OutputGroupBegin != "" { return fmt.Errorf("task: You can't set --output-group-begin without --output=group") } - if options.OutputGroupBegin != "" { + if options.OutputGroupEnd != "" { return fmt.Errorf("task: You can't set --output-group-end without --output=group") } } @@ -103,22 +100,14 @@ func RunTask(options *RunTaskOptions, otherArgs []string) error { Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, - - OutputStyle: taskfile.Output{ - Name: options.OutputName, - Group: taskfile.OutputGroup{ - Begin: options.OutputGroupBegin, - End: options.OutputGroupEnd, - }, - }, } - var listOptions = task.NewListOptions(options.List, options.ListAll, options.ListJSON) + listOptions := task.NewListOptions(options.List, options.ListAll, options.ListJSON, false) if err := listOptions.Validate(); err != nil { fatal(err.Error()) } - if (listOptions.ShouldListTasks()) && options.Silent { + if listOptions.ShouldListTasks() && options.Silent { e.ListTaskNames(options.ListAll) return nil } @@ -134,11 +123,6 @@ func RunTask(options *RunTaskOptions, otherArgs []string) error { return nil } - var ( - calls []taskfile.Call - globals *taskfile.Vars - ) - var index int var arg string for index, arg = range os.Args[2:] { @@ -161,34 +145,8 @@ func RunTask(options *RunTaskOptions, otherArgs []string) error { } } - if e.Taskfile.Version.Compare(taskfile.V3) >= 0 { - calls, globals = args.ParseV3(tasksAndVars...) - } else { - calls, globals = args.ParseV2(tasksAndVars...) - } - - globals.Set("CLI_ARGS", taskfile.Var{Static: strings.Join(otherArgs, " ")}) - e.Taskfile.Vars.Merge(globals) - - if !options.Watch { - e.InterceptInterruptSignals() - } - - ctx := context.Background() - - if options.Status { - return e.Status(ctx, calls...) - } - - if err := e.Run(ctx, calls...); err != nil { - pterm.Error.Println(err.Error()) - - if options.ExitCode { - if err, ok := err.(*errors.TaskRunError); ok { - os.Exit(err.Code()) - } - } - os.Exit(1) + if err := e.RunTask(context.Background(), &ast.Call{Task: tasksAndVars[0]}); err != nil { + fatal(err.Error()) } return nil } diff --git a/v3/internal/commands/tool_package.go b/v3/internal/commands/tool_package.go new file mode 100644 index 00000000000..66f3d2d251c --- /dev/null +++ b/v3/internal/commands/tool_package.go @@ -0,0 +1,55 @@ +package commands + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/wailsapp/wails/v3/internal/flags" + "github.com/wailsapp/wails/v3/internal/packager" +) + +// ToolPackage generates a Linux package in the specified format using nfpm +func ToolPackage(options *flags.ToolPackage) error { + DisableFooter = true + + if options.ConfigPath == "" { + return fmt.Errorf("please provide a config file using the -config flag") + } + + // Validate format + var pkgType packager.PackageType + switch strings.ToLower(options.Format) { + case "deb": + pkgType = packager.DEB + case "rpm": + pkgType = packager.RPM + case "archlinux": + pkgType = packager.ARCH + default: + return fmt.Errorf("unsupported package format '%s'. Supported formats: deb, rpm, archlinux", options.Format) + } + + // Get absolute path of config file + configPath, err := filepath.Abs(options.ConfigPath) + if err != nil { + return fmt.Errorf("error getting absolute path of config file: %w", err) + } + + // Check if config file exists + if _, err := os.Stat(configPath); err != nil { + return fmt.Errorf("config file not found: %s", configPath) + } + + // Generate output filename based on format + outputFile := fmt.Sprintf("package.%s", options.Format) + + // Create the package + err = packager.CreatePackageFromConfig(pkgType, configPath, outputFile) + if err != nil { + return fmt.Errorf("error creating package: %w", err) + } + + return nil +} diff --git a/v3/internal/commands/tool_package_test.go b/v3/internal/commands/tool_package_test.go new file mode 100644 index 00000000000..d5af802f4a8 --- /dev/null +++ b/v3/internal/commands/tool_package_test.go @@ -0,0 +1,114 @@ +package commands + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/wailsapp/wails/v3/internal/flags" +) + +func TestToolPackage(t *testing.T) { + tests := []struct { + name string + setup func() (*flags.ToolPackage, func()) + wantErr bool + errMsg string + }{ + { + name: "should fail with invalid format", + setup: func() (*flags.ToolPackage, func()) { + return &flags.ToolPackage{ + Format: "invalid", + ConfigPath: "config.yaml", + }, func() {} + }, + wantErr: true, + errMsg: "unsupported package format", + }, + { + name: "should fail with missing config file", + setup: func() (*flags.ToolPackage, func()) { + return &flags.ToolPackage{ + Format: "deb", + ConfigPath: "nonexistent.yaml", + }, func() {} + }, + wantErr: true, + errMsg: "config file not found", + }, + { + name: "should handle case-insensitive format (DEB)", + setup: func() (*flags.ToolPackage, func()) { + // Create a temporary config file + dir := t.TempDir() + configPath := filepath.Join(dir, "config.yaml") + err := os.WriteFile(configPath, []byte("name: test"), 0644) + if err != nil { + t.Fatal(err) + } + + return &flags.ToolPackage{ + Format: "DEB", + ConfigPath: configPath, + }, func() {} + }, + wantErr: false, + }, + { + name: "should handle case-insensitive format (RPM)", + setup: func() (*flags.ToolPackage, func()) { + // Create a temporary config file + dir := t.TempDir() + configPath := filepath.Join(dir, "config.yaml") + err := os.WriteFile(configPath, []byte("name: test"), 0644) + if err != nil { + t.Fatal(err) + } + + return &flags.ToolPackage{ + Format: "RPM", + ConfigPath: configPath, + }, func() {} + }, + wantErr: false, + }, + { + name: "should handle case-insensitive format (ARCHLINUX)", + setup: func() (*flags.ToolPackage, func()) { + // Create a temporary config file + dir := t.TempDir() + configPath := filepath.Join(dir, "config.yaml") + err := os.WriteFile(configPath, []byte("name: test"), 0644) + if err != nil { + t.Fatal(err) + } + + return &flags.ToolPackage{ + Format: "ARCHLINUX", + ConfigPath: configPath, + }, func() {} + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + options, cleanup := tt.setup() + defer cleanup() + + err := ToolPackage(options) + + if (err != nil) != tt.wantErr { + t.Errorf("ToolPackage() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && !strings.Contains(err.Error(), tt.errMsg) { + t.Errorf("ToolPackage() error = %v, want error containing %v", err, tt.errMsg) + } + }) + } +} diff --git a/v3/internal/flags/package.go b/v3/internal/flags/package.go new file mode 100644 index 00000000000..dfc8fb9debd --- /dev/null +++ b/v3/internal/flags/package.go @@ -0,0 +1,9 @@ +package flags + +// ToolPackage represents the options for the package command +type ToolPackage struct { + Common + + Format string `name:"format" description:"Package format to generate (deb, rpm, archlinux)" default:"deb"` + ConfigPath string `name:"config" description:"Path to the package configuration file" default:""` +} diff --git a/v3/internal/packager/packager.go b/v3/internal/packager/packager.go new file mode 100644 index 00000000000..5cf235d72ef --- /dev/null +++ b/v3/internal/packager/packager.go @@ -0,0 +1,94 @@ +// Package packager provides a simplified interface for creating Linux packages using nfpm +package packager + +import ( + "fmt" + "io" + "os" + + "github.com/goreleaser/nfpm/v2" + _ "github.com/goreleaser/nfpm/v2/apk" // Register APK packager + _ "github.com/goreleaser/nfpm/v2/arch" // Register Arch Linux packager + _ "github.com/goreleaser/nfpm/v2/deb" // Register DEB packager + _ "github.com/goreleaser/nfpm/v2/ipk" // Register IPK packager + _ "github.com/goreleaser/nfpm/v2/rpm" // Register RPM packager +) + +// PackageType represents supported package formats +type PackageType string + +const ( + // DEB is for Debian/Ubuntu packages + DEB PackageType = "deb" + // RPM is for RedHat/CentOS packages + RPM PackageType = "rpm" + // APK is for Alpine Linux packages + APK PackageType = "apk" + // IPK is for OpenWrt packages + IPK PackageType = "ipk" + // ARCH is for Arch Linux packages + ARCH PackageType = "archlinux" +) + +// CreatePackageFromConfig loads a configuration file and creates a package +func CreatePackageFromConfig(pkgType PackageType, configPath string, output string) error { + // Parse nfpm config + config, err := nfpm.ParseFile(configPath) + if err != nil { + return fmt.Errorf("error parsing config file: %w", err) + } + + // Get info for the specified packager + info, err := config.Get(string(pkgType)) + if err != nil { + return fmt.Errorf("error getting packager info: %w", err) + } + + // Get the packager + packager, err := nfpm.Get(string(pkgType)) + if err != nil { + return fmt.Errorf("error getting packager: %w", err) + } + + // Create output file + out, err := os.Create(output) + if err != nil { + return fmt.Errorf("error creating output file: %w", err) + } + defer out.Close() + + // Create the package + if err := packager.Package(info, out); err != nil { + return fmt.Errorf("error creating package: %w", err) + } + + return nil +} + +// CreatePackageFromConfigWriter loads a configuration file and writes the package to the provided writer +func CreatePackageFromConfigWriter(pkgType PackageType, configPath string, output io.Writer) error { + // Parse nfpm config + config, err := nfpm.ParseFile(configPath) + if err != nil { + return fmt.Errorf("error parsing config file: %w", err) + } + + // Get info for the specified packager + info, err := config.Get(string(pkgType)) + if err != nil { + return fmt.Errorf("error getting packager info: %w", err) + } + + // Get the packager + packager, err := nfpm.Get(string(pkgType)) + if err != nil { + return fmt.Errorf("error getting packager: %w", err) + } + + // Create the package + if err := packager.Package(info, output); err != nil { + return fmt.Errorf("error creating package: %w", err) + } + + return nil +} diff --git a/v3/internal/packager/packager_test.go b/v3/internal/packager/packager_test.go new file mode 100644 index 00000000000..3ed4a4f489d --- /dev/null +++ b/v3/internal/packager/packager_test.go @@ -0,0 +1,100 @@ +package packager + +import ( + "bytes" + "os" + "path/filepath" + "testing" +) + +func TestCreatePackageFromConfig(t *testing.T) { + // Create a temporary file for testing + content := []byte("test content") + tmpfile, err := os.CreateTemp("", "example") + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpfile.Name()) + + if _, err := tmpfile.Write(content); err != nil { + t.Fatal(err) + } + if err := tmpfile.Close(); err != nil { + t.Fatal(err) + } + + // Create a temporary config file + configContent := []byte(` +name: test-package +version: v1.0.0 +arch: amd64 +description: Test package +maintainer: Test User +license: MIT +contents: +- src: ` + tmpfile.Name() + ` + dst: /usr/local/bin/test-file +`) + + configFile, err := os.CreateTemp("", "config*.yaml") + if err != nil { + t.Fatal(err) + } + defer os.Remove(configFile.Name()) + + if _, err := configFile.Write(configContent); err != nil { + t.Fatal(err) + } + if err := configFile.Close(); err != nil { + t.Fatal(err) + } + + // Test creating packages for each format + formats := []struct { + pkgType PackageType + ext string + }{ + {DEB, "deb"}, + {RPM, "rpm"}, + {APK, "apk"}, + {IPK, "ipk"}, + {ARCH, "pkg.tar.zst"}, + } + + for _, format := range formats { + t.Run(string(format.pkgType), func(t *testing.T) { + // Test file-based package creation + outputPath := filepath.Join(os.TempDir(), "test-package."+format.ext) + err := CreatePackageFromConfig(format.pkgType, configFile.Name(), outputPath) + if err != nil { + t.Errorf("CreatePackageFromConfig failed for %s: %v", format.pkgType, err) + } + defer os.Remove(outputPath) + + // Verify the file was created + if _, err := os.Stat(outputPath); os.IsNotExist(err) { + t.Errorf("Package file was not created for %s", format.pkgType) + } + + // Test writer-based package creation + var buf bytes.Buffer + err = CreatePackageFromConfigWriter(format.pkgType, configFile.Name(), &buf) + if err != nil { + t.Errorf("CreatePackageFromConfigWriter failed for %s: %v", format.pkgType, err) + } + + // Verify some content was written + if buf.Len() == 0 { + t.Errorf("No content was written for %s", format.pkgType) + } + }) + } + + // Test with invalid config file + t.Run("InvalidConfig", func(t *testing.T) { + err := CreatePackageFromConfig(DEB, "nonexistent.yaml", "output.deb") + if err == nil { + t.Error("Expected error for invalid config, got nil") + } + }) +} From 8d7f7630950a42bf81e73faf9acba6729472b81d Mon Sep 17 00:00:00 2001 From: atterpac Date: Sat, 23 Nov 2024 19:44:05 -0700 Subject: [PATCH 14/20] package tool fixes and add bundle name field empty name guard --- .../commands/build_assets/Taskfile.linux.yml | 28 ++++--------------- v3/internal/commands/tool_package.go | 10 ++++++- v3/internal/flags/package.go | 5 ++-- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/v3/internal/commands/build_assets/Taskfile.linux.yml b/v3/internal/commands/build_assets/Taskfile.linux.yml index bfd0250be04..2b2a46a81e6 100644 --- a/v3/internal/commands/build_assets/Taskfile.linux.yml +++ b/v3/internal/commands/build_assets/Taskfile.linux.yml @@ -28,10 +28,9 @@ tasks: PRODUCTION: "true" cmds: - task: create:appimage - # Requires nfpm to be installed - # - task: create:deb - # - task: create:rpm - # - task: create:aur + - task: create:deb + - task: create:rpm + - task: create:aur create:appimage: summary: Creates an AppImage @@ -81,33 +80,18 @@ tasks: generate:deb: summary: Creates a deb package - preconditions: - - sh: nfpm --version - msg: It appears nfpm is not installed. Please install using `go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest` cmds: - - nfpm pkg -f ./build/nfpm/nfpm.yaml -p deb -t ./bin/{{.APP_NAME}}.deb - env: - GOARCH: '{{.ARCH | default ARCH}}' + - wails3 tool package -name {{.APP_NAME}} -format deb -config ./build/nfpm/nfpm.yaml generate:rpm: summary: Creates a rpm package - preconditions: - - sh: nfpm --version - msg: It appears nfpm is not installed. Please install using `go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest` cmds: - - nfpm pkg -f ./build/nfpm/nfpm.yaml -p rpm -t ./bin/{{.APP_NAME}}.rpm - env: - GOARCH: '{{.ARCH | default ARCH}}' + - wails3 tool package -name {{.APP_NAME}} -format rpm -config ./build/nfpm/nfpm.yaml generate:aur: summary: Creates a arch linux packager package - preconditions: - - sh: nfpm --version - msg: It appears nfpm is not installed. Please install using `go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest` cmds: - - nfpm pkg -f ./build/nfpm/nfpm.yaml -p arch -t ./bin/{{.APP_NAME}}.pkg.tar.zst - env: - GOARCH: '{{.ARCH | default ARCH}}' + - wails3 tool package -name {{.APP_NAME}} -format arch -config ./build/nfpm/nfpm.yaml generate:dotdesktop: summary: Generates a `.desktop` file diff --git a/v3/internal/commands/tool_package.go b/v3/internal/commands/tool_package.go index 66f3d2d251c..0ea07e79691 100644 --- a/v3/internal/commands/tool_package.go +++ b/v3/internal/commands/tool_package.go @@ -18,6 +18,10 @@ func ToolPackage(options *flags.ToolPackage) error { return fmt.Errorf("please provide a config file using the -config flag") } + if options.ExecutableName == "" { + return fmt.Errorf("please provide an executable name using the -name flag") + } + // Validate format var pkgType packager.PackageType switch strings.ToLower(options.Format) { @@ -43,7 +47,11 @@ func ToolPackage(options *flags.ToolPackage) error { } // Generate output filename based on format - outputFile := fmt.Sprintf("package.%s", options.Format) + if options.Format == "archlinux" { + // Arch linux packages are not .archlinux files, they are .pkg.tar.zst + options.Format = "pkg.tar.zst" + } + outputFile := fmt.Sprintf("./bin/%s.%s", options.ExecutableName, options.Format) // Create the package err = packager.CreatePackageFromConfig(pkgType, configPath, outputFile) diff --git a/v3/internal/flags/package.go b/v3/internal/flags/package.go index dfc8fb9debd..f4ffb99ebd8 100644 --- a/v3/internal/flags/package.go +++ b/v3/internal/flags/package.go @@ -4,6 +4,7 @@ package flags type ToolPackage struct { Common - Format string `name:"format" description:"Package format to generate (deb, rpm, archlinux)" default:"deb"` - ConfigPath string `name:"config" description:"Path to the package configuration file" default:""` + Format string `name:"format" description:"Package format to generate (deb, rpm, archlinux)" default:"deb"` + ExecutableName string `name:"name" description:"Name of the executable to package" default:"myapp"` + ConfigPath string `name:"config" description:"Path to the package configuration file" default:""` } From c2228039f69dcca09de1cd5424287817ca8da01a Mon Sep 17 00:00:00 2001 From: atterpac Date: Sat, 23 Nov 2024 21:56:11 -0700 Subject: [PATCH 15/20] add linux depdencies --- v3/internal/commands/build_assets/Taskfile.linux.yml | 3 +++ .../updatable_build_assets/nfpm/nfpm.yaml.tmpl | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/v3/internal/commands/build_assets/Taskfile.linux.yml b/v3/internal/commands/build_assets/Taskfile.linux.yml index 2b2a46a81e6..eb08fbdacb0 100644 --- a/v3/internal/commands/build_assets/Taskfile.linux.yml +++ b/v3/internal/commands/build_assets/Taskfile.linux.yml @@ -58,6 +58,7 @@ tasks: vars: PRODUCTION: "true" cmds: + - task: generate:dotdesktop - task: generate:deb create:rpm: @@ -67,6 +68,7 @@ tasks: vars: PRODUCTION: "true" cmds: + - task: generate:dotdesktop - task: generate:rpm create:aur: @@ -76,6 +78,7 @@ tasks: vars: PRODUCTION: "true" cmds: + - task: generate:dotdesktop - task: generate:aur generate:deb: diff --git a/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl b/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl index 4c37eb6774e..6900d00a7c4 100644 --- a/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl +++ b/v3/internal/commands/updatable_build_assets/nfpm/nfpm.yaml.tmpl @@ -21,14 +21,20 @@ contents: dst: "/usr/local/bin/{{.BinaryName}}" - src: "./build/appicon.png" dst: "/usr/share/icons/hicolor/128x128/apps/{{.BinaryName}}.png" + - src: "./build/{{.BinaryName}}.desktop" + dst: "/usr/share/applications/{{.BinaryName}}.desktop" + +depends: + - gtk3 + - libwebkit2gtk # replaces: # - foobar # provides: # - bar # depends: -# - foo -# - bar +# - gtk3 +# - libwebkit2gtk # recommends: # - whatever # suggests: From 2276b7384d68a80a7a57b772386ed95e63b62d1c Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 24 Nov 2024 18:23:55 +1100 Subject: [PATCH 16/20] Add some docs --- .../docs/en/getting-started/your-first-app.md | 38 ++++++++++- .../docs/en/learn/guides/packaging.md | 68 +++++++++++++++++++ mkdocs-website/mkdocs.yml | 3 +- 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 mkdocs-website/docs/en/learn/guides/packaging.md diff --git a/mkdocs-website/docs/en/getting-started/your-first-app.md b/mkdocs-website/docs/en/getting-started/your-first-app.md index 0cb65f9fa4f..2d0a9099261 100644 --- a/mkdocs-website/docs/en/getting-started/your-first-app.md +++ b/mkdocs-website/docs/en/getting-started/your-first-app.md @@ -79,6 +79,42 @@ You'll notice that the build time was faster this time. That's because the new b You should see a new executable in the `build` directory. +## Step 6: Packaging Your Application + +Once your application is ready for distribution, you can create platform-specific packages: + +=== "Mac" + + To create a `.app` bundle: + ```bash + wails3 package + ``` + This will create a production build and package it into a `.app` bundle in the `bin` directory. + +=== "Windows" + + To create an NSIS installer: + ```bash + wails3 package + ``` + This will create a production build and package it into an NSIS installer in the `bin` directory. + +=== "Linux" + + Wails supports multiple package formats for Linux distribution: + ```bash + # Create all package types (AppImage, deb, rpm, and Arch Linux) + wails3 package + + # Or create specific package types + wails3 task linux:create:appimage # AppImage format + wails3 task linux:create:deb # Debian package + wails3 task linux:create:rpm # Red Hat package + wails3 task linux:create:aur # Arch Linux package + ``` + +For more detailed information about packaging options and configuration, check out our [Packaging Guide](../learn/guides/packaging.md). + ## Conclusion -Congratulations! You've just created and built your first Wails application. This is just the beginning of what you can achieve with Wails v3 Alpha. Explore the documentation, experiment with different features, and start building amazing applications! +Congratulations! You've just created, developed and packaged your first Wails application. This is just the beginning of what you can achieve with Wails v3. Explore the documentation, experiment with different features, and start building amazing applications! diff --git a/mkdocs-website/docs/en/learn/guides/packaging.md b/mkdocs-website/docs/en/learn/guides/packaging.md new file mode 100644 index 00000000000..0ea4c4268de --- /dev/null +++ b/mkdocs-website/docs/en/learn/guides/packaging.md @@ -0,0 +1,68 @@ +# Packaging Your Application + +This guide explains how to package your Wails application for different platforms. + +## Windows + +Windows applications are packaged as `.exe` files. Wails automatically handles this during the build process, creating a standalone executable that includes all necessary resources. + +## macOS + +macOS applications are packaged as `.app` bundles. Wails creates these bundles automatically during the build process, including proper code signing and notarization if configured. + +## Linux + +Linux applications can be packaged in various formats. Wails v3 uses [nfpm](https://github.com/goreleaser/nfpm), an excellent packaging tool that makes it easy to create `.deb`, `.rpm`, and Arch Linux packages. nfpm is a powerful tool that handles the complexities of Linux packaging, making it easy to create professional-grade packages. + +### Package Types + +Wails supports creating the following types of Linux packages: +- Debian packages (`.deb`) - for Debian, Ubuntu, and related distributions +- Red Hat packages (`.rpm`) - for Red Hat, Fedora, CentOS, and related distributions +- Arch Linux packages - for Arch Linux and related distributions +- AppImage - a distribution-independent package format + +### Building Packages + +Wails provides several task commands for building Linux packages. These are defined in `Taskfile.linux.yml` and can be invoked using the `wails3 task` command: + +```bash +# Build all package types (AppImage, deb, rpm, and Arch Linux) +wails3 task linux:package + +# Build specific package types +wails3 task linux:create:appimage # Create an AppImage +wails3 task linux:create:deb # Create a Debian package +wails3 task linux:create:rpm # Create a Red Hat package +wails3 task linux:create:aur # Create an Arch Linux package +``` + +Each of these tasks will: +1. Build your application in production mode +2. Generate necessary desktop integration files +3. Create the appropriate package using nfpm + +### Configuration + +The package configuration file should follow the nfpm configuration format and is typically located at `build/nfpm/nfpm.yaml`. Here's an example: + +```yaml +name: "myapp" +arch: "amd64" +version: "v1.0.0" +maintainer: "Your Name " +description: | + A short description of your application +vendor: "Your Company" +homepage: "https://yourcompany.com" +license: "MIT" +contents: + - src: ./build/bin/myapp + dst: /usr/bin/myapp + - src: ./assets/icon.png + dst: /usr/share/icons/myapp.png + - src: ./assets/myapp.desktop + dst: /usr/share/applications/myapp.desktop +``` + +For detailed information about all available configuration options, please refer to the [nfpm configuration documentation](https://nfpm.goreleaser.com/configuration/). diff --git a/mkdocs-website/mkdocs.yml b/mkdocs-website/mkdocs.yml index 66d1745b3b9..8bdec59d739 100644 --- a/mkdocs-website/mkdocs.yml +++ b/mkdocs-website/mkdocs.yml @@ -153,6 +153,7 @@ nav: - Guides: - Customising Windows: learn/guides/customising-windows.md - File Associations: learn/guides/file-associations.md + - Packaging: learn/guides/packaging.md - Feedback: getting-started/feedback.md - Feedback: getting-started/feedback.md - What's New in v3?: whats-new.md @@ -175,4 +176,4 @@ watch: - overrides - shared copyright: - Copyright © 2024 Lea Anthony + Copyright 2024 Lea Anthony From 473bbfbdbbd8bf91f373deacecfe3f3f1368bfe1 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 24 Nov 2024 20:21:45 +1100 Subject: [PATCH 17/20] Fixed tests. Updated task to latest. --- v3/go.mod | 35 +++++++++------ v3/go.sum | 46 +++++++++++++++++++ v3/internal/commands/tool_package.go | 2 +- v3/internal/commands/tool_package_test.go | 55 +++++++++++++++++------ 4 files changed, 110 insertions(+), 28 deletions(-) diff --git a/v3/go.mod b/v3/go.mod index 88e87064376..b19d3beac1a 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -9,7 +9,7 @@ require ( github.com/ebitengine/purego v0.4.0-alpha.4 github.com/go-git/go-git/v5 v5.12.0 github.com/go-ole/go-ole v1.2.6 - github.com/go-task/task/v3 v3.35.1 + github.com/go-task/task/v3 v3.40.0 github.com/godbus/dbus/v5 v5.1.0 github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 @@ -32,9 +32,9 @@ require ( github.com/tc-hib/winres v0.3.1 github.com/wailsapp/go-webview2 v1.0.17 github.com/wailsapp/mimetype v1.4.1 - golang.org/x/sys v0.22.0 - golang.org/x/term v0.20.0 - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d + golang.org/x/sys v0.26.0 + golang.org/x/term v0.25.0 + golang.org/x/tools v0.23.0 gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.21.0 ) @@ -45,12 +45,14 @@ require ( dario.cat/mergo v1.0.1 // indirect github.com/AlekSi/pointer v1.2.0 // indirect github.com/BurntSushi/toml v1.3.2 // indirect + github.com/Ladicle/tabwriter v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect + github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect github.com/buger/jsonparser v1.1.1 // indirect @@ -59,15 +61,18 @@ require ( github.com/cloudflare/circl v1.3.8 // indirect github.com/containerd/console v1.0.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dlclark/regexp2 v1.11.0 // indirect + github.com/dominikbraun/graph v0.23.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-billy/v5 v5.6.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/go-task/template v0.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a // indirect @@ -86,16 +91,17 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.3 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/lithammer/fuzzysearch v1.1.5 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/mattn/go-zglob v0.0.4 // indirect + github.com/mattn/go-zglob v0.0.6 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/mango v0.1.0 // indirect github.com/muesli/mango-cobra v1.2.0 // indirect github.com/muesli/mango-pflag v0.1.0 // indirect @@ -115,16 +121,17 @@ require ( github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/ulikunitz/xz v0.5.12 // indirect + github.com/whilp/git-urls v1.0.0 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/image v0.21.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/text v0.19.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect @@ -139,5 +146,5 @@ require ( modernc.org/opt v0.1.3 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.1 // indirect - mvdan.cc/sh/v3 v3.8.0 // indirect + mvdan.cc/sh/v3 v3.10.0 // indirect ) diff --git a/v3/go.sum b/v3/go.sum index 42b8de7894c..750a8d926d1 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -14,6 +14,8 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9Dg= +github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= @@ -47,6 +49,8 @@ github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDO github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY= github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -81,11 +85,18 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= +github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/ebitengine/purego v0.4.0-alpha.4 h1:Y7yIV06Yo5M2BAdD7EVPhfp6LZ0tEcQo5770OhYUVes= @@ -98,6 +109,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -108,6 +121,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= +github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= @@ -123,6 +138,10 @@ github.com/go-task/task/v3 v3.31.0 h1:o6iyj9gPJXxvxPi/u/l8e025PmM2BqKgtLNPS2i7hV github.com/go-task/task/v3 v3.31.0/go.mod h1:/CPDAu9nS3+soqY/e1tTrSo/zxk76lnljEV9aBTeKrg= github.com/go-task/task/v3 v3.35.1 h1:zjQ3tLv+LIStDDTzOQx8F97NE/8FSTanjZuwgy/hwro= github.com/go-task/task/v3 v3.35.1/go.mod h1:7F6HetCXjlBkgxNjXeTKQYpsA5Q34k4fV94fWXq8GTY= +github.com/go-task/task/v3 v3.40.0 h1:1gKx+2UDz06Jtm0MBiN+EqVN87wWEyspuEze4LRGusk= +github.com/go-task/task/v3 v3.40.0/go.mod h1:Eb9p9TYX2LpNrd8rBL+Ceht7LzSqA+WniSFeHAJlsnI= +github.com/go-task/template v0.1.0 h1:ym/r2G937RZA1bsgiWedNnY9e5kxDT+3YcoAnuIetTE= +github.com/go-task/template v0.1.0/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -186,6 +205,8 @@ github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuOb github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -229,6 +250,8 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= +github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A= +github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -239,6 +262,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbYvWg= @@ -251,6 +276,7 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -281,6 +307,7 @@ github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4Ug github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= @@ -311,6 +338,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -328,6 +356,8 @@ github.com/wailsapp/go-webview2 v1.0.17 h1:DkLnUKqW7J///OBXkInMq1fzC88G6ZjHwKuHX github.com/wailsapp/go-webview2 v1.0.17/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= +github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU= +github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -351,10 +381,14 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= @@ -362,6 +396,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -372,6 +408,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -402,6 +440,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -411,6 +451,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -426,6 +468,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -477,3 +521,5 @@ mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= +mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4= +mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY= diff --git a/v3/internal/commands/tool_package.go b/v3/internal/commands/tool_package.go index 0ea07e79691..8e7718882b4 100644 --- a/v3/internal/commands/tool_package.go +++ b/v3/internal/commands/tool_package.go @@ -51,7 +51,7 @@ func ToolPackage(options *flags.ToolPackage) error { // Arch linux packages are not .archlinux files, they are .pkg.tar.zst options.Format = "pkg.tar.zst" } - outputFile := fmt.Sprintf("./bin/%s.%s", options.ExecutableName, options.Format) + outputFile := filepath.Join(filepath.Dir(configPath), "bin", fmt.Sprintf("%s.%s", options.ExecutableName, options.Format)) // Create the package err = packager.CreatePackageFromConfig(pkgType, configPath, outputFile) diff --git a/v3/internal/commands/tool_package_test.go b/v3/internal/commands/tool_package_test.go index d5af802f4a8..21d52962dab 100644 --- a/v3/internal/commands/tool_package_test.go +++ b/v3/internal/commands/tool_package_test.go @@ -20,8 +20,9 @@ func TestToolPackage(t *testing.T) { name: "should fail with invalid format", setup: func() (*flags.ToolPackage, func()) { return &flags.ToolPackage{ - Format: "invalid", - ConfigPath: "config.yaml", + Format: "invalid", + ConfigPath: "config.yaml", + ExecutableName: "myapp", }, func() {} }, wantErr: true, @@ -31,8 +32,9 @@ func TestToolPackage(t *testing.T) { name: "should fail with missing config file", setup: func() (*flags.ToolPackage, func()) { return &flags.ToolPackage{ - Format: "deb", - ConfigPath: "nonexistent.yaml", + Format: "deb", + ConfigPath: "nonexistent.yaml", + ExecutableName: "myapp", }, func() {} }, wantErr: true, @@ -49,10 +51,19 @@ func TestToolPackage(t *testing.T) { t.Fatal(err) } + // Create bin directory + err = os.MkdirAll(filepath.Join(dir, "bin"), 0755) + if err != nil { + t.Fatal(err) + } + return &flags.ToolPackage{ - Format: "DEB", - ConfigPath: configPath, - }, func() {} + Format: "DEB", + ConfigPath: configPath, + ExecutableName: "myapp", + }, func() { + os.RemoveAll(filepath.Join(dir, "bin")) + } }, wantErr: false, }, @@ -67,10 +78,19 @@ func TestToolPackage(t *testing.T) { t.Fatal(err) } + // Create bin directory + err = os.MkdirAll(filepath.Join(dir, "bin"), 0755) + if err != nil { + t.Fatal(err) + } + return &flags.ToolPackage{ - Format: "RPM", - ConfigPath: configPath, - }, func() {} + Format: "RPM", + ConfigPath: configPath, + ExecutableName: "myapp", + }, func() { + os.RemoveAll(filepath.Join(dir, "bin")) + } }, wantErr: false, }, @@ -85,10 +105,19 @@ func TestToolPackage(t *testing.T) { t.Fatal(err) } + // Create bin directory + err = os.MkdirAll(filepath.Join(dir, "bin"), 0755) + if err != nil { + t.Fatal(err) + } + return &flags.ToolPackage{ - Format: "ARCHLINUX", - ConfigPath: configPath, - }, func() {} + Format: "ARCHLINUX", + ConfigPath: configPath, + ExecutableName: "myapp", + }, func() { + os.RemoveAll(filepath.Join(dir, "bin")) + } }, wantErr: false, }, From bd568e618911ee393e71281796363d9040e8c27a Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sun, 24 Nov 2024 20:41:54 +1100 Subject: [PATCH 18/20] Update v3/internal/commands/tool_package.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- v3/internal/commands/tool_package.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/v3/internal/commands/tool_package.go b/v3/internal/commands/tool_package.go index 8e7718882b4..c631352a501 100644 --- a/v3/internal/commands/tool_package.go +++ b/v3/internal/commands/tool_package.go @@ -42,8 +42,10 @@ func ToolPackage(options *flags.ToolPackage) error { } // Check if config file exists - if _, err := os.Stat(configPath); err != nil { + if info, err := os.Stat(configPath); err != nil { return fmt.Errorf("config file not found: %s", configPath) + } else if info.Mode().Perm()&0444 == 0 { + return fmt.Errorf("config file is not readable: %s", configPath) } // Generate output filename based on format From 0f2bd0ee742ecf7a13bdca01236608304ce5c980 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 30 Nov 2024 13:21:17 +1100 Subject: [PATCH 19/20] Remove doctor references to nfpm --- v3/internal/doctor/packagemanager/apt.go | 3 --- v3/internal/doctor/packagemanager/dnf.go | 3 --- v3/internal/doctor/packagemanager/emerge.go | 3 --- v3/internal/doctor/packagemanager/eopkg.go | 3 --- v3/internal/doctor/packagemanager/nixpkgs.go | 3 --- .../doctor/packagemanager/packagemanager.go | 21 ------------------- v3/internal/doctor/packagemanager/pacman.go | 3 --- v3/internal/doctor/packagemanager/zypper.go | 3 --- 8 files changed, 42 deletions(-) diff --git a/v3/internal/doctor/packagemanager/apt.go b/v3/internal/doctor/packagemanager/apt.go index 1f46db46970..d7d43ea3566 100644 --- a/v3/internal/doctor/packagemanager/apt.go +++ b/v3/internal/doctor/packagemanager/apt.go @@ -40,9 +40,6 @@ func (a *Apt) Packages() Packagemap { "npm": []*Package{ {Name: "npm", SystemPackage: true}, }, - "nfpm": []*Package{ - {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } diff --git a/v3/internal/doctor/packagemanager/dnf.go b/v3/internal/doctor/packagemanager/dnf.go index 223845dd0a6..7c5be417924 100644 --- a/v3/internal/doctor/packagemanager/dnf.go +++ b/v3/internal/doctor/packagemanager/dnf.go @@ -43,9 +43,6 @@ func (y *Dnf) Packages() Packagemap { {Name: "npm", SystemPackage: true}, {Name: "nodejs-npm", SystemPackage: true}, }, - "nfpm*": []*Package{ - {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } diff --git a/v3/internal/doctor/packagemanager/emerge.go b/v3/internal/doctor/packagemanager/emerge.go index aae18e8da06..33c78a2e6b3 100644 --- a/v3/internal/doctor/packagemanager/emerge.go +++ b/v3/internal/doctor/packagemanager/emerge.go @@ -41,9 +41,6 @@ func (e *Emerge) Packages() Packagemap { "npm": []*Package{ {Name: "net-libs/nodejs", SystemPackage: true}, }, - "nfpm": []*Package{ - {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } diff --git a/v3/internal/doctor/packagemanager/eopkg.go b/v3/internal/doctor/packagemanager/eopkg.go index 8f7d0df1d7f..060e5959537 100644 --- a/v3/internal/doctor/packagemanager/eopkg.go +++ b/v3/internal/doctor/packagemanager/eopkg.go @@ -41,9 +41,6 @@ func (e *Eopkg) Packages() Packagemap { "npm": []*Package{ {Name: "nodejs", SystemPackage: true}, }, - "nfpm": []*Package{ - {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } diff --git a/v3/internal/doctor/packagemanager/nixpkgs.go b/v3/internal/doctor/packagemanager/nixpkgs.go index 6d39a53a27c..4141de05676 100644 --- a/v3/internal/doctor/packagemanager/nixpkgs.go +++ b/v3/internal/doctor/packagemanager/nixpkgs.go @@ -55,9 +55,6 @@ func (n *Nixpkgs) Packages() Packagemap { "npm": []*Package{ {Name: channel + ".nodejs", SystemPackage: true}, }, - "nfpm": []*Package{ - {Name: channel + ".nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } diff --git a/v3/internal/doctor/packagemanager/packagemanager.go b/v3/internal/doctor/packagemanager/packagemanager.go index 3d95291613d..800b05f7a93 100644 --- a/v3/internal/doctor/packagemanager/packagemanager.go +++ b/v3/internal/doctor/packagemanager/packagemanager.go @@ -134,10 +134,6 @@ func AppVersion(name string) string { return npmVersion() } - if name == "nfpm" { - return nfpmVersion() - } - return "" } @@ -171,20 +167,3 @@ func npmVersion() string { version, _ := execCmd("npm", "--version") return strings.TrimSpace(version) } - -func nfpmVersion() string { - output, _ := execCmd("nfpm", "--version") - lines := strings.Split(output, "\n") - for _, line := range lines { - if strings.HasPrefix(line, "GitVersion:") { - version := strings.TrimSpace(strings.TrimPrefix(line, "GitVersion:")) - return version - } - } - return "unknown" -} - -func isNfpmInstalled() bool { - _, err := exec.LookPath("nfpm") - return err == nil -} diff --git a/v3/internal/doctor/packagemanager/pacman.go b/v3/internal/doctor/packagemanager/pacman.go index 131a6a8b685..e785901e930 100644 --- a/v3/internal/doctor/packagemanager/pacman.go +++ b/v3/internal/doctor/packagemanager/pacman.go @@ -41,9 +41,6 @@ func (p *Pacman) Packages() Packagemap { "npm": []*Package{ {Name: "npm", SystemPackage: true}, }, - "nfpm": []*Package{ - {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } diff --git a/v3/internal/doctor/packagemanager/zypper.go b/v3/internal/doctor/packagemanager/zypper.go index 3a350e89578..da3cb200e8b 100644 --- a/v3/internal/doctor/packagemanager/zypper.go +++ b/v3/internal/doctor/packagemanager/zypper.go @@ -44,9 +44,6 @@ func (z *Zypper) Packages() Packagemap { "npm": []*Package{ {Name: "npm10", SystemPackage: true}, }, - "nfpm": []*Package{ - {Name: "nfpm", SystemPackage: false, InstallCheck: isNfpmInstalled, InstallCommand: "go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest", Optional: true}, - }, } } From ac210d9ef23093703c2dca9f838b4ac08582ddd5 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 30 Nov 2024 14:03:33 +1100 Subject: [PATCH 20/20] Fix bugs --- v3/examples/window/main.go | 16 ++- v3/go.mod | 18 +-- v3/go.sum | 118 +++++--------------- v3/internal/commands/build-assets.go | 8 +- v3/internal/commands/tool_package_test.go | 36 +++--- v3/pkg/application/keys_linux.go | 5 +- v3/pkg/application/linux_cgo.go | 35 +++--- v3/pkg/application/messageprocessor.go | 2 +- v3/pkg/application/webview_panel.go | 4 +- v3/pkg/application/webview_panel_darwin.go | 2 +- v3/pkg/application/webview_panel_options.go | 4 - v3/pkg/application/webview_window_darwin.go | 32 ++++-- v3/pkg/application/window.go | 2 + 13 files changed, 114 insertions(+), 168 deletions(-) diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go index ae906be70cc..15cad7cef0f 100644 --- a/v3/examples/window/main.go +++ b/v3/examples/window/main.go @@ -120,6 +120,20 @@ func main() { Show() windowCounter++ }) + if runtime.GOOS == "darwin" { + myMenu.Add("New Panel Window").SetAccelerator("CmdOrCtrl+P").OnClick(func(ctx *application.Context) { + app.NewWebviewPanelWithOptions(application.WebviewPanelOptions{ + Floating: true, + ShouldClose: nil, + KeyBindings: nil, + }). + SetTitle("PanelWindow "+strconv.Itoa(windowCounter)). + SetRelativePosition(rand.Intn(1000), rand.Intn(800)). + SetURL("https://wails.io"). + Show() + windowCounter++ + }) + } if runtime.GOOS != "linux" { myMenu.Add("New WebviewWindow (Disable Minimise)"). OnClick(func(ctx *application.Context) { @@ -496,7 +510,7 @@ func main() { }) }) positionMenu.Add("Set Relative Position (Corner)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { + currentWindow(func(w application.Window) { screen, _ := w.GetScreen() w.SetRelativePosition(screen.WorkArea.Width-w.Width(), screen.WorkArea.Height-w.Height()) }) diff --git a/v3/go.mod b/v3/go.mod index 5e9928d3cb5..352a1e9c8f8 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -14,6 +14,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.4.0 + github.com/goreleaser/nfpm/v2 v2.41.1 github.com/jackmordaunt/icns/v2 v2.2.7 github.com/jaypipes/ghw v0.12.0 github.com/leaanthony/clir v1.6.0 @@ -32,9 +33,9 @@ require ( github.com/tc-hib/winres v0.3.1 github.com/wailsapp/go-webview2 v1.0.18-0.20241130004144-dd8667af33c1 github.com/wailsapp/mimetype v1.4.1 + golang.org/x/sys v0.27.0 golang.org/x/term v0.25.0 golang.org/x/tools v0.23.0 - golang.org/x/sys v0.27.0 gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.21.0 ) @@ -53,14 +54,10 @@ require ( github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect - github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect - github.com/buger/jsonparser v1.1.1 // indirect - github.com/caarlos0/go-version v0.1.1 // indirect github.com/cavaliergopher/cpio v1.0.1 // indirect github.com/cloudflare/circl v1.3.8 // indirect github.com/containerd/console v1.0.4 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect @@ -79,11 +76,8 @@ require ( github.com/gookit/color v1.5.2 // indirect github.com/goreleaser/chglog v0.6.1 // indirect github.com/goreleaser/fileglob v1.3.0 // indirect - github.com/goreleaser/nfpm/v2 v2.41.1 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.16 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/invopop/jsonschema v0.12.0 // indirect github.com/jaypipes/pcidb v1.0.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect @@ -94,7 +88,6 @@ require ( github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/lithammer/fuzzysearch v1.1.5 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-zglob v0.0.6 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -102,27 +95,20 @@ require ( github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect - github.com/muesli/mango v0.1.0 // indirect - github.com/muesli/mango-cobra v1.2.0 // indirect - github.com/muesli/mango-pflag v0.1.0 // indirect - github.com/muesli/roff v0.1.0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/radovskyb/watcher v1.0.7 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rjeczalik/notify v0.9.3 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sajari/fuzzy v1.0.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/skeema/knownhosts v1.2.2 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/ulikunitz/xz v0.5.12 // indirect github.com/whilp/git-urls v1.0.0 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect diff --git a/v3/go.sum b/v3/go.sum index 614c68ae100..21d68b42399 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -4,8 +4,6 @@ atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4= atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/keyboard v0.2.8 h1:Di09BitwZgdTV1hPyX/b9Cqxi8HVuJQwWivnZUEqlj4= atomicgo.dev/keyboard v0.2.8/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w= @@ -28,8 +26,6 @@ github.com/MarvinJWendt/testza v0.5.1/go.mod h1:L7csM8IBqCc0HH4TRYZSPCIRg6zJeqzM github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= @@ -37,8 +33,6 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= @@ -49,8 +43,12 @@ github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDO github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY= github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4= +github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= +github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -58,36 +56,23 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/atterpac/refresh v0.8.3 h1:Xj0rtd6Wfv/u03wZOdauASBOPxGZOJeik065S0wISNg= github.com/atterpac/refresh v0.8.3/go.mod h1:fJpWySLdpbANS8Ej5OvfZVZIVvi/9bmnhTjKS5EjQes= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/caarlos0/go-version v0.1.1 h1:1bikKHkGGVIIxqCmufhSSs3hpBScgHGacrvsi8FuIfc= -github.com/caarlos0/go-version v0.1.1/go.mod h1:Ze5Qx4TsBBi5FyrSKVg1Ibc44KGV/llAaKGp86oTwZ0= +github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8= github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk= github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -105,39 +90,29 @@ github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcej github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-task/task/v3 v3.31.0 h1:o6iyj9gPJXxvxPi/u/l8e025PmM2BqKgtLNPS2i7hV4= -github.com/go-task/task/v3 v3.31.0/go.mod h1:/CPDAu9nS3+soqY/e1tTrSo/zxk76lnljEV9aBTeKrg= -github.com/go-task/task/v3 v3.35.1 h1:zjQ3tLv+LIStDDTzOQx8F97NE/8FSTanjZuwgy/hwro= -github.com/go-task/task/v3 v3.35.1/go.mod h1:7F6HetCXjlBkgxNjXeTKQYpsA5Q34k4fV94fWXq8GTY= github.com/go-task/task/v3 v3.40.0 h1:1gKx+2UDz06Jtm0MBiN+EqVN87wWEyspuEze4LRGusk= github.com/go-task/task/v3 v3.40.0/go.mod h1:Eb9p9TYX2LpNrd8rBL+Ceht7LzSqA+WniSFeHAJlsnI= github.com/go-task/template v0.1.0 h1:ym/r2G937RZA1bsgiWedNnY9e5kxDT+3YcoAnuIetTE= @@ -157,29 +132,27 @@ github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/goreleaser/chglog v0.6.1 h1:NZKiX8l0FTQPRzBgKST7knvNZmZ04f7PEGkN2wInfhE= github.com/goreleaser/chglog v0.6.1/go.mod h1:Bnnfo07jMZkaAb0uRNASMZyOsX6ROW6X1qbXqN3guUo= github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I= github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU= github.com/goreleaser/nfpm/v2 v2.41.1 h1:4tyZ9b817msLuyGKw53ed3suZNApkGHVZDekdGe8ZEE= github.com/goreleaser/nfpm/v2 v2.41.1/go.mod h1:VPc5kF5OgfA+BosV/A2aB+Vg34honjWvp0Vt8ogsSi0= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= -github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/jackmordaunt/icns/v2 v2.2.7 h1:K/RbfvuzjmjVY5y4g+XENRs8ZZatwz4YnLHypa2KwQg= github.com/jackmordaunt/icns/v2 v2.2.7/go.mod h1:ovoTxGguSuoUGKMk5Nn3R7L7BgMQkylsO+bblBuI22A= github.com/jaypipes/ghw v0.12.0 h1:xU2/MDJfWmBhJnujHY9qwXQLs3DBsf0/Xa9vECY0Tho= @@ -193,7 +166,8 @@ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEE github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= @@ -203,8 +177,6 @@ github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= @@ -234,8 +206,6 @@ github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMr github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q= github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -248,8 +218,6 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= -github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A= github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -264,19 +232,10 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= -github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= -github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbYvWg= -github.com/muesli/mango-cobra v1.2.0/go.mod h1:vMJL54QytZAJhCT13LPVDfkvCUJ5/4jNUKF/8NC2UjA= -github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg= -github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0= -github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= -github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -304,41 +263,35 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= +github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -358,8 +311,6 @@ github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhw github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU= github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= @@ -379,14 +330,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= -golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -394,8 +339,6 @@ golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -406,8 +349,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -429,7 +370,6 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -447,8 +387,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -464,8 +402,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -515,9 +451,5 @@ modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= -mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= -mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= -mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= -mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4= mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY= diff --git a/v3/internal/commands/build-assets.go b/v3/internal/commands/build-assets.go index 19105f6cf39..5f5dedff0ce 100644 --- a/v3/internal/commands/build-assets.go +++ b/v3/internal/commands/build-assets.go @@ -127,10 +127,10 @@ type WailsConfig struct { CompanyName string `yaml:"companyName"` ProductName string `yaml:"productName"` ProductIdentifier string `yaml:"productIdentifier"` - Description string `yaml:"description"` - Copyright string `yaml:"copyright"` - Comments string `yaml:"comments"` - Version string `yaml:"version"` + Description string `yaml:"description"` + Copyright string `yaml:"copyright"` + Comments string `yaml:"comments"` + Version string `yaml:"version"` } `yaml:"info"` FileAssociations []FileAssociation `yaml:"fileAssociations"` } diff --git a/v3/internal/commands/tool_package_test.go b/v3/internal/commands/tool_package_test.go index 21d52962dab..7db09f08bd3 100644 --- a/v3/internal/commands/tool_package_test.go +++ b/v3/internal/commands/tool_package_test.go @@ -58,12 +58,12 @@ func TestToolPackage(t *testing.T) { } return &flags.ToolPackage{ - Format: "DEB", - ConfigPath: configPath, - ExecutableName: "myapp", - }, func() { - os.RemoveAll(filepath.Join(dir, "bin")) - } + Format: "DEB", + ConfigPath: configPath, + ExecutableName: "myapp", + }, func() { + os.RemoveAll(filepath.Join(dir, "bin")) + } }, wantErr: false, }, @@ -85,12 +85,12 @@ func TestToolPackage(t *testing.T) { } return &flags.ToolPackage{ - Format: "RPM", - ConfigPath: configPath, - ExecutableName: "myapp", - }, func() { - os.RemoveAll(filepath.Join(dir, "bin")) - } + Format: "RPM", + ConfigPath: configPath, + ExecutableName: "myapp", + }, func() { + os.RemoveAll(filepath.Join(dir, "bin")) + } }, wantErr: false, }, @@ -112,12 +112,12 @@ func TestToolPackage(t *testing.T) { } return &flags.ToolPackage{ - Format: "ARCHLINUX", - ConfigPath: configPath, - ExecutableName: "myapp", - }, func() { - os.RemoveAll(filepath.Join(dir, "bin")) - } + Format: "ARCHLINUX", + ConfigPath: configPath, + ExecutableName: "myapp", + }, func() { + os.RemoveAll(filepath.Join(dir, "bin")) + } }, wantErr: false, }, diff --git a/v3/pkg/application/keys_linux.go b/v3/pkg/application/keys_linux.go index e7b44e380e9..d6c92ad835c 100644 --- a/v3/pkg/application/keys_linux.go +++ b/v3/pkg/application/keys_linux.go @@ -15,7 +15,7 @@ var VirtualKeyCodes = map[uint]string{ 0xffff: "delete", 0xff50: "home", 0xff51: "left", - + 0xffe1: "lshift", 0xffe2: "rshift", 0xffe3: "lcontrol", @@ -51,7 +51,6 @@ var VirtualKeyCodes = map[uint]string{ 0xff57: "end", 0xff58: "begin", - // Alphabet 0x41: "a", 0x42: "b", @@ -160,6 +159,4 @@ var VirtualKeyCodes = map[uint]string{ 0xffd3: "f22", 0xffd4: "f23", 0xffd5: "f24", - - } diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index ac9465b9dce..0f6ae0b3ea9 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -482,12 +482,12 @@ func clipboardGet() string { func clipboardSet(text string) { cText := C.CString(text) + defer C.free(unsafe.Pointer(cText)) clip := C.gtk_clipboard_get(C.GDK_SELECTION_CLIPBOARD) C.gtk_clipboard_set_text(clip, cText, -1) clip = C.gtk_clipboard_get(C.GDK_SELECTION_PRIMARY) C.gtk_clipboard_set_text(clip, cText, -1) - C.free(unsafe.Pointer(cText)) } // Menu @@ -662,10 +662,10 @@ func menuItemSetDisabled(widget pointer, disabled bool) { func menuItemSetLabel(widget pointer, label string) { value := C.CString(label) + defer C.free(unsafe.Pointer(value)) C.gtk_menu_item_set_label( (*C.GtkMenuItem)(widget), value) - C.free(unsafe.Pointer(value)) } func menuItemRemoveBitmap(widget pointer) { @@ -710,10 +710,11 @@ func menuItemSetBitmap(widget pointer, bitmap []byte) { func menuItemSetToolTip(widget pointer, tooltip string) { value := C.CString(tooltip) + defer C.free(unsafe.Pointer(value)) + C.gtk_widget_set_tooltip_text( (*C.GtkWidget)(widget), value) - C.free(unsafe.Pointer(value)) } func menuItemSignalBlock(widget pointer, handlerId uint, block bool) { @@ -827,15 +828,18 @@ func (w *linuxWebviewWindow) enableDND() { func (w *linuxWebviewWindow) execJS(js string) { value := C.CString(js) + defer C.free(unsafe.Pointer(value)) + blank := C.CString("") + defer C.free(unsafe.Pointer(blank)) C.webkit_web_view_evaluate_javascript(w.webKitWebView(), value, C.long(len(js)), nil, - C.CString(""), + blank, nil, nil, nil) - C.free(unsafe.Pointer(value)) + } func getMousePosition() (int, int, *Screen) { @@ -1105,6 +1109,7 @@ func (w *linuxWebviewWindow) setBackgroundColour(colour RGBA) { colour.Alpha = 255 cssStr := C.CString(fmt.Sprintf("#webview-box {background-color: rgba(%d, %d, %d, %1.1f);}", colour.Red, colour.Green, colour.Blue, float32(colour.Alpha)/255.0)) + defer C.free(unsafe.Pointer(cssStr)) provider := C.gtk_css_provider_new() C.gtk_style_context_add_provider( C.gtk_widget_get_style_context((*C.GtkWidget)(w.vbox)), @@ -1112,7 +1117,6 @@ func (w *linuxWebviewWindow) setBackgroundColour(colour RGBA) { C.GTK_STYLE_PROVIDER_PRIORITY_USER) C.g_object_unref(C.gpointer(provider)) C.gtk_css_provider_load_from_data(provider, cssStr, -1, nil) - C.free(unsafe.Pointer(cssStr)) } func getPrimaryScreen() (*Screen, error) { @@ -1185,8 +1189,8 @@ func (w *linuxWebviewWindow) flash(_ bool) { func (w *linuxWebviewWindow) setTitle(title string) { if !w.parent.options.Frameless { cTitle := C.CString(title) + defer C.free(unsafe.Pointer(cTitle)) C.gtk_window_set_title(w.gtkWindow(), cTitle) - C.free(unsafe.Pointer(cTitle)) } } @@ -1212,8 +1216,8 @@ func (w *linuxWebviewWindow) setTransparent() { func (w *linuxWebviewWindow) setURL(uri string) { target := C.CString(uri) + defer C.free(unsafe.Pointer(target)) C.webkit_web_view_load_uri(w.webKitWebView(), target) - C.free(unsafe.Pointer(target)) } //export emit @@ -1369,8 +1373,8 @@ func (w *linuxWebviewWindow) zoomReset() { func (w *linuxWebviewWindow) reload() { uri := C.CString("wails://") + defer C.free(unsafe.Pointer(uri)) C.webkit_web_view_load_uri(w.webKitWebView(), uri) - C.free(unsafe.Pointer(uri)) } func (w *linuxWebviewWindow) setZoom(zoom float64) { @@ -1481,8 +1485,9 @@ func onUriList(extracted **C.char, data unsafe.Pointer) { } } -var debounceTimer *time.Timer +var debounceTimer *time.Timer var isDebouncing bool = false + //export onKeyPressEvent func onKeyPressEvent(_ *C.GtkWidget, event *C.GdkEventKey, userData C.uintptr_t) C.gboolean { // Keypress re-emits if the key is pressed over a certain threshold so we need a debounce @@ -1617,12 +1622,14 @@ func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden b gtkFilters := []*C.GtkFileFilter{} for _, filter := range filters { f := C.gtk_file_filter_new() + displayStr := C.CString(filter.DisplayName) - C.gtk_file_filter_set_name(f, displayStr) - C.free(unsafe.Pointer(displayStr)) + defer C.free(unsafe.Pointer(displayStr)) patternStr := C.CString(filter.Pattern) + defer C.free(unsafe.Pointer(patternStr)) + + C.gtk_file_filter_set_name(f, displayStr) C.gtk_file_filter_add_pattern(f, patternStr) - C.free(unsafe.Pointer(patternStr)) C.gtk_file_chooser_add_filter((*C.GtkFileChooser)(fc), f) gtkFilters = append(gtkFilters, f) } @@ -1638,10 +1645,10 @@ func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden b if currentFolder != "" { path := C.CString(currentFolder) + defer C.free(unsafe.Pointer(path)) C.gtk_file_chooser_set_current_folder( (*C.GtkFileChooser)(fc), path) - C.free(unsafe.Pointer(path)) } // FIXME: This should be consolidated - duplicate exists in linux_purego.go diff --git a/v3/pkg/application/messageprocessor.go b/v3/pkg/application/messageprocessor.go index 62d7950dc3c..dd47ddf17c4 100644 --- a/v3/pkg/application/messageprocessor.go +++ b/v3/pkg/application/messageprocessor.go @@ -28,7 +28,7 @@ const ( ) type MessageProcessor struct { - logger *slog.Logger + logger *slog.Logger runningCalls map[string]context.CancelFunc l sync.Mutex diff --git a/v3/pkg/application/webview_panel.go b/v3/pkg/application/webview_panel.go index 7779c351681..743ffe9505a 100644 --- a/v3/pkg/application/webview_panel.go +++ b/v3/pkg/application/webview_panel.go @@ -12,7 +12,7 @@ type WebviewPanel struct { options WebviewPanelOptions impl webviewPanelImpl // keyBindings holds the keybindings for the panel - keyBindings map[string]func(*WebviewPanel) + keyBindings map[string]func(*WebviewPanel) } // NewPanel creates a new panel with the given options @@ -22,7 +22,7 @@ func NewPanel(options WebviewPanelOptions) *WebviewPanel { result := &WebviewPanel{ WebviewWindow: window, - options: options, + options: options, } // Process keybindings specific to the WebviewPanel diff --git a/v3/pkg/application/webview_panel_darwin.go b/v3/pkg/application/webview_panel_darwin.go index dc04db27b32..b7d56e82cf0 100644 --- a/v3/pkg/application/webview_panel_darwin.go +++ b/v3/pkg/application/webview_panel_darwin.go @@ -38,7 +38,7 @@ type macosWebviewPanel struct { func newPanelImpl(parent *WebviewPanel) *macosWebviewPanel { result := &macosWebviewPanel{ macosWebviewWindow: newWindowImpl(parent.WebviewWindow), - parent: parent, + parent: parent, } return result } diff --git a/v3/pkg/application/webview_panel_options.go b/v3/pkg/application/webview_panel_options.go index 23ce1528c6c..241b2b87788 100644 --- a/v3/pkg/application/webview_panel_options.go +++ b/v3/pkg/application/webview_panel_options.go @@ -17,10 +17,6 @@ type WebviewPanelOptions struct { KeyBindings map[string]func(panel *WebviewPanel) } -var WebviewPanelDefaults = &WebviewPanelOptions{ - WebviewWindowOptions: *WebviewWindowDefaults, -} - func processKeyBindingOptionsForPanel(keyBindings map[string]func(panel *WebviewPanel), windowKeyBindings map[string]func(panel *WebviewWindow)) map[string]func(panel *WebviewPanel) { result := make(map[string]func(panel *WebviewPanel)) diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index 6e0799109a8..31cee2e3982 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -243,12 +243,16 @@ func (w *macosWebviewWindow) execJS(js string) { if w.nsWindow == nil { return } - C.windowExecJS(w.nsWindow, C.CString(js)) + cJS := C.CString(js) + defer C.free(unsafe.Pointer(cJS)) + C.windowExecJS(w.nsWindow, cJS) }) } func (w *macosWebviewWindow) setURL(uri string) { - C.navigationLoadURL(w.nsWindow, C.CString(uri)) + cURI := C.CString(uri) + defer C.free(unsafe.Pointer(cURI)) + C.navigationLoadURL(w.nsWindow, cURI) } func (w *macosWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) { @@ -268,6 +272,7 @@ func newWindowImpl(parent *WebviewWindow) *macosWebviewWindow { func (w *macosWebviewWindow) setTitle(title string) { if !w.parent.options.Frameless { cTitle := C.CString(title) + defer C.free(unsafe.Pointer(cTitle)) C.windowSetTitle(w.nsWindow, cTitle) } } @@ -446,7 +451,9 @@ func (w *macosWebviewWindow) setup(options *WebviewWindowOptions, macOptions *Ma } if macOptions.Appearance != "" { - C.windowSetAppearanceTypeByName(w.nsWindow, C.CString(string(macOptions.Appearance))) + cAppearance := C.CString(string(macOptions.Appearance)) + defer C.free(unsafe.Pointer(cAppearance)) + C.windowSetAppearanceTypeByName(w.nsWindow, cAppearance) } if macOptions.InvisibleTitleBarHeight != 0 { @@ -463,10 +470,10 @@ func (w *macosWebviewWindow) setup(options *WebviewWindowOptions, macOptions *Ma case WindowStateNormal: } if w.parent.options.InitialPosition == WindowCentered { - C.windowCenter(w.nsWindow) - } else { - w.setPosition(options.X, options.Y) - } + C.windowCenter(w.nsWindow) + } else { + w.setPosition(options.X, options.Y) + } startURL, err := assetserver.GetStartURL(options.URL) if err != nil { @@ -482,16 +489,20 @@ func (w *macosWebviewWindow) setup(options *WebviewWindowOptions, macOptions *Ma w.execJS(options.JS) } if options.CSS != "" { - C.windowInjectCSS(w.nsWindow, C.CString(options.CSS)) + cCSS := C.CString(options.CSS) + C.windowInjectCSS(w.nsWindow, cCSS) + C.free(unsafe.Pointer(cCSS)) } if !options.Hidden { w.parent.Show() - w.setHasShadow(!options.Mac.DisableShadow)w.setAlwaysOnTop(options.AlwaysOnTop) + w.setHasShadow(!options.Mac.DisableShadow) + w.setAlwaysOnTop(options.AlwaysOnTop) } else { // We have to wait until the window is shown before we can remove the shadow var cancel func() cancel = w.parent.OnWindowEvent(events.Mac.WindowDidBecomeKey, func(_ *WindowEvent) { - w.setHasShadow(!options.Mac.DisableShadow)w.setAlwaysOnTop(options.AlwaysOnTop) + w.setHasShadow(!options.Mac.DisableShadow) + w.setAlwaysOnTop(options.AlwaysOnTop) cancel() }) } @@ -586,6 +597,7 @@ func (w *macosWebviewWindow) destroy() { func (w *macosWebviewWindow) setHTML(html string) { // Convert HTML to C string cHTML := C.CString(html) + defer C.free(unsafe.Pointer(cHTML)) // Render HTML C.windowRenderHTML(w.nsWindow, cHTML) } diff --git a/v3/pkg/application/window.go b/v3/pkg/application/window.go index f3fe06cf415..6604a373aea 100644 --- a/v3/pkg/application/window.go +++ b/v3/pkg/application/window.go @@ -12,6 +12,8 @@ type Callback interface { } type Window interface { + Bounds() Rect + SetBounds(bounds Rect) Callback Center() Close()