diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 2f00cd1f5feb7..d2a4ef468b5e5 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -425,13 +425,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 (`NSWindowStyleMaskTexturedBackground`). * 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 enables the window to float on top of full-screened apps + by adding the `NSWindowStyleMaskNonactivatingPanel` style mask,normally + reserved for NSPanel, at runtime. Also, the window will appear on all + spaces (desktops). * On Windows, possible type is `toolbar`. ### Instance Events diff --git a/filenames.gni b/filenames.gni index aa26914ee6d36..3ce306928a96f 100644 --- a/filenames.gni +++ b/filenames.gni @@ -167,6 +167,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 b7ba0fd6c02f8..6a3fc8e39b0db 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -317,7 +317,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( @@ -355,6 +356,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]; @@ -811,6 +816,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { } void NativeWindowMac::SetResizable(bool resizable) { + ScopedDisableResize disable_resize; SetStyleMask(resizable, NSWindowStyleMaskResizable); SetCanResize(resizable); } diff --git a/shell/browser/ui/cocoa/electron_native_widget_mac.h b/shell/browser/ui/cocoa/electron_native_widget_mac.h index 7fdfd0433a01a..2e378ce0fa7e3 100644 --- a/shell/browser/ui/cocoa/electron_native_widget_mac.h +++ b/shell/browser/ui/cocoa/electron_native_widget_mac.h @@ -5,6 +5,8 @@ #ifndef ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NATIVE_WIDGET_MAC_H_ #define ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NATIVE_WIDGET_MAC_H_ +#include + #include "ui/views/widget/native_widget_mac.h" namespace electron { @@ -14,6 +16,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; @@ -29,6 +32,7 @@ class ElectronNativeWidgetMac : public views::NativeWidgetMac { private: NativeWindowMac* shell_; + std::string window_type_; NSUInteger style_mask_; }; diff --git a/shell/browser/ui/cocoa/electron_native_widget_mac.mm b/shell/browser/ui/cocoa/electron_native_widget_mac.mm index 4247a45229f93..12a9469b92ba6 100644 --- a/shell/browser/ui/cocoa/electron_native_widget_mac.mm +++ b/shell/browser/ui/cocoa/electron_native_widget_mac.mm @@ -4,24 +4,34 @@ #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..755271acec135 --- /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 ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_NS_PANEL_H_ +#define ELECTRON_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 // ELECTRON_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 diff --git a/shell/browser/ui/cocoa/electron_ns_window.h b/shell/browser/ui/cocoa/electron_ns_window.h index 50ad1ca8a96d2..f5d7b80b0399b 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.h +++ b/shell/browser/ui/cocoa/electron_ns_window.h @@ -16,13 +16,14 @@ class NativeWindowMac; // Prevents window from resizing during the scope. class ScopedDisableResize { public: - ScopedDisableResize() { disable_resize_ = true; } - ~ScopedDisableResize() { disable_resize_ = false; } + ScopedDisableResize() { disable_resize_++; } + ~ScopedDisableResize() { disable_resize_--; } - static bool IsResizeDisabled() { return disable_resize_; } + // True if there are 1+ nested ScopedDisableResize objects in the scope + static bool IsResizeDisabled() { return disable_resize_ > 0; } private: - static bool disable_resize_; + static int disable_resize_; }; } // namespace electron diff --git a/shell/browser/ui/cocoa/electron_ns_window.mm b/shell/browser/ui/cocoa/electron_ns_window.mm index f4cc2bc5bcbf1..a8929237e4030 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.mm +++ b/shell/browser/ui/cocoa/electron_ns_window.mm @@ -13,7 +13,7 @@ namespace electron { -bool ScopedDisableResize::disable_resize_ = false; +int ScopedDisableResize::disable_resize_ = 0; } // namespace electron