Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add panel support for BrowserWindow #34665

6 changes: 5 additions & 1 deletion docs/api/browser-window.md
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions filenames.gni
Expand Up @@ -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",
Expand Down
8 changes: 7 additions & 1 deletion shell/browser/native_window_mac.mm
Expand Up @@ -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<ElectronNSWindow*>(
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -811,6 +816,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
}

void NativeWindowMac::SetResizable(bool resizable) {
ScopedDisableResize disable_resize;
SetStyleMask(resizable, NSWindowStyleMaskResizable);
SetCanResize(resizable);
}
Expand Down
4 changes: 4 additions & 0 deletions shell/browser/ui/cocoa/electron_native_widget_mac.h
Expand Up @@ -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 <string>

#include "ui/views/widget/native_widget_mac.h"

namespace electron {
Expand All @@ -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;
Expand All @@ -29,6 +32,7 @@ class ElectronNativeWidgetMac : public views::NativeWidgetMac {

private:
NativeWindowMac* shell_;
std::string window_type_;
NSUInteger style_mask_;
};

Expand Down
14 changes: 12 additions & 2 deletions shell/browser/ui/cocoa/electron_native_widget_mac.mm
Expand Up @@ -4,24 +4,34 @@

#include "shell/browser/ui/cocoa/electron_native_widget_mac.h"

#include <string>

#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
17 changes: 17 additions & 0 deletions 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_
39 changes: 39 additions & 0 deletions 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
9 changes: 5 additions & 4 deletions shell/browser/ui/cocoa/electron_ns_window.h
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion shell/browser/ui/cocoa/electron_ns_window.mm
Expand Up @@ -13,7 +13,7 @@

namespace electron {

bool ScopedDisableResize::disable_resize_ = false;
int ScopedDisableResize::disable_resize_ = 0;

} // namespace electron

Expand Down