diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 1176f4fd01317..d7901efd8ef58 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -406,13 +406,17 @@ Possible values are: * On Linux, possible types are `desktop`, `dock`, `toolbar`, `splash`, `notification`. -* On macOS, possible types are `desktop`, `textured`. +* On macOS, possible types are `desktop`, `textured`, `panel`. * The `textured` type adds metal gradient appearance (`NSTexturedBackgroundWindowMask`). * The `desktop` type places the window at the desktop background window level (`kCGDesktopWindowLevel - 1`). Note that desktop window will not receive focus, keyboard or mouse events, but you can use `globalShortcut` to receive input sparingly. + * The `panel` type sets the window level to float (`NSFloatingWindowLevel`) and + makes it appear in all spaces. The `NSWindowStyleMaskNonactivatingPanel` style + mask is added on runtime, such that the window can float on top of full-screened + apps. * On Windows, possible type is `toolbar`. ### Instance Events diff --git a/filenames.gni b/filenames.gni index 45a6badd2d340..cc0b4c4ec97f0 100644 --- a/filenames.gni +++ b/filenames.gni @@ -164,6 +164,8 @@ filenames = { "shell/browser/ui/cocoa/electron_native_widget_mac.mm", "shell/browser/ui/cocoa/electron_ns_window_delegate.h", "shell/browser/ui/cocoa/electron_ns_window_delegate.mm", + "shell/browser/ui/cocoa/electron_ns_panel.h", + "shell/browser/ui/cocoa/electron_ns_panel.mm", "shell/browser/ui/cocoa/electron_ns_window.h", "shell/browser/ui/cocoa/electron_ns_window.mm", "shell/browser/ui/cocoa/electron_preview_item.h", diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index dbabadee743f4..20e0906058340 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -318,7 +318,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { params.bounds = bounds; params.delegate = this; params.type = views::Widget::InitParams::TYPE_WINDOW; - params.native_widget = new ElectronNativeWidgetMac(this, styleMask, widget()); + params.native_widget = + new ElectronNativeWidgetMac(this, windowType, styleMask, widget()); widget()->Init(std::move(params)); SetCanResize(resizable); window_ = static_cast( @@ -356,6 +357,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { NSWindowCollectionBehaviorIgnoresCycle)]; } + if (windowType == "panel") { + [window_ setLevel:NSFloatingWindowLevel]; + } + bool focusable; if (options.Get(options::kFocusable, &focusable) && !focusable) [window_ setDisableKeyOrMainWindow:YES]; diff --git a/shell/browser/ui/cocoa/electron_native_widget_mac.h b/shell/browser/ui/cocoa/electron_native_widget_mac.h index 5a1f3ad99f0a8..81ccc760e4b9f 100644 --- a/shell/browser/ui/cocoa/electron_native_widget_mac.h +++ b/shell/browser/ui/cocoa/electron_native_widget_mac.h @@ -5,6 +5,7 @@ #ifndef SHELL_BROWSER_UI_COCOA_ELECTRON_NATIVE_WIDGET_MAC_H_ #define SHELL_BROWSER_UI_COCOA_ELECTRON_NATIVE_WIDGET_MAC_H_ +#include #include "ui/views/widget/native_widget_mac.h" namespace electron { @@ -14,6 +15,7 @@ class NativeWindowMac; class ElectronNativeWidgetMac : public views::NativeWidgetMac { public: ElectronNativeWidgetMac(NativeWindowMac* shell, + const std::string& window_type, NSUInteger style_mask, views::internal::NativeWidgetDelegate* delegate); ~ElectronNativeWidgetMac() override; @@ -25,6 +27,7 @@ class ElectronNativeWidgetMac : public views::NativeWidgetMac { private: NativeWindowMac* shell_; + std::string window_type_; NSUInteger style_mask_; DISALLOW_COPY_AND_ASSIGN(ElectronNativeWidgetMac); diff --git a/shell/browser/ui/cocoa/electron_native_widget_mac.mm b/shell/browser/ui/cocoa/electron_native_widget_mac.mm index 4247a45229f93..bafaf2479d401 100644 --- a/shell/browser/ui/cocoa/electron_native_widget_mac.mm +++ b/shell/browser/ui/cocoa/electron_native_widget_mac.mm @@ -4,24 +4,33 @@ #include "shell/browser/ui/cocoa/electron_native_widget_mac.h" +#include +#include "shell/browser/ui/cocoa/electron_ns_panel.h" #include "shell/browser/ui/cocoa/electron_ns_window.h" namespace electron { ElectronNativeWidgetMac::ElectronNativeWidgetMac( NativeWindowMac* shell, + const std::string& window_type, NSUInteger style_mask, views::internal::NativeWidgetDelegate* delegate) : views::NativeWidgetMac(delegate), shell_(shell), + window_type_(window_type), style_mask_(style_mask) {} ElectronNativeWidgetMac::~ElectronNativeWidgetMac() = default; NativeWidgetMacNSWindow* ElectronNativeWidgetMac::CreateNSWindow( const remote_cocoa::mojom::CreateWindowParams* params) { - return [[[ElectronNSWindow alloc] initWithShell:shell_ - styleMask:style_mask_] autorelease]; + if (window_type_ == "panel") { + return [[[ElectronNSPanel alloc] initWithShell:shell_ + styleMask:style_mask_] autorelease]; + } else { + return [[[ElectronNSWindow alloc] initWithShell:shell_ + styleMask:style_mask_] autorelease]; + } } } // namespace electron diff --git a/shell/browser/ui/cocoa/electron_ns_panel.h b/shell/browser/ui/cocoa/electron_ns_panel.h new file mode 100644 index 0000000000000..d33d5d25d7c8f --- /dev/null +++ b/shell/browser/ui/cocoa/electron_ns_panel.h @@ -0,0 +1,17 @@ +// Copyright (c) 2022 Microsoft, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ +#define SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ + +#include "shell/browser/ui/cocoa/electron_ns_window.h" + +@interface ElectronNSPanel : ElectronNSWindow +@property NSWindowStyleMask styleMask; +@property NSWindowStyleMask originalStyleMask; +- (id)initWithShell:(electron::NativeWindowMac*)shell + styleMask:(NSUInteger)styleMask; +@end + +#endif // SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ diff --git a/shell/browser/ui/cocoa/electron_ns_panel.mm b/shell/browser/ui/cocoa/electron_ns_panel.mm new file mode 100644 index 0000000000000..581c142ede5ef --- /dev/null +++ b/shell/browser/ui/cocoa/electron_ns_panel.mm @@ -0,0 +1,39 @@ +// Copyright (c) 2022 Microsoft, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/browser/ui/cocoa/electron_ns_panel.h" + +@implementation ElectronNSPanel + +@synthesize originalStyleMask; + +- (id)initWithShell:(electron::NativeWindowMac*)shell + styleMask:(NSUInteger)styleMask { + if (self = [super initWithShell:shell styleMask:styleMask]) { + originalStyleMask = styleMask; + } + return self; +} + +@dynamic styleMask; +// The Nonactivating mask is reserverd for NSPanel, +// but we can use this workaround to add it at runtime +- (NSWindowStyleMask)styleMask { + return originalStyleMask | NSWindowStyleMaskNonactivatingPanel; +} + +- (void)setStyleMask:(NSWindowStyleMask)styleMask { + originalStyleMask = styleMask; + // Notify change of style mask. + [super setStyleMask:styleMask]; +} + +- (void)setCollectionBehavior:(NSWindowCollectionBehavior)collectionBehavior { + NSWindowCollectionBehavior panelBehavior = + (NSWindowCollectionBehaviorCanJoinAllSpaces | + NSWindowCollectionBehaviorFullScreenAuxiliary); + [super setCollectionBehavior:collectionBehavior | panelBehavior]; +} + +@end