Index: chrome/browser/ui/cocoa/fullscreen/immersive_fullscreen_controller.mm |
diff --git a/chrome/browser/ui/cocoa/fullscreen/immersive_fullscreen_controller.mm b/chrome/browser/ui/cocoa/fullscreen/immersive_fullscreen_controller.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..766fbff0c2939fe803d33eaf12b2d804bd748b82 |
--- /dev/null |
+++ b/chrome/browser/ui/cocoa/fullscreen/immersive_fullscreen_controller.mm |
@@ -0,0 +1,196 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "chrome/browser/ui/cocoa/fullscreen/immersive_fullscreen_controller.h" |
+ |
+#include "base/mac/sdk_forward_declarations.h" |
+#import "chrome/browser/ui/cocoa/browser_window_controller.h" |
+#import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_layout_manager.h" |
+#import "ui/base/cocoa/tracking_area.h" |
+ |
+namespace { |
+ |
+// The height from the top of the screen that will show the menubar. |
+const CGFloat kMenubarShowZoneHeight = 4; |
+ |
+// The height from the top of the screen that will hide the menubar. |
+// The height must be greater than the menubar's height. |
+const CGFloat kMenubarHideZoneHeight = 28; |
+ |
+} // namespace |
+ |
+@interface ImmersiveFullscreenController () { |
+ BrowserWindowController* browserController_; // weak |
+ |
+ // Used to track the mouse movements to show/hide the menu. |
+ base::scoped_nsobject<CrTrackingArea> trackingArea_; |
+ |
+ // The content view for the window. |
+ NSView* contentView_; // weak |
+ |
+ // Tracks the currently requested system fullscreen mode, used to show or |
+ // hide the menubar. Its value is as follows: |
+ // + |kFullScreenModeNormal| - when the window is not main or not fullscreen, |
+ // + |kFullScreenModeHideDock| - when the user interacts with the top of the |
+ // screen |
+ // + |kFullScreenModeHideAll| - when the conditions don't meet the first two |
+ // modes. |
+ base::mac::FullScreenMode systemFullscreenMode_; |
+ |
+ // True if the menubar should be shown on the screen. |
+ BOOL shouldShowMenubar_; |
+} |
+ |
+// Whether the current screen is expected to have a menu bar, regardless of |
+// current visibility of the menu bar. |
+- (BOOL)doesScreenHaveMenuBar; |
+ |
+// Returns |kFullScreenModeHideAll| when the menubar is hidden and |
+// |kFullScreenModeHideDock| when the menubar is shown. |
+- (base::mac::FullScreenMode)desiredSystemFullscreenMode; |
+ |
+// Adjusts the AppKit Fullscreen options of the application. |
+- (void)setSystemFullscreenModeTo:(base::mac::FullScreenMode)mode; |
+ |
+// Methods that update and remove the tracking area. |
+- (void)updateTrackingArea; |
+- (void)removeTrackingArea; |
+ |
+@end |
+ |
+@implementation ImmersiveFullscreenController |
+ |
+- (id)initWithBrowserController:(BrowserWindowController*)bwc { |
+ if ((self = [super init])) { |
+ browserController_ = bwc; |
+ systemFullscreenMode_ = base::mac::kFullScreenModeNormal; |
+ contentView_ = [[bwc window] contentView]; |
+ |
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; |
+ NSWindow* window = [browserController_ window]; |
+ |
+ [nc addObserver:self |
+ selector:@selector(windowDidBecomeMain:) |
+ name:NSWindowDidBecomeMainNotification |
+ object:window]; |
+ |
+ [nc addObserver:self |
+ selector:@selector(windowDidResignMain:) |
+ name:NSWindowDidResignMainNotification |
+ object:window]; |
+ |
+ [self updateTrackingArea]; |
+ } |
+ |
+ return self; |
+} |
+ |
+- (void)dealloc { |
+ [[NSNotificationCenter defaultCenter] removeObserver:self]; |
+ |
+ [self removeTrackingArea]; |
+ [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; |
+ |
+ [super dealloc]; |
+} |
+ |
+- (void)updateMenuBarAndDockVisibility { |
+ BOOL isMouseOnScreen = |
+ NSMouseInRect([NSEvent mouseLocation], |
+ [[browserController_ window] screen].frame, false); |
+ |
+ if (isMouseOnScreen || ![browserController_ isInImmersiveFullscreen]) |
+ [self setSystemFullscreenModeTo:base::mac::kFullScreenModeNormal]; |
+ else if (![self doesScreenHaveMenuBar]) |
+ [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock]; |
+ else |
+ [self setSystemFullscreenModeTo:[self desiredSystemFullscreenMode]]; |
+} |
+ |
+- (BOOL)shouldShowMenubar { |
+ return [self doesScreenHaveMenuBar] && shouldShowMenubar_; |
+} |
+ |
+- (void)windowDidBecomeMain:(NSNotification*)notification { |
+ [self updateMenuBarAndDockVisibility]; |
+} |
+ |
+- (void)windowDidResignMain:(NSNotification*)notification { |
+ [self updateMenuBarAndDockVisibility]; |
+} |
+ |
+- (base::mac::FullScreenMode)desiredSystemFullscreenMode { |
+ return [self shouldShowMenubar] ? base::mac::kFullScreenModeHideDock |
+ : base::mac::kFullScreenModeHideAll; |
+} |
+ |
+- (BOOL)doesScreenHaveMenuBar { |
+ NSScreen* screen = [[browserController_ window] screen]; |
+ NSScreen* primaryScreen = [[NSScreen screens] firstObject]; |
+ BOOL isWindowOnPrimaryScreen = screen == primaryScreen; |
+ |
+ BOOL eachScreenShouldHaveMenuBar = [NSScreen screensHaveSeparateSpaces]; |
+ return eachScreenShouldHaveMenuBar ?: isWindowOnPrimaryScreen; |
+} |
+ |
+- (void)setSystemFullscreenModeTo:(base::mac::FullScreenMode)mode { |
+ if (mode == systemFullscreenMode_) |
+ return; |
+ |
+ if (systemFullscreenMode_ == base::mac::kFullScreenModeNormal) |
+ base::mac::RequestFullScreen(mode); |
+ else if (mode == base::mac::kFullScreenModeNormal) |
+ base::mac::ReleaseFullScreen(systemFullscreenMode_); |
+ else |
+ base::mac::SwitchFullScreenModes(systemFullscreenMode_, mode); |
+ |
+ systemFullscreenMode_ = mode; |
+} |
+ |
+- (void)updateTrackingArea { |
+ if (trackingArea_) |
+ [self removeTrackingArea]; |
+ |
+ CGFloat trackingHeight = |
+ shouldShowMenubar_ ? kMenubarHideZoneHeight : kMenubarShowZoneHeight; |
+ NSRect trackingFrame = [contentView_ bounds]; |
+ trackingFrame.origin.y = NSMaxY(trackingFrame) - trackingHeight; |
+ trackingFrame.size.height = trackingHeight; |
+ |
+ // Create and add a new tracking area for |frame|. |
+ trackingArea_.reset([[CrTrackingArea alloc] |
+ initWithRect:trackingFrame |
+ options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow |
+ owner:self |
+ userInfo:nil]); |
+ DCHECK(contentView_); |
+ [contentView_ addTrackingArea:trackingArea_]; |
+} |
+ |
+- (void)removeTrackingArea { |
+ if (trackingArea_) { |
+ DCHECK(contentView_); // |contentView_| better be valid. |
+ [contentView_ removeTrackingArea:trackingArea_]; |
+ trackingArea_.reset(); |
+ } |
+} |
+ |
+- (void)mouseEntered:(NSEvent*)event { |
+ if (shouldShowMenubar_) |
+ return; |
+ |
+ shouldShowMenubar_ = YES; |
+ [self updateTrackingArea]; |
+ [self updateMenuBarAndDockVisibility]; |
+} |
+ |
+- (void)mouseExited:(NSEvent*)event { |
+ DCHECK_EQ([event trackingArea], trackingArea_.get()); |
+ |
+ shouldShowMenubar_ = NO; |
+ [self updateTrackingArea]; |
+ [self updateMenuBarAndDockVisibility]; |
+} |
+ |
+@end |