File: immersive_fullscreen_controller.mm

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (205 lines) | stat: -rw-r--r-- 6,567 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// 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"

#import "base/mac/mac_util.h"
#include "base/mac/sdk_forward_declarations.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.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 value must be greater than the menubar's height of 22px.
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 isMenubarVisible_;
}

// Whether the current screen is expected to have a menubar, regardless of
// current visibility of the menubar.
- (BOOL)doesScreenHaveMenubar;

// Adjusts the AppKit Fullscreen options of the application.
- (void)setSystemFullscreenModeTo:(base::mac::FullScreenMode)mode;

// Sets |isMenubarVisible_|. If the value has changed, update the tracking
// area, the dock, and the menubar
- (void)setMenubarVisibility:(BOOL)visible;

// Methods that update and remove the tracking area.
- (void)updateTrackingArea;
- (void)removeTrackingArea;

@end

@implementation ImmersiveFullscreenController

- (instancetype)initWithBrowserController:(BrowserWindowController*)bwc {
  if ((self = [super init])) {
    browserController_ = bwc;
    systemFullscreenMode_ = base::mac::kFullScreenModeNormal;

    contentView_ = [[bwc window] contentView];
    DCHECK(contentView_);

    isMenubarVisible_ = NO;

    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 shouldShowMenubar])
    [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideDock];
  else
    [self setSystemFullscreenModeTo:base::mac::kFullScreenModeHideAll];
}

- (BOOL)shouldShowMenubar {
  return [self doesScreenHaveMenubar] && isMenubarVisible_;
}

- (void)windowDidBecomeMain:(NSNotification*)notification {
  [self updateMenuBarAndDockVisibility];
}

- (void)windowDidResignMain:(NSNotification*)notification {
  [self updateMenuBarAndDockVisibility];
}

- (BOOL)doesScreenHaveMenubar {
  NSScreen* screen = [[browserController_ window] screen];
  NSScreen* primaryScreen = [[NSScreen screens] firstObject];
  BOOL isWindowOnPrimaryScreen = [screen isEqual: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)setMenubarVisibility:(BOOL)visible {
  if (isMenubarVisible_ == visible)
    return;

  isMenubarVisible_ = visible;
  [self updateTrackingArea];
  [self updateMenuBarAndDockVisibility];
}

- (void)updateTrackingArea {
  [self removeTrackingArea];

  CGFloat trackingHeight =
      isMenubarVisible_ ? kMenubarHideZoneHeight : kMenubarShowZoneHeight;
  NSRect trackingFrame = [contentView_ bounds];
  trackingFrame.origin.y = NSMaxY(trackingFrame) - trackingHeight;
  trackingFrame.size.height = trackingHeight;

  // If we replace the tracking area with a new one under the cursor, the new
  // tracking area might not receive a |-mouseEntered:| or |-mouseExited| call.
  // As a result, we should also track the mouse's movements so that the
  // so the menubar won't get stuck.
  NSTrackingAreaOptions options =
      NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow;
  if (isMenubarVisible_)
    options |= NSTrackingMouseMoved;

  // Create and add a new tracking area for |frame|.
  trackingArea_.reset([[CrTrackingArea alloc] initWithRect:trackingFrame
                                                   options:options
                                                     owner:self
                                                  userInfo:nil]);
  [contentView_ addTrackingArea:trackingArea_];
}

- (void)removeTrackingArea {
  if (trackingArea_) {
    [contentView_ removeTrackingArea:trackingArea_];
    trackingArea_.reset();
  }
}

- (void)mouseEntered:(NSEvent*)event {
  [self setMenubarVisibility:YES];
}

- (void)mouseExited:(NSEvent*)event {
  [self setMenubarVisibility:NO];
}

- (void)mouseMoved:(NSEvent*)event {
  [self setMenubarVisibility:[trackingArea_
                                 mouseInsideTrackingAreaForView:contentView_]];
}

@end