diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 95f0a2d96f..c1f826a827 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -8,8 +8,8 @@ #include #include -#include "atom/browser/browser.h" #include "atom/browser/native_browser_view_mac.h" +#include "atom/browser/ui/cocoa/atom_ns_window_delegate.h" #include "atom/browser/ui/cocoa/atom_touch_bar.h" #include "atom/browser/window_list.h" #include "atom/common/options_switches.h" @@ -165,256 +165,6 @@ bool ScopedDisableResize::disable_resize_ = false; @end -@interface AtomNSWindowDelegate : NSObject { - @private - atom::NativeWindowMac* shell_; - bool is_zooming_; - int level_; - bool is_resizable_; -} -- (id)initWithShell:(atom::NativeWindowMac*)shell; -@end - -@implementation AtomNSWindowDelegate - -- (id)initWithShell:(atom::NativeWindowMac*)shell { - if ((self = [super init])) { - shell_ = shell; - is_zooming_ = false; - level_ = [shell_->GetNativeWindow() level]; - } - return self; -} - -- (void)windowDidChangeOcclusionState:(NSNotification *)notification { - // notification.object is the window that changed its state. - // It's safe to use self.window instead if you don't assign one delegate to many windows - NSWindow *window = notification.object; - - // check occlusion binary flag - if (window.occlusionState & NSWindowOcclusionStateVisible) { - // The app is visible - shell_->NotifyWindowShow(); - } else { - // The app is not visible - shell_->NotifyWindowHide(); - } -} - -// Called when the user clicks the zoom button or selects it from the Window -// menu to determine the "standard size" of the window. -- (NSRect)windowWillUseStandardFrame:(NSWindow*)window - defaultFrame:(NSRect)frame { - if (!shell_->zoom_to_page_width()) - return frame; - - // If the shift key is down, maximize. - if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) - return frame; - - // Get preferred width from observers. Usually the page width. - int preferred_width = 0; - shell_->NotifyWindowRequestPreferredWith(&preferred_width); - - // Never shrink from the current size on zoom. - NSRect window_frame = [window frame]; - CGFloat zoomed_width = std::max(static_cast(preferred_width), - NSWidth(window_frame)); - - // |frame| determines our maximum extents. We need to set the origin of the - // frame -- and only move it left if necessary. - if (window_frame.origin.x + zoomed_width > NSMaxX(frame)) - frame.origin.x = NSMaxX(frame) - zoomed_width; - else - frame.origin.x = window_frame.origin.x; - - // Set the width. Don't touch y or height. - frame.size.width = zoomed_width; - - return frame; -} - -- (void)windowDidBecomeMain:(NSNotification*)notification { - shell_->NotifyWindowFocus(); -} - -- (void)windowDidResignMain:(NSNotification*)notification { - shell_->NotifyWindowBlur(); -} - -- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize { - NSSize newSize = frameSize; - double aspectRatio = shell_->GetAspectRatio(); - - if (aspectRatio > 0.0) { - gfx::Size windowSize = shell_->GetSize(); - gfx::Size contentSize = shell_->GetContentSize(); - gfx::Size extraSize = shell_->GetAspectRatioExtraSize(); - - double extraWidthPlusFrame = - windowSize.width() - contentSize.width() + extraSize.width(); - double extraHeightPlusFrame = - windowSize.height() - contentSize.height() + extraSize.height(); - - newSize.width = - roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio + - extraWidthPlusFrame); - newSize.height = - roundf((newSize.width - extraWidthPlusFrame) / aspectRatio + - extraHeightPlusFrame); - } - - return newSize; -} - -- (void)windowDidResize:(NSNotification*)notification { - shell_->NotifyWindowResize(); -} - -- (void)windowDidMove:(NSNotification*)notification { - // TODO(zcbenz): Remove the alias after figuring out a proper - // way to dispatch move. - shell_->NotifyWindowMove(); - shell_->NotifyWindowMoved(); -} - -- (void)windowWillMiniaturize:(NSNotification*)notification { - NSWindow* window = shell_->GetNativeWindow(); - // store the current status window level to be restored in windowDidDeminiaturize - level_ = [window level]; - [window setLevel:NSNormalWindowLevel]; -} - -- (void)windowDidMiniaturize:(NSNotification*)notification { - shell_->NotifyWindowMinimize(); -} - -- (void)windowDidDeminiaturize:(NSNotification*)notification { - [shell_->GetNativeWindow() setLevel:level_]; - shell_->NotifyWindowRestore(); -} - -- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame { - is_zooming_ = true; - return YES; -} - -- (void)windowDidEndLiveResize:(NSNotification*)notification { - if (is_zooming_) { - if (shell_->IsMaximized()) - shell_->NotifyWindowMaximize(); - else - shell_->NotifyWindowUnmaximize(); - is_zooming_ = false; - } -} - -- (void)windowWillEnterFullScreen:(NSNotification*)notification { - // Setting resizable to true before entering fullscreen - is_resizable_ = shell_->IsResizable(); - shell_->SetResizable(true); - // Hide the native toolbar before entering fullscreen, so there is no visual - // artifacts. - if (@available(macOS 10.10, *)) { - if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { - NSWindow* window = shell_->GetNativeWindow(); - [window setToolbar:nil]; - } - } -} - -- (void)windowDidEnterFullScreen:(NSNotification*)notification { - shell_->NotifyWindowEnterFullScreen(); - - if (@available(macOS 10.10, *)) { - // For frameless window we don't show set title for normal mode since the - // titlebar is expected to be empty, but after entering fullscreen mode we - // have to set one, because title bar is visible here. - NSWindow* window = shell_->GetNativeWindow(); - if ((shell_->transparent() || !shell_->has_frame()) && - // FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under - // fullscreen mode. - // Show title if fullscreen_window_title flag is set - (shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET || - shell_->fullscreen_window_title())) { - [window setTitleVisibility:NSWindowTitleVisible]; - } - - // Restore the native toolbar immediately after entering fullscreen, if we do - // this before leaving fullscreen, traffic light buttons will be jumping. - if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { - base::scoped_nsobject toolbar( - [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); - [toolbar setShowsBaselineSeparator:NO]; - [window setToolbar:toolbar]; - - // Set window style to hide the toolbar, otherwise the toolbar will show in - // fullscreen mode. - shell_->SetStyleMask(true, NSFullSizeContentViewWindowMask); - } - } -} - -- (void)windowWillExitFullScreen:(NSNotification*)notification { - if (@available(macOS 10.10, *)) { - // Restore the titlebar visibility. - NSWindow* window = shell_->GetNativeWindow(); - if ((shell_->transparent() || !shell_->has_frame()) && - (shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET || - shell_->fullscreen_window_title())) { - [window setTitleVisibility:NSWindowTitleHidden]; - } - - // Turn off the style for toolbar. - if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { - shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask); - } - } -} - -- (void)windowDidExitFullScreen:(NSNotification*)notification { - shell_->SetResizable(is_resizable_); - shell_->NotifyWindowLeaveFullScreen(); -} - -- (void)windowWillClose:(NSNotification*)notification { - shell_->NotifyWindowClosed(); - - // Clears the delegate when window is going to be closed, since EL Capitan it - // is possible that the methods of delegate would get called after the window - // has been closed. - [shell_->GetNativeWindow() setDelegate:nil]; -} - -- (BOOL)windowShouldClose:(id)window { - shell_->NotifyWindowCloseButtonClicked(); - return NO; -} - -- (NSRect)window:(NSWindow*)window - willPositionSheet:(NSWindow*)sheet usingRect:(NSRect)rect { - NSView* view = window.contentView; - - rect.origin.x = shell_->GetSheetOffsetX(); - rect.origin.y = view.frame.size.height - shell_->GetSheetOffsetY(); - return rect; -} - -- (void)windowWillBeginSheet:(NSNotification *)notification { - shell_->NotifyWindowSheetBegin(); -} - -- (void)windowDidEndSheet:(NSNotification *)notification { - shell_->NotifyWindowSheetEnd(); -} - -- (IBAction)newWindowForTab:(id)sender { - shell_->NotifyNewWindowForTab(); - atom::Browser::Get()->NewWindowForTab(); -} - -@end - @interface AtomPreviewItem : NSObject @property (nonatomic, retain) NSURL* previewItemURL; diff --git a/atom/browser/ui/cocoa/atom_native_widget_mac.h b/atom/browser/ui/cocoa/atom_native_widget_mac.h index a078fcb1ee..49250239f3 100644 --- a/atom/browser/ui/cocoa/atom_native_widget_mac.h +++ b/atom/browser/ui/cocoa/atom_native_widget_mac.h @@ -16,7 +16,7 @@ class AtomNativeWidgetMac : public views::NativeWidgetMac { protected: // NativeWidgetMac: - views::NativeWidgetMacNSWindow* CreateNSWindow( + NativeWidgetMacNSWindow* CreateNSWindow( const views::Widget::InitParams& params) override; private: diff --git a/atom/browser/ui/cocoa/atom_native_widget_mac.mm b/atom/browser/ui/cocoa/atom_native_widget_mac.mm index 01f2fa3926..f9eaf38fc6 100644 --- a/atom/browser/ui/cocoa/atom_native_widget_mac.mm +++ b/atom/browser/ui/cocoa/atom_native_widget_mac.mm @@ -14,7 +14,7 @@ AtomNativeWidgetMac::AtomNativeWidgetMac( AtomNativeWidgetMac::~AtomNativeWidgetMac() { } -views::NativeWidgetMacNSWindow* AtomNativeWidgetMac::CreateNSWindow( +NativeWidgetMacNSWindow* AtomNativeWidgetMac::CreateNSWindow( const views::Widget::InitParams& params) { return views::NativeWidgetMac::CreateNSWindow(params); } diff --git a/atom/browser/ui/cocoa/atom_ns_window_delegate.h b/atom/browser/ui/cocoa/atom_ns_window_delegate.h new file mode 100644 index 0000000000..2cd4171b14 --- /dev/null +++ b/atom/browser/ui/cocoa/atom_ns_window_delegate.h @@ -0,0 +1,24 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_UI_COCOA_ATOM_NS_WINDOW_DELEGATE_H_ +#define ATOM_BROWSER_UI_COCOA_ATOM_NS_WINDOW_DELEGATE_H_ + +#include "ui/views/cocoa/views_nswindow_delegate.h" + +namespace atom { +class NativeWindowMac; +} + +@interface AtomNSWindowDelegate : NSObject { + @private + atom::NativeWindowMac* shell_; + bool is_zooming_; + int level_; + bool is_resizable_; +} +- (id)initWithShell:(atom::NativeWindowMac*)shell; +@end + +#endif // ATOM_BROWSER_UI_COCOA_ATOM_NS_WINDOW_DELEGATE_H_ diff --git a/atom/browser/ui/cocoa/atom_ns_window_delegate.mm b/atom/browser/ui/cocoa/atom_ns_window_delegate.mm new file mode 100644 index 0000000000..090e8db6e2 --- /dev/null +++ b/atom/browser/ui/cocoa/atom_ns_window_delegate.mm @@ -0,0 +1,249 @@ +// Copyright (c) 2018 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/ui/cocoa/atom_ns_window_delegate.h" + +#include "atom/browser/browser.h" +#include "atom/browser/native_window_mac.h" +#include "base/mac/mac_util.h" + +@implementation AtomNSWindowDelegate + +- (id)initWithShell:(atom::NativeWindowMac*)shell { + if ((self = [super init])) { + shell_ = shell; + is_zooming_ = false; + level_ = [shell_->GetNativeWindow() level]; + } + return self; +} + +- (void)windowDidChangeOcclusionState:(NSNotification *)notification { + // notification.object is the window that changed its state. + // It's safe to use self.window instead if you don't assign one delegate to many windows + NSWindow *window = notification.object; + + // check occlusion binary flag + if (window.occlusionState & NSWindowOcclusionStateVisible) { + // The app is visible + shell_->NotifyWindowShow(); + } else { + // The app is not visible + shell_->NotifyWindowHide(); + } +} + +// Called when the user clicks the zoom button or selects it from the Window +// menu to determine the "standard size" of the window. +- (NSRect)windowWillUseStandardFrame:(NSWindow*)window + defaultFrame:(NSRect)frame { + if (!shell_->zoom_to_page_width()) + return frame; + + // If the shift key is down, maximize. + if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) + return frame; + + // Get preferred width from observers. Usually the page width. + int preferred_width = 0; + shell_->NotifyWindowRequestPreferredWith(&preferred_width); + + // Never shrink from the current size on zoom. + NSRect window_frame = [window frame]; + CGFloat zoomed_width = std::max(static_cast(preferred_width), + NSWidth(window_frame)); + + // |frame| determines our maximum extents. We need to set the origin of the + // frame -- and only move it left if necessary. + if (window_frame.origin.x + zoomed_width > NSMaxX(frame)) + frame.origin.x = NSMaxX(frame) - zoomed_width; + else + frame.origin.x = window_frame.origin.x; + + // Set the width. Don't touch y or height. + frame.size.width = zoomed_width; + + return frame; +} + +- (void)windowDidBecomeMain:(NSNotification*)notification { + shell_->NotifyWindowFocus(); +} + +- (void)windowDidResignMain:(NSNotification*)notification { + shell_->NotifyWindowBlur(); +} + +- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize { + NSSize newSize = frameSize; + double aspectRatio = shell_->GetAspectRatio(); + + if (aspectRatio > 0.0) { + gfx::Size windowSize = shell_->GetSize(); + gfx::Size contentSize = shell_->GetContentSize(); + gfx::Size extraSize = shell_->GetAspectRatioExtraSize(); + + double extraWidthPlusFrame = + windowSize.width() - contentSize.width() + extraSize.width(); + double extraHeightPlusFrame = + windowSize.height() - contentSize.height() + extraSize.height(); + + newSize.width = + roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio + + extraWidthPlusFrame); + newSize.height = + roundf((newSize.width - extraWidthPlusFrame) / aspectRatio + + extraHeightPlusFrame); + } + + return newSize; +} + +- (void)windowDidResize:(NSNotification*)notification { + shell_->NotifyWindowResize(); +} + +- (void)windowDidMove:(NSNotification*)notification { + // TODO(zcbenz): Remove the alias after figuring out a proper + // way to dispatch move. + shell_->NotifyWindowMove(); + shell_->NotifyWindowMoved(); +} + +- (void)windowWillMiniaturize:(NSNotification*)notification { + NSWindow* window = shell_->GetNativeWindow(); + // store the current status window level to be restored in windowDidDeminiaturize + level_ = [window level]; + [window setLevel:NSNormalWindowLevel]; +} + +- (void)windowDidMiniaturize:(NSNotification*)notification { + shell_->NotifyWindowMinimize(); +} + +- (void)windowDidDeminiaturize:(NSNotification*)notification { + [shell_->GetNativeWindow() setLevel:level_]; + shell_->NotifyWindowRestore(); +} + +- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame { + is_zooming_ = true; + return YES; +} + +- (void)windowDidEndLiveResize:(NSNotification*)notification { + if (is_zooming_) { + if (shell_->IsMaximized()) + shell_->NotifyWindowMaximize(); + else + shell_->NotifyWindowUnmaximize(); + is_zooming_ = false; + } +} + +- (void)windowWillEnterFullScreen:(NSNotification*)notification { + // Setting resizable to true before entering fullscreen + is_resizable_ = shell_->IsResizable(); + shell_->SetResizable(true); + // Hide the native toolbar before entering fullscreen, so there is no visual + // artifacts. + if (@available(macOS 10.10, *)) { + if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { + NSWindow* window = shell_->GetNativeWindow(); + [window setToolbar:nil]; + } + } +} + +- (void)windowDidEnterFullScreen:(NSNotification*)notification { + shell_->NotifyWindowEnterFullScreen(); + + if (@available(macOS 10.10, *)) { + // For frameless window we don't show set title for normal mode since the + // titlebar is expected to be empty, but after entering fullscreen mode we + // have to set one, because title bar is visible here. + NSWindow* window = shell_->GetNativeWindow(); + if ((shell_->transparent() || !shell_->has_frame()) && + // FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under + // fullscreen mode. + // Show title if fullscreen_window_title flag is set + (shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET || + shell_->fullscreen_window_title())) { + [window setTitleVisibility:NSWindowTitleVisible]; + } + + // Restore the native toolbar immediately after entering fullscreen, if we do + // this before leaving fullscreen, traffic light buttons will be jumping. + if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { + base::scoped_nsobject toolbar( + [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); + [toolbar setShowsBaselineSeparator:NO]; + [window setToolbar:toolbar]; + + // Set window style to hide the toolbar, otherwise the toolbar will show in + // fullscreen mode. + shell_->SetStyleMask(true, NSFullSizeContentViewWindowMask); + } + } +} + +- (void)windowWillExitFullScreen:(NSNotification*)notification { + if (@available(macOS 10.10, *)) { + // Restore the titlebar visibility. + NSWindow* window = shell_->GetNativeWindow(); + if ((shell_->transparent() || !shell_->has_frame()) && + (shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET || + shell_->fullscreen_window_title())) { + [window setTitleVisibility:NSWindowTitleHidden]; + } + + // Turn off the style for toolbar. + if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { + shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask); + } + } +} + +- (void)windowDidExitFullScreen:(NSNotification*)notification { + shell_->SetResizable(is_resizable_); + shell_->NotifyWindowLeaveFullScreen(); +} + +- (void)windowWillClose:(NSNotification*)notification { + shell_->NotifyWindowClosed(); + + // Clears the delegate when window is going to be closed, since EL Capitan it + // is possible that the methods of delegate would get called after the window + // has been closed. + [shell_->GetNativeWindow() setDelegate:nil]; +} + +- (BOOL)windowShouldClose:(id)window { + shell_->NotifyWindowCloseButtonClicked(); + return NO; +} + +- (NSRect)window:(NSWindow*)window + willPositionSheet:(NSWindow*)sheet usingRect:(NSRect)rect { + NSView* view = window.contentView; + + rect.origin.x = shell_->GetSheetOffsetX(); + rect.origin.y = view.frame.size.height - shell_->GetSheetOffsetY(); + return rect; +} + +- (void)windowWillBeginSheet:(NSNotification *)notification { + shell_->NotifyWindowSheetBegin(); +} + +- (void)windowDidEndSheet:(NSNotification *)notification { + shell_->NotifyWindowSheetEnd(); +} + +- (IBAction)newWindowForTab:(id)sender { + shell_->NotifyNewWindowForTab(); + atom::Browser::Get()->NewWindowForTab(); +} + +@end diff --git a/filenames.gypi b/filenames.gypi index a76b5d08d1..afed5285aa 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -318,6 +318,8 @@ 'atom/browser/ui/cocoa/atom_menu_controller.mm', 'atom/browser/ui/cocoa/atom_native_widget_mac.h', 'atom/browser/ui/cocoa/atom_native_widget_mac.mm', + 'atom/browser/ui/cocoa/atom_ns_window_delegate.h', + 'atom/browser/ui/cocoa/atom_ns_window_delegate.mm', 'atom/browser/ui/cocoa/atom_touch_bar.h', 'atom/browser/ui/cocoa/atom_touch_bar.mm', 'atom/browser/ui/cocoa/views_delegate_mac.h', diff --git a/script/cpplint.py b/script/cpplint.py index 78419745c2..346a3c18a8 100755 --- a/script/cpplint.py +++ b/script/cpplint.py @@ -12,6 +12,7 @@ IGNORE_FILES = set(os.path.join(*components) for components in [ ['atom', 'browser', 'mac', 'atom_application_delegate.h'], ['atom', 'browser', 'resources', 'win', 'resource.h'], ['atom', 'browser', 'ui', 'cocoa', 'atom_menu_controller.h'], + ['atom', 'browser', 'ui', 'cocoa', 'atom_ns_window_delegate.h'], ['atom', 'browser', 'ui', 'cocoa', 'atom_touch_bar.h'], ['atom', 'browser', 'ui', 'cocoa', 'touch_bar_forward_declarations.h'], ['atom', 'browser', 'ui', 'cocoa', 'NSColor+Hex.h'],