atom_ns_window_delegate.mm 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright (c) 2018 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/ui/cocoa/atom_ns_window_delegate.h"
  5. #include "atom/browser/browser.h"
  6. #include "atom/browser/native_window_mac.h"
  7. #include "atom/browser/ui/cocoa/atom_preview_item.h"
  8. #include "atom/browser/ui/cocoa/atom_touch_bar.h"
  9. #include "base/mac/mac_util.h"
  10. #include "ui/views/widget/native_widget_mac.h"
  11. @implementation AtomNSWindowDelegate
  12. - (id)initWithShell:(atom::NativeWindowMac*)shell {
  13. // The views library assumes the window delegate must be an instance of
  14. // ViewsNSWindowDelegate, since we don't have a way to override the creation
  15. // of NSWindowDelegate, we have to dynamically replace the window delegate
  16. // on the fly.
  17. // TODO(zcbenz): Add interface in NativeWidgetMac to allow overriding creating
  18. // window delegate.
  19. views::BridgedNativeWidget* bridged_view =
  20. views::NativeWidgetMac::GetBridgeForNativeWindow(
  21. shell->GetNativeWindow());
  22. if ((self = [super initWithBridgedNativeWidget:bridged_view])) {
  23. shell_ = shell;
  24. is_zooming_ = false;
  25. level_ = [shell_->GetNativeWindow() level];
  26. }
  27. return self;
  28. }
  29. #pragma mark - NSWindowDelegate
  30. - (void)windowDidChangeOcclusionState:(NSNotification*)notification {
  31. // notification.object is the window that changed its state.
  32. // It's safe to use self.window instead if you don't assign one delegate to
  33. // many windows
  34. NSWindow* window = notification.object;
  35. // check occlusion binary flag
  36. if (window.occlusionState & NSWindowOcclusionStateVisible) {
  37. // The app is visible
  38. shell_->NotifyWindowShow();
  39. } else {
  40. // The app is not visible
  41. shell_->NotifyWindowHide();
  42. }
  43. }
  44. // Called when the user clicks the zoom button or selects it from the Window
  45. // menu to determine the "standard size" of the window.
  46. - (NSRect)windowWillUseStandardFrame:(NSWindow*)window
  47. defaultFrame:(NSRect)frame {
  48. if (!shell_->zoom_to_page_width())
  49. return frame;
  50. // If the shift key is down, maximize.
  51. if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask)
  52. return frame;
  53. // Get preferred width from observers. Usually the page width.
  54. int preferred_width = 0;
  55. shell_->NotifyWindowRequestPreferredWith(&preferred_width);
  56. // Never shrink from the current size on zoom.
  57. NSRect window_frame = [window frame];
  58. CGFloat zoomed_width =
  59. std::max(static_cast<CGFloat>(preferred_width), NSWidth(window_frame));
  60. // |frame| determines our maximum extents. We need to set the origin of the
  61. // frame -- and only move it left if necessary.
  62. if (window_frame.origin.x + zoomed_width > NSMaxX(frame))
  63. frame.origin.x = NSMaxX(frame) - zoomed_width;
  64. else
  65. frame.origin.x = window_frame.origin.x;
  66. // Set the width. Don't touch y or height.
  67. frame.size.width = zoomed_width;
  68. return frame;
  69. }
  70. - (void)windowDidBecomeMain:(NSNotification*)notification {
  71. shell_->NotifyWindowFocus();
  72. }
  73. - (void)windowDidResignMain:(NSNotification*)notification {
  74. shell_->NotifyWindowBlur();
  75. }
  76. - (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
  77. NSSize newSize = frameSize;
  78. double aspectRatio = shell_->GetAspectRatio();
  79. if (aspectRatio > 0.0) {
  80. gfx::Size windowSize = shell_->GetSize();
  81. gfx::Size contentSize = shell_->GetContentSize();
  82. gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
  83. double extraWidthPlusFrame =
  84. windowSize.width() - contentSize.width() + extraSize.width();
  85. double extraHeightPlusFrame =
  86. windowSize.height() - contentSize.height() + extraSize.height();
  87. newSize.width =
  88. roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
  89. extraWidthPlusFrame);
  90. newSize.height =
  91. roundf((newSize.width - extraWidthPlusFrame) / aspectRatio +
  92. extraHeightPlusFrame);
  93. }
  94. return newSize;
  95. }
  96. - (void)windowDidResize:(NSNotification*)notification {
  97. [super windowDidResize:notification];
  98. shell_->NotifyWindowResize();
  99. }
  100. - (void)windowDidMove:(NSNotification*)notification {
  101. [super windowDidMove:notification];
  102. // TODO(zcbenz): Remove the alias after figuring out a proper
  103. // way to dispatch move.
  104. shell_->NotifyWindowMove();
  105. shell_->NotifyWindowMoved();
  106. }
  107. - (void)windowWillMiniaturize:(NSNotification*)notification {
  108. NSWindow* window = shell_->GetNativeWindow();
  109. // store the current status window level to be restored in
  110. // windowDidDeminiaturize
  111. level_ = [window level];
  112. [window setLevel:NSNormalWindowLevel];
  113. }
  114. - (void)windowDidMiniaturize:(NSNotification*)notification {
  115. [super windowDidMiniaturize:notification];
  116. shell_->NotifyWindowMinimize();
  117. }
  118. - (void)windowDidDeminiaturize:(NSNotification*)notification {
  119. [super windowDidDeminiaturize:notification];
  120. [shell_->GetNativeWindow() setLevel:level_];
  121. shell_->NotifyWindowRestore();
  122. }
  123. - (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame {
  124. is_zooming_ = true;
  125. return YES;
  126. }
  127. - (void)windowDidEndLiveResize:(NSNotification*)notification {
  128. if (is_zooming_) {
  129. if (shell_->IsMaximized())
  130. shell_->NotifyWindowMaximize();
  131. else
  132. shell_->NotifyWindowUnmaximize();
  133. is_zooming_ = false;
  134. }
  135. }
  136. - (void)windowWillEnterFullScreen:(NSNotification*)notification {
  137. // Setting resizable to true before entering fullscreen
  138. is_resizable_ = shell_->IsResizable();
  139. shell_->SetResizable(true);
  140. // Hide the native toolbar before entering fullscreen, so there is no visual
  141. // artifacts.
  142. if (@available(macOS 10.10, *)) {
  143. if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
  144. NSWindow* window = shell_->GetNativeWindow();
  145. [window setToolbar:nil];
  146. }
  147. }
  148. }
  149. - (void)windowDidEnterFullScreen:(NSNotification*)notification {
  150. shell_->NotifyWindowEnterFullScreen();
  151. if (@available(macOS 10.10, *)) {
  152. // For frameless window we don't show set title for normal mode since the
  153. // titlebar is expected to be empty, but after entering fullscreen mode we
  154. // have to set one, because title bar is visible here.
  155. NSWindow* window = shell_->GetNativeWindow();
  156. if ((shell_->transparent() || !shell_->has_frame()) &&
  157. // FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under
  158. // fullscreen mode.
  159. // Show title if fullscreen_window_title flag is set
  160. (shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET ||
  161. shell_->fullscreen_window_title())) {
  162. [window setTitleVisibility:NSWindowTitleVisible];
  163. }
  164. // Restore the native toolbar immediately after entering fullscreen, if we
  165. // do this before leaving fullscreen, traffic light buttons will be jumping.
  166. if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
  167. base::scoped_nsobject<NSToolbar> toolbar(
  168. [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
  169. [toolbar setShowsBaselineSeparator:NO];
  170. [window setToolbar:toolbar];
  171. // Set window style to hide the toolbar, otherwise the toolbar will show
  172. // in fullscreen mode.
  173. shell_->SetStyleMask(true, NSFullSizeContentViewWindowMask);
  174. }
  175. }
  176. }
  177. - (void)windowWillExitFullScreen:(NSNotification*)notification {
  178. if (@available(macOS 10.10, *)) {
  179. // Restore the titlebar visibility.
  180. NSWindow* window = shell_->GetNativeWindow();
  181. if ((shell_->transparent() || !shell_->has_frame()) &&
  182. (shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET ||
  183. shell_->fullscreen_window_title())) {
  184. [window setTitleVisibility:NSWindowTitleHidden];
  185. }
  186. // Turn off the style for toolbar.
  187. if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) {
  188. shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask);
  189. }
  190. }
  191. }
  192. - (void)windowDidExitFullScreen:(NSNotification*)notification {
  193. shell_->SetResizable(is_resizable_);
  194. shell_->NotifyWindowLeaveFullScreen();
  195. }
  196. - (void)windowWillClose:(NSNotification*)notification {
  197. shell_->NotifyWindowClosed();
  198. // Clears the delegate when window is going to be closed, since EL Capitan it
  199. // is possible that the methods of delegate would get called after the window
  200. // has been closed.
  201. [shell_->GetNativeWindow() setDelegate:nil];
  202. }
  203. - (BOOL)windowShouldClose:(id)window {
  204. shell_->NotifyWindowCloseButtonClicked();
  205. return NO;
  206. }
  207. - (NSRect)window:(NSWindow*)window
  208. willPositionSheet:(NSWindow*)sheet
  209. usingRect:(NSRect)rect {
  210. NSView* view = window.contentView;
  211. rect.origin.x = shell_->GetSheetOffsetX();
  212. rect.origin.y = view.frame.size.height - shell_->GetSheetOffsetY();
  213. return rect;
  214. }
  215. - (void)windowWillBeginSheet:(NSNotification*)notification {
  216. shell_->NotifyWindowSheetBegin();
  217. }
  218. - (void)windowDidEndSheet:(NSNotification*)notification {
  219. shell_->NotifyWindowSheetEnd();
  220. }
  221. - (IBAction)newWindowForTab:(id)sender {
  222. shell_->NotifyNewWindowForTab();
  223. atom::Browser::Get()->NewWindowForTab();
  224. }
  225. #pragma mark - NSTouchBarDelegate
  226. - (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
  227. makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
  228. API_AVAILABLE(macosx(10.12.2)) {
  229. if (touchBar && shell_->touch_bar())
  230. return [shell_->touch_bar() makeItemForIdentifier:identifier];
  231. else
  232. return nil;
  233. }
  234. #pragma mark - QLPreviewPanelDataSource
  235. - (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel*)panel {
  236. return 1;
  237. }
  238. - (id<QLPreviewItem>)previewPanel:(QLPreviewPanel*)panel
  239. previewItemAtIndex:(NSInteger)index {
  240. return shell_->preview_item();
  241. }
  242. @end