fix: fallback to FullSizeContentView for frameless window on mac (#13600)
When using `views::Widget` to create window, Chromium will automatically use a `BridgedContentView` as content view, which however does not support draggable regions inside it. By fallback to `FullSizeContentView` we can work around this problem, with the price of losing the ability to use `views::View` APIs. Since we don't expect users to use the new `View` APIs in `BrowserWindow` anyway, it should not be a problem. This change does not affect users of `TopLevelWindow`, and for users of `BrowserWindow` there is nothing to lose. In the long term we should look into how to make draggable regions work with `BridgedContentView`. The related Chromium code is still being changed rapidly, we can wait until Chromium migrated its `NativeAppWindowCocoa` class to use `views::Widget`.
This commit is contained in:
parent
f6ae438005
commit
85526c7f21
5 changed files with 123 additions and 55 deletions
|
@ -85,6 +85,11 @@ BrowserWindow::BrowserWindow(v8::Isolate* isolate,
|
||||||
|
|
||||||
InitWith(isolate, wrapper);
|
InitWith(isolate, wrapper);
|
||||||
|
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
if (!window()->has_frame())
|
||||||
|
OverrideNSWindowContentView();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Init window after everything has been setup.
|
// Init window after everything has been setup.
|
||||||
window()->InitFromOptions(options);
|
window()->InitFromOptions(options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,10 @@ class BrowserWindow : public TopLevelWindow,
|
||||||
v8::Local<v8::Value> GetWebContents(v8::Isolate* isolate);
|
v8::Local<v8::Value> GetWebContents(v8::Isolate* isolate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if defined(OS_MACOSX)
|
||||||
|
void OverrideNSWindowContentView();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
|
|
||||||
// Called when the window needs to update its draggable region.
|
// Called when the window needs to update its draggable region.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
#include "atom/browser/native_browser_view.h"
|
#include "atom/browser/native_browser_view.h"
|
||||||
|
#include "atom/browser/native_window_mac.h"
|
||||||
#include "atom/common/draggable_region.h"
|
#include "atom/common/draggable_region.h"
|
||||||
#include "base/mac/scoped_nsobject.h"
|
#include "base/mac/scoped_nsobject.h"
|
||||||
|
|
||||||
|
@ -53,6 +54,17 @@ std::vector<gfx::Rect> CalculateNonDraggableRegions(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void BrowserWindow::OverrideNSWindowContentView() {
|
||||||
|
// Make NativeWindow use a NSView as content view.
|
||||||
|
static_cast<NativeWindowMac*>(window())->OverrideNSWindowContentView();
|
||||||
|
// Add webview to contentView.
|
||||||
|
NSView* webView = web_contents()->GetNativeView();
|
||||||
|
NSView* contentView = [window()->GetNativeWindow() contentView];
|
||||||
|
[webView setFrame:[contentView bounds]];
|
||||||
|
[contentView addSubview:webView];
|
||||||
|
[contentView viewDidMoveToWindow];
|
||||||
|
}
|
||||||
|
|
||||||
void BrowserWindow::UpdateDraggableRegions(
|
void BrowserWindow::UpdateDraggableRegions(
|
||||||
content::RenderFrameHost* rfh,
|
content::RenderFrameHost* rfh,
|
||||||
const std::vector<DraggableRegion>& regions) {
|
const std::vector<DraggableRegion>& regions) {
|
||||||
|
|
|
@ -128,6 +128,9 @@ class NativeWindowMac : public NativeWindow {
|
||||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
|
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
|
||||||
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
|
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
|
||||||
|
|
||||||
|
// Use a custom content view instead of Chromium's BridgedContentView.
|
||||||
|
void OverrideNSWindowContentView();
|
||||||
|
|
||||||
// Set the attribute of NSWindow while work around a bug of zoom button.
|
// Set the attribute of NSWindow while work around a bug of zoom button.
|
||||||
void SetStyleMask(bool on, NSUInteger flag);
|
void SetStyleMask(bool on, NSUInteger flag);
|
||||||
void SetCollectionBehavior(bool on, NSUInteger flag);
|
void SetCollectionBehavior(bool on, NSUInteger flag);
|
||||||
|
@ -152,6 +155,9 @@ class NativeWindowMac : public NativeWindow {
|
||||||
views::View* GetContentsView() override;
|
views::View* GetContentsView() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Add custom layers to the content view.
|
||||||
|
void AddContentViewLayers();
|
||||||
|
|
||||||
void InternalSetParentWindow(NativeWindow* parent, bool attach);
|
void InternalSetParentWindow(NativeWindow* parent, bool attach);
|
||||||
void ShowWindowButton(NSWindowButton button);
|
void ShowWindowButton(NSWindowButton button);
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,31 @@
|
||||||
#include "ui/views/cocoa/bridged_native_widget.h"
|
#include "ui/views/cocoa/bridged_native_widget.h"
|
||||||
#include "ui/views/widget/widget.h"
|
#include "ui/views/widget/widget.h"
|
||||||
|
|
||||||
|
// This view always takes the size of its superview. It is intended to be used
|
||||||
|
// as a NSWindow's contentView. It is needed because NSWindow's implementation
|
||||||
|
// explicitly resizes the contentView at inopportune times.
|
||||||
|
@interface FullSizeContentView : NSView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation FullSizeContentView
|
||||||
|
|
||||||
|
// This method is directly called by NSWindow during a window resize on OSX
|
||||||
|
// 10.10.0, beta 2. We must override it to prevent the content view from
|
||||||
|
// shrinking.
|
||||||
|
- (void)setFrameSize:(NSSize)size {
|
||||||
|
if ([self superview])
|
||||||
|
size = [[self superview] bounds].size;
|
||||||
|
[super setFrameSize:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The contentView gets moved around during certain full-screen operations.
|
||||||
|
// This is less than ideal, and should eventually be removed.
|
||||||
|
- (void)viewDidMoveToSuperview {
|
||||||
|
[self setFrame:[[self superview] bounds]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
// Custom Quit, Minimize and Full Screen button container for frameless
|
// Custom Quit, Minimize and Full Screen button container for frameless
|
||||||
// windows.
|
// windows.
|
||||||
@interface CustomWindowButtonView : NSView {
|
@interface CustomWindowButtonView : NSView {
|
||||||
|
@ -443,61 +468,7 @@ NativeWindowMac::NativeWindowMac(const mate::Dictionary& options,
|
||||||
|
|
||||||
// Default content view.
|
// Default content view.
|
||||||
SetContentView(new views::View());
|
SetContentView(new views::View());
|
||||||
|
AddContentViewLayers();
|
||||||
// Make sure the bottom corner is rounded for non-modal windows:
|
|
||||||
// http://crbug.com/396264. But do not enable it on OS X 10.9 for transparent
|
|
||||||
// window, otherwise a semi-transparent frame would show.
|
|
||||||
if (!(transparent() && base::mac::IsOS10_9()) && !is_modal()) {
|
|
||||||
base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
|
|
||||||
[background_layer
|
|
||||||
setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
|
|
||||||
[[window_ contentView] setLayer:background_layer];
|
|
||||||
[[window_ contentView] setWantsLayer:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_frame()) {
|
|
||||||
// In OSX 10.10, adding subviews to the root view for the NSView hierarchy
|
|
||||||
// produces warnings. To eliminate the warnings, we resize the contentView
|
|
||||||
// to fill the window, and add subviews to that.
|
|
||||||
// http://crbug.com/380412
|
|
||||||
if (!original_set_frame_size) {
|
|
||||||
Class cl = [[window_ contentView] class];
|
|
||||||
original_set_frame_size = class_replaceMethod(
|
|
||||||
cl, @selector(setFrameSize:), (IMP)SetFrameSize, "v@:{_NSSize=ff}");
|
|
||||||
original_view_did_move_to_superview =
|
|
||||||
class_replaceMethod(cl, @selector(viewDidMoveToSuperview),
|
|
||||||
(IMP)ViewDidMoveToSuperview, "v@:");
|
|
||||||
[[window_ contentView] viewDidMoveToWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
// The fullscreen button should always be hidden for frameless window.
|
|
||||||
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
|
||||||
|
|
||||||
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
|
|
||||||
buttons_view_.reset(
|
|
||||||
[[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
|
|
||||||
[[window_ contentView] addSubview:buttons_view_];
|
|
||||||
} else {
|
|
||||||
if (title_bar_style_ != NORMAL) {
|
|
||||||
if (base::mac::IsOS10_9()) {
|
|
||||||
ShowWindowButton(NSWindowZoomButton);
|
|
||||||
ShowWindowButton(NSWindowMiniaturizeButton);
|
|
||||||
ShowWindowButton(NSWindowCloseButton);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide the window buttons.
|
|
||||||
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
|
||||||
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
|
||||||
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some third-party macOS utilities check the zoom button's enabled state to
|
|
||||||
// determine whether to show custom UI on hover, so we disable it here to
|
|
||||||
// prevent them from doing so in a frameless app window.
|
|
||||||
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeWindowMac::~NativeWindowMac() {
|
NativeWindowMac::~NativeWindowMac() {
|
||||||
|
@ -1320,6 +1291,63 @@ views::View* NativeWindowMac::GetContentsView() {
|
||||||
return root_view_.get();
|
return root_view_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeWindowMac::AddContentViewLayers() {
|
||||||
|
// Make sure the bottom corner is rounded for non-modal windows:
|
||||||
|
// http://crbug.com/396264. But do not enable it on OS X 10.9 for transparent
|
||||||
|
// window, otherwise a semi-transparent frame would show.
|
||||||
|
if (!(transparent() && base::mac::IsOS10_9()) && !is_modal()) {
|
||||||
|
base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]);
|
||||||
|
[background_layer
|
||||||
|
setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
|
||||||
|
[[window_ contentView] setLayer:background_layer];
|
||||||
|
[[window_ contentView] setWantsLayer:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_frame()) {
|
||||||
|
// In OSX 10.10, adding subviews to the root view for the NSView hierarchy
|
||||||
|
// produces warnings. To eliminate the warnings, we resize the contentView
|
||||||
|
// to fill the window, and add subviews to that.
|
||||||
|
// http://crbug.com/380412
|
||||||
|
if (!original_set_frame_size) {
|
||||||
|
Class cl = [[window_ contentView] class];
|
||||||
|
original_set_frame_size = class_replaceMethod(
|
||||||
|
cl, @selector(setFrameSize:), (IMP)SetFrameSize, "v@:{_NSSize=ff}");
|
||||||
|
original_view_did_move_to_superview =
|
||||||
|
class_replaceMethod(cl, @selector(viewDidMoveToSuperview),
|
||||||
|
(IMP)ViewDidMoveToSuperview, "v@:");
|
||||||
|
[[window_ contentView] viewDidMoveToWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The fullscreen button should always be hidden for frameless window.
|
||||||
|
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
||||||
|
|
||||||
|
if (title_bar_style_ == CUSTOM_BUTTONS_ON_HOVER) {
|
||||||
|
buttons_view_.reset(
|
||||||
|
[[CustomWindowButtonView alloc] initWithFrame:NSZeroRect]);
|
||||||
|
[[window_ contentView] addSubview:buttons_view_];
|
||||||
|
} else {
|
||||||
|
if (title_bar_style_ != NORMAL) {
|
||||||
|
if (base::mac::IsOS10_9()) {
|
||||||
|
ShowWindowButton(NSWindowZoomButton);
|
||||||
|
ShowWindowButton(NSWindowMiniaturizeButton);
|
||||||
|
ShowWindowButton(NSWindowCloseButton);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the window buttons.
|
||||||
|
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||||
|
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||||
|
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some third-party macOS utilities check the zoom button's enabled state to
|
||||||
|
// determine whether to show custom UI on hover, so we disable it here to
|
||||||
|
// prevent them from doing so in a frameless app window.
|
||||||
|
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
|
void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
|
||||||
bool attach) {
|
bool attach) {
|
||||||
if (is_modal())
|
if (is_modal())
|
||||||
|
@ -1350,6 +1378,19 @@ void NativeWindowMac::SetForwardMouseMessages(bool forward) {
|
||||||
[window_ setAcceptsMouseMovedEvents:forward];
|
[window_ setAcceptsMouseMovedEvents:forward];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeWindowMac::OverrideNSWindowContentView() {
|
||||||
|
// When using `views::Widget` to hold WebContents, Chromium would use
|
||||||
|
// `BridgedContentView` as content view, which does not support draggable
|
||||||
|
// regions. In order to make draggable regions work, we have to replace the
|
||||||
|
// content view with a simple NSView.
|
||||||
|
container_view_.reset([[FullSizeContentView alloc] init]);
|
||||||
|
[container_view_
|
||||||
|
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||||
|
[container_view_ setFrame:[[[window_ contentView] superview] bounds]];
|
||||||
|
[window_ setContentView:container_view_];
|
||||||
|
AddContentViewLayers();
|
||||||
|
}
|
||||||
|
|
||||||
void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
|
void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
|
||||||
// Changing the styleMask of a frameless windows causes it to change size so
|
// Changing the styleMask of a frameless windows causes it to change size so
|
||||||
// we explicitly disable resizing while setting it.
|
// we explicitly disable resizing while setting it.
|
||||||
|
|
Loading…
Reference in a new issue