123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- // 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 "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 {
- // 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];
- }
- return self;
- }
- #pragma mark - NSWindowDelegate
- - (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<CGFloat>(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 {
- [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();
- 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 {
- [super windowDidMiniaturize:notification];
- shell_->NotifyWindowMinimize();
- }
- - (void)windowDidDeminiaturize:(NSNotification*)notification {
- [super windowDidDeminiaturize: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<NSToolbar> 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();
- }
- #pragma mark - NSTouchBarDelegate
- - (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
- makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
- API_AVAILABLE(macosx(10.12.2)) {
- if (touchBar && shell_->touch_bar())
- return [shell_->touch_bar() makeItemForIdentifier:identifier];
- else
- return nil;
- }
- #pragma mark - QLPreviewPanelDataSource
- - (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel*)panel {
- return 1;
- }
- - (id<QLPreviewItem>)previewPanel:(QLPreviewPanel*)panel
- previewItemAtIndex:(NSInteger)index {
- return shell_->preview_item();
- }
- @end
|