chore: put NativeWindowMac's methods in order (#27040)

This commit is contained in:
Cheng Zhao 2020-12-18 09:50:51 +09:00 committed by GitHub
parent a55e028b12
commit f99ea7c0ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 222 additions and 228 deletions

View file

@ -236,7 +236,7 @@ class NativeWindow : public base::SupportsUserData,
const std::string& display_name); const std::string& display_name);
virtual void CloseFilePreview(); virtual void CloseFilePreview();
virtual void SetGTKDarkThemeEnabled(bool use_dark_theme) = 0; virtual void SetGTKDarkThemeEnabled(bool use_dark_theme) {}
// Converts between content bounds and window bounds. // Converts between content bounds and window bounds.
virtual gfx::Rect ContentBoundsToWindowBounds( virtual gfx::Rect ContentBoundsToWindowBounds(

View file

@ -32,11 +32,6 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
NativeWindowMac(const gin_helper::Dictionary& options, NativeWindow* parent); NativeWindowMac(const gin_helper::Dictionary& options, NativeWindow* parent);
~NativeWindowMac() override; ~NativeWindowMac() override;
// Cleanup observers when window is getting closed. Note that the destructor
// can be called much later after window gets closed, so we should not do
// cleanup in destructor.
void Cleanup();
// NativeWindow: // NativeWindow:
void SetContentView(views::View* view) override; void SetContentView(views::View* view) override;
void Close() override; void Close() override;
@ -68,11 +63,6 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void MoveTop() override; void MoveTop() override;
bool IsResizable() override; bool IsResizable() override;
void SetMovable(bool movable) override; void SetMovable(bool movable) override;
void SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) override;
void PreviewFile(const std::string& path,
const std::string& display_name) override;
void CloseFilePreview() override;
bool IsMovable() override; bool IsMovable() override;
void SetMinimizable(bool minimizable) override; void SetMinimizable(bool minimizable) override;
bool IsMinimizable() override; bool IsMinimizable() override;
@ -122,32 +112,38 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void SetProgressBar(double progress, const ProgressState state) override; void SetProgressBar(double progress, const ProgressState state) override;
void SetOverlayIcon(const gfx::Image& overlay, void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) override; const std::string& description) override;
void SetVisibleOnAllWorkspaces(bool visible, void SetVisibleOnAllWorkspaces(bool visible,
bool visibleOnFullScreen) override; bool visibleOnFullScreen) override;
bool IsVisibleOnAllWorkspaces() override; bool IsVisibleOnAllWorkspaces() override;
void SetAutoHideCursor(bool auto_hide) override; void SetAutoHideCursor(bool auto_hide) override;
void SetVibrancy(const std::string& type) override;
void SetTrafficLightPosition(base::Optional<gfx::Point> position) override;
base::Optional<gfx::Point> GetTrafficLightPosition() const override;
void RedrawTrafficLights() override;
void SetTouchBar(
std::vector<gin_helper::PersistentDictionary> items) override;
void RefreshTouchBarItem(const std::string& item_id) override;
void SetEscapeTouchBarItem(gin_helper::PersistentDictionary item) override;
void SelectPreviousTab() override; void SelectPreviousTab() override;
void SelectNextTab() override; void SelectNextTab() override;
void MergeAllWindows() override; void MergeAllWindows() override;
void MoveTabToNewWindow() override; void MoveTabToNewWindow() override;
void ToggleTabBar() override; void ToggleTabBar() override;
bool AddTabbedWindow(NativeWindow* window) override; bool AddTabbedWindow(NativeWindow* window) override;
bool SetWindowButtonVisibility(bool visible) override; bool SetWindowButtonVisibility(bool visible) override;
void SetAspectRatio(double aspect_ratio,
void SetVibrancy(const std::string& type) override; const gfx::Size& extra_size) override;
void SetTouchBar( void PreviewFile(const std::string& path,
std::vector<gin_helper::PersistentDictionary> items) override; const std::string& display_name) override;
void RefreshTouchBarItem(const std::string& item_id) override; void CloseFilePreview() override;
void SetEscapeTouchBarItem(gin_helper::PersistentDictionary item) override;
void SetGTKDarkThemeEnabled(bool use_dark_theme) override {}
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;
// Cleanup observers when window is getting closed. Note that the destructor
// can be called much later after window gets closed, so we should not do
// cleanup in destructor.
void Cleanup();
// Use a custom content view instead of Chromium's BridgedContentView. // Use a custom content view instead of Chromium's BridgedContentView.
void OverrideNSWindowContentView(); void OverrideNSWindowContentView();
@ -156,12 +152,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void SetCollectionBehavior(bool on, NSUInteger flag); void SetCollectionBehavior(bool on, NSUInteger flag);
void SetWindowLevel(int level); void SetWindowLevel(int level);
// Custom traffic light positioning
void RedrawTrafficLights() override;
void SetExitingFullScreen(bool flag); void SetExitingFullScreen(bool flag);
void SetTrafficLightPosition(base::Optional<gfx::Point> position) override;
base::Optional<gfx::Point> GetTrafficLightPosition() const override;
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
enum class VisualEffectState { enum class VisualEffectState {
kFollowWindow, kFollowWindow,
@ -189,6 +180,9 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
bool CanResize() const override; bool CanResize() const override;
views::View* GetContentsView() override; views::View* GetContentsView() override;
// ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override;
private: private:
// Add custom layers to the content view. // Add custom layers to the content view.
void AddContentViewLayers(bool minimizable, bool closable); void AddContentViewLayers(bool minimizable, bool closable);

View file

@ -540,73 +540,6 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
NativeWindowMac::~NativeWindowMac() {} NativeWindowMac::~NativeWindowMac() {}
void NativeWindowMac::Cleanup() {
DCHECK(!IsClosed());
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
[NSEvent removeMonitor:wheel_event_monitor_];
}
void NativeWindowMac::RedrawTrafficLights() {
// Ensure maximizable options retain pre-existing state.
SetMaximizable(maximizable_);
// Changing system titlebar is only allowed for "hidden" titleBarStyle.
if (!traffic_light_position_ || title_bar_style_ != TitleBarStyle::kHidden)
return;
if (IsFullscreen())
return;
NSWindow* window = window_;
NSButton* close = [window standardWindowButton:NSWindowCloseButton];
NSButton* miniaturize =
[window standardWindowButton:NSWindowMiniaturizeButton];
NSButton* zoom = [window standardWindowButton:NSWindowZoomButton];
// Safety check just in case apple changes the view structure in a macOS
// update
DCHECK(close.superview);
DCHECK(close.superview.superview);
if (!close.superview || !close.superview.superview)
return;
NSView* titleBarContainerView = close.superview.superview;
// Hide the container when exiting fullscreen, otherwise traffic light buttons
// jump
if (exiting_fullscreen_) {
[titleBarContainerView setHidden:YES];
return;
}
[titleBarContainerView setHidden:NO];
CGFloat buttonHeight = [close frame].size.height;
CGFloat titleBarFrameHeight = buttonHeight + traffic_light_position_->y();
CGRect titleBarRect = titleBarContainerView.frame;
CGFloat titleBarWidth = NSWidth(titleBarRect);
titleBarRect.size.height = titleBarFrameHeight;
titleBarRect.origin.y = window.frame.size.height - titleBarFrameHeight;
[titleBarContainerView setFrame:titleBarRect];
BOOL isRTL = [titleBarContainerView userInterfaceLayoutDirection] ==
NSUserInterfaceLayoutDirectionRightToLeft;
NSArray* windowButtons = @[ close, miniaturize, zoom ];
const CGFloat space_between =
[miniaturize frame].origin.x - [close frame].origin.x;
for (NSUInteger i = 0; i < windowButtons.count; i++) {
NSView* view = [windowButtons objectAtIndex:i];
CGRect rect = [view frame];
if (isRTL) {
CGFloat buttonWidth = NSWidth(rect);
// origin is always top-left, even in RTL
rect.origin.x = titleBarWidth - traffic_light_position_->x() +
(i * space_between) - buttonWidth;
} else {
rect.origin.x = traffic_light_position_->x() + (i * space_between);
}
rect.origin.y = (titleBarFrameHeight - rect.size.height) / 2;
[view setFrameOrigin:rect.origin];
}
}
void NativeWindowMac::SetContentView(views::View* view) { void NativeWindowMac::SetContentView(views::View* view) {
views::View* root_view = GetContentsView(); views::View* root_view = GetContentsView();
if (content_view()) if (content_view())
@ -716,16 +649,6 @@ bool NativeWindowMac::IsVisible() {
return [window_ isVisible] && !occluded && !IsMinimized(); return [window_ isVisible] && !occluded && !IsMinimized();
} }
void NativeWindowMac::SetExitingFullScreen(bool flag) {
exiting_fullscreen_ = flag;
}
void NativeWindowMac::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
base::PostTask(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&NativeWindow::RedrawTrafficLights, GetWeakPtr()));
}
bool NativeWindowMac::IsEnabled() { bool NativeWindowMac::IsEnabled() {
return [window_ attachedSheet] == nil; return [window_ attachedSheet] == nil;
} }
@ -902,31 +825,6 @@ bool NativeWindowMac::IsResizable() {
return [window_ styleMask] & NSWindowStyleMaskResizable; return [window_ styleMask] & NSWindowStyleMaskResizable;
} }
void NativeWindowMac::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
// Reset the behaviour to default if aspect_ratio is set to 0 or less.
if (aspect_ratio > 0.0)
[window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
else
[window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
}
void NativeWindowMac::PreviewFile(const std::string& path,
const std::string& display_name) {
preview_item_.reset([[ElectronPreviewItem alloc]
initWithURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(path)]
title:base::SysUTF8ToNSString(display_name)]);
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
}
void NativeWindowMac::CloseFilePreview() {
if ([QLPreviewPanel sharedPreviewPanelExists]) {
[[QLPreviewPanel sharedPreviewPanel] close];
}
}
void NativeWindowMac::SetMovable(bool movable) { void NativeWindowMac::SetMovable(bool movable) {
[window_ setMovable:movable]; [window_ setMovable:movable];
} }
@ -1406,60 +1304,6 @@ void NativeWindowMac::SetAutoHideCursor(bool auto_hide) {
[window_ setDisableAutoHideCursor:!auto_hide]; [window_ setDisableAutoHideCursor:!auto_hide];
} }
void NativeWindowMac::SelectPreviousTab() {
if (@available(macOS 10.12, *)) {
[window_ selectPreviousTab:nil];
}
}
void NativeWindowMac::SelectNextTab() {
if (@available(macOS 10.12, *)) {
[window_ selectNextTab:nil];
}
}
void NativeWindowMac::MergeAllWindows() {
if (@available(macOS 10.12, *)) {
[window_ mergeAllWindows:nil];
}
}
void NativeWindowMac::MoveTabToNewWindow() {
if (@available(macOS 10.12, *)) {
[window_ moveTabToNewWindow:nil];
}
}
void NativeWindowMac::ToggleTabBar() {
if (@available(macOS 10.12, *)) {
[window_ toggleTabBar:nil];
}
}
bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
if (window_ == window->GetNativeWindow().GetNativeNSWindow()) {
return false;
} else {
if (@available(macOS 10.12, *))
[window_ addTabbedWindow:window->GetNativeWindow().GetNativeNSWindow()
ordered:NSWindowAbove];
}
return true;
}
bool NativeWindowMac::SetWindowButtonVisibility(bool visible) {
if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
return false;
}
window_button_visibility_ = visible;
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:!visible];
return true;
}
void NativeWindowMac::SetVibrancy(const std::string& type) { void NativeWindowMac::SetVibrancy(const std::string& type) {
NSView* vibrant_view = [window_ vibrantView]; NSView* vibrant_view = [window_ vibrantView];
@ -1611,6 +1455,67 @@ base::Optional<gfx::Point> NativeWindowMac::GetTrafficLightPosition() const {
return traffic_light_position_; return traffic_light_position_;
} }
void NativeWindowMac::RedrawTrafficLights() {
// Ensure maximizable options retain pre-existing state.
SetMaximizable(maximizable_);
// Changing system titlebar is only allowed for "hidden" titleBarStyle.
if (!traffic_light_position_ || title_bar_style_ != TitleBarStyle::kHidden)
return;
if (IsFullscreen())
return;
NSWindow* window = window_;
NSButton* close = [window standardWindowButton:NSWindowCloseButton];
NSButton* miniaturize =
[window standardWindowButton:NSWindowMiniaturizeButton];
NSButton* zoom = [window standardWindowButton:NSWindowZoomButton];
// Safety check just in case apple changes the view structure in a macOS
// update
DCHECK(close.superview);
DCHECK(close.superview.superview);
if (!close.superview || !close.superview.superview)
return;
NSView* titleBarContainerView = close.superview.superview;
// Hide the container when exiting fullscreen, otherwise traffic light buttons
// jump
if (exiting_fullscreen_) {
[titleBarContainerView setHidden:YES];
return;
}
[titleBarContainerView setHidden:NO];
CGFloat buttonHeight = [close frame].size.height;
CGFloat titleBarFrameHeight = buttonHeight + traffic_light_position_->y();
CGRect titleBarRect = titleBarContainerView.frame;
CGFloat titleBarWidth = NSWidth(titleBarRect);
titleBarRect.size.height = titleBarFrameHeight;
titleBarRect.origin.y = window.frame.size.height - titleBarFrameHeight;
[titleBarContainerView setFrame:titleBarRect];
BOOL isRTL = [titleBarContainerView userInterfaceLayoutDirection] ==
NSUserInterfaceLayoutDirectionRightToLeft;
NSArray* windowButtons = @[ close, miniaturize, zoom ];
const CGFloat space_between =
[miniaturize frame].origin.x - [close frame].origin.x;
for (NSUInteger i = 0; i < windowButtons.count; i++) {
NSView* view = [windowButtons objectAtIndex:i];
CGRect rect = [view frame];
if (isRTL) {
CGFloat buttonWidth = NSWidth(rect);
// origin is always top-left, even in RTL
rect.origin.x = titleBarWidth - traffic_light_position_->x() +
(i * space_between) - buttonWidth;
} else {
rect.origin.x = traffic_light_position_->x() + (i * space_between);
}
rect.origin.y = (titleBarFrameHeight - rect.size.height) / 2;
[view setFrameOrigin:rect.origin];
}
}
void NativeWindowMac::SetTouchBar( void NativeWindowMac::SetTouchBar(
std::vector<gin_helper::PersistentDictionary> items) { std::vector<gin_helper::PersistentDictionary> items) {
if (@available(macOS 10.12.2, *)) { if (@available(macOS 10.12.2, *)) {
@ -1638,6 +1543,85 @@ void NativeWindowMac::SetEscapeTouchBarItem(
} }
} }
void NativeWindowMac::SelectPreviousTab() {
if (@available(macOS 10.12, *)) {
[window_ selectPreviousTab:nil];
}
}
void NativeWindowMac::SelectNextTab() {
if (@available(macOS 10.12, *)) {
[window_ selectNextTab:nil];
}
}
void NativeWindowMac::MergeAllWindows() {
if (@available(macOS 10.12, *)) {
[window_ mergeAllWindows:nil];
}
}
void NativeWindowMac::MoveTabToNewWindow() {
if (@available(macOS 10.12, *)) {
[window_ moveTabToNewWindow:nil];
}
}
void NativeWindowMac::ToggleTabBar() {
if (@available(macOS 10.12, *)) {
[window_ toggleTabBar:nil];
}
}
bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
if (window_ == window->GetNativeWindow().GetNativeNSWindow()) {
return false;
} else {
if (@available(macOS 10.12, *))
[window_ addTabbedWindow:window->GetNativeWindow().GetNativeNSWindow()
ordered:NSWindowAbove];
}
return true;
}
bool NativeWindowMac::SetWindowButtonVisibility(bool visible) {
if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
return false;
}
window_button_visibility_ = visible;
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:!visible];
return true;
}
void NativeWindowMac::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
// Reset the behaviour to default if aspect_ratio is set to 0 or less.
if (aspect_ratio > 0.0)
[window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)];
else
[window_ setResizeIncrements:NSMakeSize(1.0, 1.0)];
}
void NativeWindowMac::PreviewFile(const std::string& path,
const std::string& display_name) {
preview_item_.reset([[ElectronPreviewItem alloc]
initWithURL:[NSURL fileURLWithPath:base::SysUTF8ToNSString(path)]
title:base::SysUTF8ToNSString(display_name)]);
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
}
void NativeWindowMac::CloseFilePreview() {
if ([QLPreviewPanel sharedPreviewPanelExists]) {
[[QLPreviewPanel sharedPreviewPanel] close];
}
}
gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds( gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds(
const gfx::Rect& bounds) const { const gfx::Rect& bounds) const {
if (has_frame()) { if (has_frame()) {
@ -1664,6 +1648,60 @@ gfx::Rect NativeWindowMac::WindowBoundsToContentBounds(
} }
} }
void NativeWindowMac::Cleanup() {
DCHECK(!IsClosed());
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
[NSEvent removeMonitor:wheel_event_monitor_];
}
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.
if (has_frame()) {
container_view_.reset(
[[ElectronAdaptedContentView alloc] initWithShell:this]);
} else {
container_view_.reset([[FullSizeContentView alloc] init]);
[container_view_ setFrame:[[[window_ contentView] superview] bounds]];
}
[container_view_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[window_ setContentView:container_view_];
AddContentViewLayers(IsMinimizable(), IsClosable());
}
void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
// Changing the styleMask of a frameless windows causes it to change size so
// we explicitly disable resizing while setting it.
ScopedDisableResize disable_resize;
bool was_maximizable = IsMaximizable();
if (on)
[window_ setStyleMask:[window_ styleMask] | flag];
else
[window_ setStyleMask:[window_ styleMask] & (~flag)];
// Change style mask will make the zoom button revert to default, probably
// a bug of Cocoa or macOS.
SetMaximizable(was_maximizable);
}
void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
bool was_maximizable = IsMaximizable();
if (on)
[window_ setCollectionBehavior:[window_ collectionBehavior] | flag];
else
[window_ setCollectionBehavior:[window_ collectionBehavior] & (~flag)];
// Change collectionBehavior will make the zoom button revert to default,
// probably a bug of Cocoa or macOS.
SetMaximizable(was_maximizable);
}
void NativeWindowMac::SetExitingFullScreen(bool flag) {
exiting_fullscreen_ = flag;
}
bool NativeWindowMac::CanResize() const { bool NativeWindowMac::CanResize() const {
return resizable_; return resizable_;
} }
@ -1672,6 +1710,12 @@ views::View* NativeWindowMac::GetContentsView() {
return root_view_.get(); return root_view_.get();
} }
void NativeWindowMac::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
base::PostTask(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&NativeWindow::RedrawTrafficLights, GetWeakPtr()));
}
void NativeWindowMac::AddContentViewLayers(bool minimizable, bool closable) { void NativeWindowMac::AddContentViewLayers(bool minimizable, bool closable) {
// Make sure the bottom corner is rounded for non-modal windows: // Make sure the bottom corner is rounded for non-modal windows:
// http://crbug.com/396264. // http://crbug.com/396264.
@ -1763,50 +1807,6 @@ 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.
if (has_frame()) {
container_view_.reset(
[[ElectronAdaptedContentView alloc] initWithShell:this]);
} else {
container_view_.reset([[FullSizeContentView alloc] init]);
[container_view_ setFrame:[[[window_ contentView] superview] bounds]];
}
[container_view_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[window_ setContentView:container_view_];
AddContentViewLayers(IsMinimizable(), IsClosable());
}
void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
// Changing the styleMask of a frameless windows causes it to change size so
// we explicitly disable resizing while setting it.
ScopedDisableResize disable_resize;
bool was_maximizable = IsMaximizable();
if (on)
[window_ setStyleMask:[window_ styleMask] | flag];
else
[window_ setStyleMask:[window_ styleMask] & (~flag)];
// Change style mask will make the zoom button revert to default, probably
// a bug of Cocoa or macOS.
SetMaximizable(was_maximizable);
}
void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
bool was_maximizable = IsMaximizable();
if (on)
[window_ setCollectionBehavior:[window_ collectionBehavior] | flag];
else
[window_ setCollectionBehavior:[window_ collectionBehavior] & (~flag)];
// Change collectionBehavior will make the zoom button revert to default,
// probably a bug of Cocoa or macOS.
SetMaximizable(was_maximizable);
}
// static // static
NativeWindow* NativeWindow::Create(const gin_helper::Dictionary& options, NativeWindow* NativeWindow::Create(const gin_helper::Dictionary& options,
NativeWindow* parent) { NativeWindow* parent) {