mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
Merge 7304725e04 into bb4fbf9574
This commit is contained in:
commit
688e05fcf6
6 changed files with 270 additions and 144 deletions
|
|
@ -828,8 +828,9 @@ Controls how the window behaves across macOS Spaces and fullscreen. These are bi
|
|||
- `MacWindowCollectionBehaviorFullScreenAllowsTiling` - Allows side-by-side tiling (macOS 10.11+)
|
||||
- `MacWindowCollectionBehaviorFullScreenDisallowsTiling` - Prevents tiling (macOS 10.11+)
|
||||
|
||||
**Example - Spotlight-like window:**
|
||||
**Note:** MacWindowClassWindow fullscreen overlay requires `application.Options{ Mac: application.MacOptions{ ActivationPolicy: application.ActivationPolicyAccessory } }`
|
||||
|
||||
**Example - Spotlight-like window:**
|
||||
```go
|
||||
// Window that appears on all Spaces AND can overlay fullscreen apps
|
||||
Mac: application.MacWindow{
|
||||
|
|
@ -848,6 +849,32 @@ Mac: application.MacWindow{
|
|||
},
|
||||
```
|
||||
|
||||
**WindowClass** (`MacWindowClass`)
|
||||
- `MacWindowClassWindow` - Standard window (default)
|
||||
- `MacWindowClassPanel` - Auxiliary window that can float above other windows and receive input without activating the application
|
||||
|
||||
**PanelPreferences** (`MacPanelPreferences`)
|
||||
|
||||
Preferences for MacWindowClassPanel windows (only applies when `WindowClass` is `MacWindowClassPanel`):
|
||||
- `FloatingPanel` - Panel floats above other windows
|
||||
- `BecomesKeyOnlyIfNeeded` - Panel becomes key only when needed
|
||||
- `NonactivatingPanel` - Panel receives input without activating the application
|
||||
- `UtilityWindow` - Panel uses utility window style
|
||||
|
||||
**Note:** Unlike MacWindowClassWindow, MacWindowClassPanel fullscreen overlay does NOT require `application.Options{ Mac: application.MacOptions{ ActivationPolicy: application.ActivationPolicyAccessory } }`
|
||||
|
||||
**Example - Spotlight-like panel:**
|
||||
```go
|
||||
Mac: application.MacWindow{
|
||||
WindowClass: application.MacWindowClassPanel,
|
||||
PanelPreferences: application.MacPanelPreferences{
|
||||
NonactivatingPanel: true,
|
||||
},
|
||||
CollectionBehavior: application.MacWindowCollectionBehaviorCanJoinAllSpaces |
|
||||
application.MacWindowCollectionBehaviorFullScreenAuxiliary,
|
||||
},
|
||||
```
|
||||
|
||||
### Windows Options
|
||||
|
||||
```go
|
||||
|
|
|
|||
|
|
@ -21,114 +21,134 @@ struct WebviewPreferences {
|
|||
bool *AllowsBackForwardNavigationGestures;
|
||||
};
|
||||
|
||||
struct PanelPreferences {
|
||||
bool FloatingPanel;
|
||||
bool BecomesKeyOnlyIfNeeded;
|
||||
bool NonactivatingPanel;
|
||||
bool UtilityWindow;
|
||||
};
|
||||
|
||||
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 | NSWindowStyleMaskMiniaturizable;
|
||||
}
|
||||
WebviewWindow* window = [[WebviewWindow alloc] initWithContentRect:NSMakeRect(0, 0, width-1, height-1)
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
|
||||
// Note: collectionBehavior is set later via windowSetCollectionBehavior()
|
||||
// to allow user configuration of Space and fullscreen behavior
|
||||
|
||||
// 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
|
||||
// Shared helper to configure webview for a window or panel
|
||||
static WKWebView* configureWebviewForWindow(NSWindow* window, NSView* view, WebviewWindowDelegate* delegate,
|
||||
int width, int height, bool fraudulentWebsiteWarningEnabled,
|
||||
bool enableDragAndDrop, struct WebviewPreferences webviewPreferences) {
|
||||
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 (webviewPreferences.TabFocusesLinks != NULL) {
|
||||
config.preferences.tabFocusesLinks = *webviewPreferences.TabFocusesLinks;
|
||||
}
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 110300
|
||||
if (@available(macOS 11.3, *)) {
|
||||
if (preferences.TextInteractionEnabled != NULL) {
|
||||
config.preferences.textInteractionEnabled = *preferences.TextInteractionEnabled;
|
||||
if (webviewPreferences.TextInteractionEnabled != NULL) {
|
||||
config.preferences.textInteractionEnabled = *webviewPreferences.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;
|
||||
if (webviewPreferences.FullscreenEnabled != NULL) {
|
||||
config.preferences.elementFullscreenEnabled = *webviewPreferences.FullscreenEnabled;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup user content controller
|
||||
WKUserContentController* userContentController = [WKUserContentController new];
|
||||
[userContentController autorelease];
|
||||
config.suppressesIncrementalRendering = true;
|
||||
config.applicationNameForUserAgent = @"wails.io";
|
||||
[config setURLSchemeHandler:delegate forURLScheme:@"wails"];
|
||||
|
||||
[userContentController addScriptMessageHandler:delegate name:@"external"];
|
||||
config.userContentController = userContentController;
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
|
||||
if (@available(macOS 10.15, *)) {
|
||||
config.preferences.fraudulentWebsiteWarningEnabled = fraudulentWebsiteWarningEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
WKUserContentController* userContentController = [WKUserContentController new];
|
||||
[userContentController autorelease];
|
||||
[userContentController addScriptMessageHandler:delegate name:@"external"];
|
||||
config.userContentController = userContentController;
|
||||
|
||||
WKWebView* webView = [[WKWebView alloc] initWithFrame:frame configuration:config];
|
||||
[webView autorelease];
|
||||
|
||||
// Set allowsBackForwardNavigationGestures if specified
|
||||
if (preferences.AllowsBackForwardNavigationGestures != NULL) {
|
||||
webView.allowsBackForwardNavigationGestures = *preferences.AllowsBackForwardNavigationGestures;
|
||||
}
|
||||
|
||||
[view addSubview:webView];
|
||||
|
||||
// support webview events
|
||||
[webView setNavigationDelegate:delegate];
|
||||
[webView setUIDelegate: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;
|
||||
if (webviewPreferences.AllowsBackForwardNavigationGestures != NULL) {
|
||||
webView.allowsBackForwardNavigationGestures = *webviewPreferences.AllowsBackForwardNavigationGestures;
|
||||
}
|
||||
|
||||
window.webView = webView;
|
||||
return window;
|
||||
[view addSubview:webView];
|
||||
[webView setNavigationDelegate:delegate];
|
||||
[webView setUIDelegate:delegate];
|
||||
[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 = delegate.windowId;
|
||||
}
|
||||
|
||||
return webView;
|
||||
}
|
||||
|
||||
// Create a new Window
|
||||
void* windowNew(unsigned int id, int width, int height, bool fraudulentWebsiteWarningEnabled, bool frameless, bool enableDragAndDrop,
|
||||
struct WebviewPreferences webviewPreferences, bool isPanel, struct PanelPreferences panelPreferences) {
|
||||
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
|
||||
if (frameless) {
|
||||
styleMask = NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable;
|
||||
}
|
||||
|
||||
NSWindow* window;
|
||||
if (isPanel) {
|
||||
if (panelPreferences.NonactivatingPanel) {
|
||||
styleMask |= NSWindowStyleMaskNonactivatingPanel;
|
||||
}
|
||||
if (panelPreferences.UtilityWindow) {
|
||||
styleMask |= NSWindowStyleMaskUtilityWindow;
|
||||
}
|
||||
WebviewPanel* panel = [[WebviewPanel alloc] initWithContentRect:NSMakeRect(0, 0, width-1, height-1)
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
[panel setFloatingPanel:panelPreferences.FloatingPanel];
|
||||
[panel setBecomesKeyOnlyIfNeeded:panelPreferences.BecomesKeyOnlyIfNeeded];
|
||||
window = panel;
|
||||
} else {
|
||||
window = [[WebviewWindow alloc] initWithContentRect:NSMakeRect(0, 0, width-1, height-1)
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
}
|
||||
|
||||
WebviewWindowDelegate* delegate = [[WebviewWindowDelegate alloc] init];
|
||||
[delegate autorelease];
|
||||
[window setDelegate:delegate];
|
||||
delegate.windowId = id;
|
||||
|
||||
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];
|
||||
|
||||
WKWebView* webView = configureWebviewForWindow(window, view, delegate, width, height,
|
||||
fraudulentWebsiteWarningEnabled, enableDragAndDrop, webviewPreferences);
|
||||
if (isPanel) {
|
||||
((WebviewPanel*)window).webView = webView;
|
||||
} else {
|
||||
((WebviewWindow*)window).webView = webView;
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
void printWindowStyle(void *window) {
|
||||
WebviewWindow* nsWindow = (WebviewWindow*)window;
|
||||
|
|
@ -1276,6 +1296,17 @@ func (w *macosWebviewWindow) getWebviewPreferences() C.struct_WebviewPreferences
|
|||
return result
|
||||
}
|
||||
|
||||
func (w *macosWebviewWindow) getPanelPreferences() C.struct_PanelPreferences {
|
||||
panelPrefs := w.parent.options.Mac.PanelPreferences
|
||||
|
||||
return C.struct_PanelPreferences{
|
||||
FloatingPanel: C.bool(panelPrefs.FloatingPanel),
|
||||
BecomesKeyOnlyIfNeeded: C.bool(panelPrefs.BecomesKeyOnlyIfNeeded),
|
||||
NonactivatingPanel: C.bool(panelPrefs.NonactivatingPanel),
|
||||
UtilityWindow: C.bool(panelPrefs.UtilityWindow),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *macosWebviewWindow) run() {
|
||||
for eventId := range w.parent.eventListeners {
|
||||
w.on(eventId)
|
||||
|
|
@ -1291,6 +1322,8 @@ func (w *macosWebviewWindow) run() {
|
|||
C.bool(options.Frameless),
|
||||
C.bool(options.EnableFileDrop),
|
||||
w.getWebviewPreferences(),
|
||||
C.bool(macOptions.WindowClass == MacWindowClassPanel),
|
||||
w.getPanelPreferences(),
|
||||
)
|
||||
w.setTitle(options.Title)
|
||||
w.setResizable(!options.DisableResize)
|
||||
|
|
@ -1320,10 +1353,13 @@ func (w *macosWebviewWindow) run() {
|
|||
case MacBackdropNormal:
|
||||
}
|
||||
|
||||
if macOptions.WindowLevel == "" {
|
||||
macOptions.WindowLevel = MacWindowLevelNormal
|
||||
// Only set window level if explicitly specified, or if not a floating panel
|
||||
// (setFloatingPanel:YES already sets NSFloatingWindowLevel, so don't override it)
|
||||
if macOptions.WindowLevel != "" {
|
||||
w.setWindowLevel(macOptions.WindowLevel)
|
||||
} else if !(macOptions.WindowClass == MacWindowClassPanel && macOptions.PanelPreferences.FloatingPanel) {
|
||||
w.setWindowLevel(MacWindowLevelNormal)
|
||||
}
|
||||
w.setWindowLevel(macOptions.WindowLevel)
|
||||
|
||||
// Set collection behavior (defaults to FullScreenPrimary for backwards compatibility)
|
||||
w.setCollectionBehavior(macOptions.CollectionBehavior)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,18 @@
|
|||
|
||||
@end
|
||||
|
||||
@interface WebviewPanel : NSPanel
|
||||
- (BOOL) canBecomeKeyWindow;
|
||||
- (BOOL) canBecomeMainWindow;
|
||||
- (BOOL) acceptsFirstResponder;
|
||||
- (BOOL) becomeFirstResponder;
|
||||
- (BOOL) resignFirstResponder;
|
||||
- (WebviewPanel*) initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation;
|
||||
|
||||
@property (assign) WKWebView* webView;
|
||||
|
||||
@end
|
||||
|
||||
@interface WebviewWindowDelegate : NSObject <NSWindowDelegate, WKScriptMessageHandler, WKNavigationDelegate, WKURLSchemeHandler, NSDraggingDestination, WKUIDelegate>
|
||||
|
||||
@property unsigned int windowId;
|
||||
|
|
|
|||
|
|
@ -18,81 +18,22 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
LiquidGlassStyleDark = 2,
|
||||
LiquidGlassStyleVibrant = 3
|
||||
};
|
||||
@implementation WebviewWindow
|
||||
- (WebviewWindow*) initWithContentRect:(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];
|
||||
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.delegate;
|
||||
processWindowKeyDownEvent(delegate.windowId, utf8String);
|
||||
}
|
||||
- (NSString *)keyStringFromEvent:(NSEvent *)event {
|
||||
// Get the pressed key
|
||||
// Check for special keys like escape and tab
|
||||
|
||||
// Shared key event handling functions
|
||||
static NSString* keyStringFromKeyEvent(NSEvent *event) {
|
||||
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";
|
||||
}
|
||||
if ([characters isEqualToString:@"\r"]) return @"enter";
|
||||
if ([characters isEqualToString:@"\b"]) return @"backspace";
|
||||
if ([characters isEqualToString:@"\e"]) return @"escape";
|
||||
if ([characters isEqualToString:@"\x0B"]) return @"page down";
|
||||
if ([characters isEqualToString:@"\x0E"]) return @"page up";
|
||||
if ([characters isEqualToString:@"\x01"]) return @"home";
|
||||
if ([characters isEqualToString:@"\x04"]) return @"end";
|
||||
if ([characters isEqualToString:@"\x0C"]) return @"clear";
|
||||
switch ([event keyCode]) {
|
||||
// Function keys
|
||||
case 122: return @"f1";
|
||||
case 120: return @"f2";
|
||||
case 99: return @"f3";
|
||||
|
|
@ -113,7 +54,6 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
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";
|
||||
|
|
@ -140,7 +80,6 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
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";
|
||||
|
|
@ -151,7 +90,6 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
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";
|
||||
|
|
@ -161,7 +99,6 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
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 @",";
|
||||
|
|
@ -176,6 +113,36 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
default: return @"";
|
||||
}
|
||||
}
|
||||
|
||||
static void dispatchKeyDownEvent(NSEvent *event, unsigned int windowId) {
|
||||
NSUInteger modifierFlags = event.modifierFlags;
|
||||
NSMutableArray *modifierStrings = [NSMutableArray 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 = keyStringFromKeyEvent(event);
|
||||
if (keyString.length > 0) {
|
||||
[modifierStrings addObject:keyString];
|
||||
}
|
||||
NSString *keyEventString = [modifierStrings componentsJoinedByString:@"+"];
|
||||
processWindowKeyDownEvent(windowId, [keyEventString UTF8String]);
|
||||
}
|
||||
|
||||
@implementation WebviewWindow
|
||||
- (WebviewWindow*) initWithContentRect:(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];
|
||||
return self;
|
||||
}
|
||||
- (void)keyDown:(NSEvent *)event {
|
||||
WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)self.delegate;
|
||||
dispatchKeyDownEvent(event, delegate.windowId);
|
||||
}
|
||||
- (BOOL)canBecomeKeyWindow {
|
||||
return YES;
|
||||
}
|
||||
|
|
@ -243,6 +210,59 @@ typedef NS_ENUM(NSInteger, MacLiquidGlassStyle) {
|
|||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation WebviewPanel
|
||||
- (WebviewPanel*) initWithContentRect:(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];
|
||||
return self;
|
||||
}
|
||||
// Override sendEvent to intercept key events BEFORE WKWebView consumes them
|
||||
- (void)sendEvent:(NSEvent *)event {
|
||||
if (event.type == NSEventTypeKeyDown) {
|
||||
[self keyDown:event];
|
||||
}
|
||||
[super sendEvent:event];
|
||||
}
|
||||
- (void)keyDown:(NSEvent *)event {
|
||||
WebviewWindowDelegate *delegate = (WebviewWindowDelegate*)self.delegate;
|
||||
dispatchKeyDownEvent(event, delegate.windowId);
|
||||
}
|
||||
- (BOOL)canBecomeKeyWindow {
|
||||
return YES;
|
||||
}
|
||||
- (BOOL) canBecomeMainWindow {
|
||||
return NO; // Panels typically don't become main window
|
||||
}
|
||||
- (BOOL) acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
- (BOOL) becomeFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
- (BOOL) resignFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
- (void) setDelegate:(id<NSWindowDelegate>) delegate {
|
||||
[delegate retain];
|
||||
[super setDelegate: delegate];
|
||||
if ([delegate isKindOfClass:[WebviewWindowDelegate class]]) {
|
||||
[self registerForDraggedTypes:@[NSFilenamesPboardType]];
|
||||
}
|
||||
}
|
||||
- (void) dealloc {
|
||||
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"external"];
|
||||
if (self.delegate) {
|
||||
[self.delegate release];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation WebviewWindowDelegate
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
|
||||
NSPasteboard *pasteboard = [sender draggingPasteboard];
|
||||
|
|
|
|||
|
|
@ -485,6 +485,34 @@ type MacWindow struct {
|
|||
|
||||
// LiquidGlass contains configuration for the Liquid Glass effect
|
||||
LiquidGlass MacLiquidGlass
|
||||
|
||||
// WindowClass is the window class for the window
|
||||
WindowClass MacWindowClass
|
||||
|
||||
// PanelPreferences contains configuration for panel windows
|
||||
PanelPreferences MacPanelPreferences
|
||||
}
|
||||
|
||||
// MacWindowClass is the window class for macOS
|
||||
type MacWindowClass int
|
||||
|
||||
const (
|
||||
// MacWindowClassWindow - The default value. A window that an app displays on the screen.
|
||||
MacWindowClassWindow MacWindowClass = iota
|
||||
// MacWindowClassPanel - A special kind of window that typically performs a function that is auxiliary to the main window
|
||||
MacWindowClassPanel
|
||||
)
|
||||
|
||||
// MacPanelPreferences contains options for MacWindowClassPanel windows
|
||||
type MacPanelPreferences struct {
|
||||
// FloatingPanel will make the panel float above other windows
|
||||
FloatingPanel bool
|
||||
// BecomesKeyOnlyIfNeeded will make the panel become key only when needed
|
||||
BecomesKeyOnlyIfNeeded bool
|
||||
// NonactivatingPanel will apply the NSWindowStyleMaskNonactivatingPanel style
|
||||
NonactivatingPanel bool
|
||||
// UtilityWindow will apply the NSWindowStyleMaskUtilityWindow style
|
||||
UtilityWindow bool
|
||||
}
|
||||
|
||||
type MacWindowLevel string
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Added Panel support for macOS. Panels serve as auxiliary windows and can appear over fullscreen apps without activating the application using `NSWindowStyleMaskNonactivatingPanel`. Configure via `Mac.WindowClass` and `Mac.PanelPreferences` in window options. Added by [@Grantmartin2002](https://github.com/Grantmartin2002) in [PR](https://github.com/wailsapp/wails/pull/5024)
|
||||
|
||||
### Fixed
|
||||
- Fixed locking issue on Windows when multiselect dialog returns an error. Fixed in [PR](https://github.com/wailsapp/wails/pull/4156) by @johannes-luebke
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue