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

Refactor NativeWindow (Part 9): Use views::Widget on macOS #12696

Merged
merged 4 commits into from
Apr 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions atom/browser/native_window_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@

namespace atom {

class NativeWindowMac : public NativeWindow {
class NativeWindowMac : public NativeWindow,
public views::WidgetDelegate {
public:
NativeWindowMac(const mate::Dictionary& options, NativeWindow* parent);
~NativeWindowMac() override;
Expand Down Expand Up @@ -144,19 +145,25 @@ class NativeWindowMac : public NativeWindow {
bool fullscreen_window_title() const { return fullscreen_window_title_; }
bool simple_fullscreen() const { return always_simple_fullscreen_; }

protected:
// views::WidgetDelegate:
views::Widget* GetWidget() override;
const views::Widget* GetWidget() const override;
bool CanResize() const override;

private:
void InternalSetParentWindow(NativeWindow* parent, bool attach);
void ShowWindowButton(NSWindowButton button);

void SetForwardMouseMessages(bool forward);

base::scoped_nsobject<AtomNSWindow> window_;
std::unique_ptr<views::Widget> widget_;
AtomNSWindow* window_; // Weak ref, managed by widget_.

base::scoped_nsobject<AtomNSWindowDelegate> window_delegate_;
base::scoped_nsobject<AtomPreviewItem> preview_item_;
base::scoped_nsobject<AtomTouchBar> touch_bar_;

std::unique_ptr<views::Widget> widget_;

// Event monitor for scroll wheel event.
id wheel_event_monitor_;

Expand All @@ -167,12 +174,10 @@ class NativeWindowMac : public NativeWindow {
NSView* content_view_;

bool is_kiosk_;

bool was_fullscreen_;

bool zoom_to_page_width_;

bool fullscreen_window_title_;
bool resizable_;

NSInteger attention_request_id_; // identifier from requestUserAttention

Expand Down
86 changes: 57 additions & 29 deletions atom/browser/native_window_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string>

#include "atom/browser/native_browser_view_mac.h"
#include "atom/browser/ui/cocoa/atom_native_widget_mac.h"
#include "atom/browser/ui/cocoa/atom_ns_window.h"
#include "atom/browser/ui/cocoa/atom_ns_window_delegate.h"
#include "atom/browser/ui/cocoa/atom_preview_item.h"
Expand All @@ -25,6 +26,8 @@
#include "skia/ext/skia_utils_mac.h"
#include "ui/gfx/skia_util.h"
#include "ui/gl/gpu_switching_manager.h"
#include "ui/views/background.h"
#include "ui/views/cocoa/bridged_native_widget.h"
#include "ui/views/widget/widget.h"

// Custom Quit, Minimize and Full Screen button container for frameless
Expand Down Expand Up @@ -238,6 +241,7 @@ static bool FromV8(v8::Isolate* isolate,
was_fullscreen_(false),
zoom_to_page_width_(false),
fullscreen_window_title_(false),
resizable_(true),
attention_request_id_(0),
title_bar_style_(NORMAL),
always_simple_fullscreen_(false),
Expand All @@ -247,12 +251,16 @@ static bool FromV8(v8::Isolate* isolate,
options.Get(options::kHeight, &height);

NSRect main_screen_rect = [[[NSScreen screens] firstObject] frame];
NSRect cocoa_bounds = NSMakeRect(
round((NSWidth(main_screen_rect) - width) / 2),
round((NSHeight(main_screen_rect) - height) / 2), width, height);
gfx::Rect bounds(round((NSWidth(main_screen_rect) - width) / 2),
round((NSHeight(main_screen_rect) - height) / 2),
width,
height);

bool resizable = true;
options.Get(options::kResizable, &resizable);
options.Get(options::kResizable, &resizable_);
options.Get(options::kTitleBarStyle, &title_bar_style_);
options.Get(options::kZoomToPageWidth, &zoom_to_page_width_);
options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);
options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);

bool minimizable = true;
options.Get(options::kMinimizable, &minimizable);
Expand All @@ -263,8 +271,6 @@ static bool FromV8(v8::Isolate* isolate,
bool closable = true;
options.Get(options::kClosable, &closable);

options.Get(options::kTitleBarStyle, &title_bar_style_);

std::string tabbingIdentifier;
options.Get(options::kTabbingIdentifier, &tabbingIdentifier);

Expand Down Expand Up @@ -299,14 +305,19 @@ static bool FromV8(v8::Isolate* isolate,
if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask;
}
if (resizable) {
styleMask |= NSResizableWindowMask;
}

window_.reset([[AtomNSWindow alloc] initWithContentRect:cocoa_bounds
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:YES]);
// Create views::Widget and assign window_ with it.
// TODO(zcbenz): Get rid of the window_ in future.
widget_.reset(new views::Widget());
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.native_widget = new AtomNativeWidgetMac(styleMask, widget_.get());
widget_->Init(params);
window_ = static_cast<AtomNSWindow*>(widget_->GetNativeWindow());

[window_ setShell:this];
[window_ setEnableLargerThanScreen:enable_larger_than_screen()];

Expand Down Expand Up @@ -357,9 +368,6 @@ static bool FromV8(v8::Isolate* isolate,
}
}

// We will manage window's lifetime ourselves.
[window_ setReleasedWhenClosed:NO];

// Hide the title bar background
if (title_bar_style_ != NORMAL) {
if (@available(macOS 10.10, *)) {
Expand All @@ -380,17 +388,11 @@ static bool FromV8(v8::Isolate* isolate,
}
}

// On macOS the initial window size doesn't include window frame.
// Resize to content bounds.
bool use_content_size = false;
options.Get(options::kUseContentSize, &use_content_size);
if (!has_frame() || !use_content_size)
SetSize(gfx::Size(width, height));

options.Get(options::kZoomToPageWidth, &zoom_to_page_width_);

options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);

options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);
if (!has_frame() || use_content_size)
SetContentSize(gfx::Size(width, height));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this change the semantic meaning of width and height to refer to the contents rather than the whole window (including the border)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The views::Widget forces setting window size with window borders, which is opposite to when we manually created NSWindow. So I need to replace SetSize with SetContentSize here, for frameless window both calls are the same.


// Enable the NSView to accept first mouse event.
bool acceptsFirstMouse = false;
Expand Down Expand Up @@ -448,8 +450,13 @@ static bool FromV8(v8::Isolate* isolate,
// 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())
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];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm curious, what happened without the CALayer set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without setting a layer we would have a black flash when showing window. Cocoa seems to behave differently when we have more than one views with layers.

[[window_ contentView] setWantsLayer:YES];
}

if (has_frame()) {
[content_view_ setFrame:[[window_ contentView] bounds]];
Expand Down Expand Up @@ -712,6 +719,7 @@ static bool FromV8(v8::Isolate* isolate,
void NativeWindowMac::MoveTop() {
[window_ orderWindow:NSWindowAbove relativeTo:0];
}

void NativeWindowMac::SetResizable(bool resizable) {
SetStyleMask(resizable, NSResizableWindowMask);
}
Expand Down Expand Up @@ -974,7 +982,15 @@ static bool FromV8(v8::Isolate* isolate,
void NativeWindowMac::SetBackgroundColor(SkColor color) {
base::ScopedCFTypeRef<CGColorRef> cgcolor(
skia::CGColorCreateFromSkColor(color));
[[[window_ contentView] layer] setBackgroundColor:cgcolor];
// views::Widget adds a layer for the content view.
auto* bridge = views::NativeWidgetMac::GetBridgeForNativeWindow(window_);
NSView* compositor_superview =
static_cast<ui::AcceleratedWidgetMacNSView*>(bridge)->
AcceleratedWidgetGetNSView();
[[compositor_superview layer] setBackgroundColor:cgcolor];
// When using WebContents as content view, the contentView also has layer.
if ([[window_ contentView] wantsLayer])
[[[window_ contentView] layer] setBackgroundColor:cgcolor];
}

void NativeWindowMac::SetHasShadow(bool has_shadow) {
Expand Down Expand Up @@ -1145,7 +1161,7 @@ static bool FromV8(v8::Isolate* isolate,
}

bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
if (window_.get() == window->GetNativeWindow()) {
if (window_ == window->GetNativeWindow()) {
return false;
} else {
if (@available(macOS 10.12, *))
Expand Down Expand Up @@ -1289,6 +1305,18 @@ static bool FromV8(v8::Isolate* isolate,
}
}

views::Widget* NativeWindowMac::GetWidget() {
return widget_.get();
}

const views::Widget* NativeWindowMac::GetWidget() const {
return widget_.get();
}

bool NativeWindowMac::CanResize() const {
return resizable_;
}

void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
bool attach) {
if (is_modal())
Expand Down
5 changes: 4 additions & 1 deletion atom/browser/ui/cocoa/atom_native_widget_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace atom {

class AtomNativeWidgetMac : public views::NativeWidgetMac {
public:
explicit AtomNativeWidgetMac(views::internal::NativeWidgetDelegate* delegate);
AtomNativeWidgetMac(NSUInteger style_mask,
views::internal::NativeWidgetDelegate* delegate);
~AtomNativeWidgetMac() override;

protected:
Expand All @@ -20,6 +21,8 @@ class AtomNativeWidgetMac : public views::NativeWidgetMac {
const views::Widget::InitParams& params) override;

private:
NSUInteger style_mask_;

DISALLOW_COPY_AND_ASSIGN(AtomNativeWidgetMac);
};

Expand Down
13 changes: 11 additions & 2 deletions atom/browser/ui/cocoa/atom_native_widget_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@

#include "atom/browser/ui/cocoa/atom_native_widget_mac.h"

#include "atom/browser/ui/cocoa/atom_ns_window.h"
#include "ui/base/cocoa/window_size_constants.h"

namespace atom {

AtomNativeWidgetMac::AtomNativeWidgetMac(
NSUInteger style_mask,
views::internal::NativeWidgetDelegate* delegate)
: views::NativeWidgetMac(delegate) {}
: views::NativeWidgetMac(delegate),
style_mask_(style_mask) {}

AtomNativeWidgetMac::~AtomNativeWidgetMac() {}

NativeWidgetMacNSWindow* AtomNativeWidgetMac::CreateNSWindow(
const views::Widget::InitParams& params) {
return views::NativeWidgetMac::CreateNSWindow(params);
return [[[AtomNSWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:style_mask_
backing:NSBackingStoreBuffered
defer:YES] autorelease];
}

} // namespace atom
2 changes: 1 addition & 1 deletion atom/browser/ui/cocoa/atom_ns_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ScopedDisableResize {

} // namespace atom

@interface AtomNSWindow : EventDispatchingWindow {
@interface AtomNSWindow : NativeWidgetMacNSWindow {
@private
atom::NativeWindowMac* shell_;
CGFloat windowButtonsInterButtonSpacing_;
Expand Down
6 changes: 3 additions & 3 deletions atom/browser/ui/cocoa/atom_ns_window_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ namespace atom {
class NativeWindowMac;
}

@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate,
NSTouchBarDelegate,
QLPreviewPanelDataSource> {
@interface AtomNSWindowDelegate :
ViewsNSWindowDelegate<NSTouchBarDelegate,
QLPreviewPanelDataSource> {
@private
atom::NativeWindowMac* shell_;
bool is_zooming_;
Expand Down
16 changes: 15 additions & 1 deletion atom/browser/ui/cocoa/atom_ns_window_delegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@
#include "atom/browser/ui/cocoa/atom_preview_item.h"
#include "atom/browser/ui/cocoa/atom_touch_bar.h"
#include "base/mac/mac_util.h"
#include "ui/views/widget/native_widget_mac.h"

@implementation AtomNSWindowDelegate

- (id)initWithShell:(atom::NativeWindowMac*)shell {
if ((self = [super init])) {
// The views library assumes the window delegate must be an instance of
// ViewsNSWindowDelegate, since we don't have a way to override the creation
// of NSWindowDelegate, we have to dynamically replace the window delegate
// on the fly.
// TODO(zcbenz): Add interface in NativeWidgetMac to allow overriding creating
// window delegate.
views::BridgedNativeWidget* bridged_view =
views::NativeWidgetMac::GetBridgeForNativeWindow(
shell->GetNativeWindow());
if ((self = [super initWithBridgedNativeWidget:bridged_view])) {
shell_ = shell;
is_zooming_ = false;
level_ = [shell_->GetNativeWindow() level];
Expand Down Expand Up @@ -106,10 +116,12 @@ - (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
}

- (void)windowDidResize:(NSNotification*)notification {
[super windowDidResize:notification];
shell_->NotifyWindowResize();
}

- (void)windowDidMove:(NSNotification*)notification {
[super windowDidMove:notification];
// TODO(zcbenz): Remove the alias after figuring out a proper
// way to dispatch move.
shell_->NotifyWindowMove();
Expand All @@ -125,10 +137,12 @@ - (void)windowWillMiniaturize:(NSNotification*)notification {
}

- (void)windowDidMiniaturize:(NSNotification*)notification {
[super windowDidMiniaturize:notification];
shell_->NotifyWindowMinimize();
}

- (void)windowDidDeminiaturize:(NSNotification*)notification {
[super windowDidDeminiaturize:notification];
[shell_->GetNativeWindow() setLevel:level_];
shell_->NotifyWindowRestore();
}
Expand Down
3 changes: 1 addition & 2 deletions atom/browser/ui/cocoa/views_delegate_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
void ViewsDelegateMac::OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) {
if (!params->native_widget)
params->native_widget = new views::NativeWidgetMac(delegate);
DCHECK(params->native_widget);
}

ui::ContextFactory* ViewsDelegateMac::GetContextFactory() {
Expand Down