File: immersive_mode_controller_cocoa.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (234 lines) | stat: -rw-r--r-- 8,928 bytes parent folder | download | duplicates (5)
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_REMOTE_COCOA_APP_SHIM_IMMERSIVE_MODE_CONTROLLER_COCOA_H_
#define COMPONENTS_REMOTE_COCOA_APP_SHIM_IMMERSIVE_MODE_CONTROLLER_COCOA_H_

#import <AppKit/AppKit.h>

#include <optional>

#include "base/scoped_observation.h"
#import "components/remote_cocoa/app_shim/bridged_content_view.h"
#import "components/remote_cocoa/app_shim/browser_native_widget_window_mac.h"
#import "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h"
#import "components/remote_cocoa/app_shim/native_widget_mac_overlay_nswindow.h"
#include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
#include "components/remote_cocoa/common/native_widget_ns_window.mojom-shared.h"
#include "ui/display/display_observer.h"
#include "ui/display/screen.h"

@class ImmersiveModeMapper;

namespace remote_cocoa {
class ImmersiveModeControllerCocoa;
}  // namespace remote_cocoa

// Host of the overlay view.
@interface ImmersiveModeTitlebarViewController
    : NSTitlebarAccessoryViewController {
  NSView* __strong _blank_separator_view;
  base::WeakPtr<remote_cocoa::ImmersiveModeControllerCocoa>
      _immersive_mode_controller;
}
@end

namespace gfx {
class Rect;
}

namespace remote_cocoa {

// TODO(mek): This should not be exported and used outside of remote_cocoa. So
// figure out how to restructure code so callers outside of remote_cocoa can
// stop existing.
REMOTE_COCOA_APP_SHIM_EXPORT bool IsNSToolbarFullScreenWindow(NSWindow* window);

// Manages a single fullscreen session.
class REMOTE_COCOA_APP_SHIM_EXPORT ImmersiveModeControllerCocoa
    : public display::DisplayObserver {
 public:
  explicit ImmersiveModeControllerCocoa(
      BrowserNativeWidgetWindow* browser_window,
      NativeWidgetMacOverlayNSWindow* overlay_window);
  ~ImmersiveModeControllerCocoa() override;

  // Must be called once and only once after construction. Prevents the side-
  // effects of adding a toolbar accessory from accessing partially constructed
  // objects.
  virtual void Init();
  bool is_initialized() { return initialized_; }

  virtual void FullscreenTransitionCompleted();
  virtual void OnTopViewBoundsChanged(const gfx::Rect& bounds);
  virtual void UpdateToolbarVisibility(
      std::optional<mojom::ToolbarVisibilityStyle> style);

  // Reveal top chrome leaving it visible until all outstanding calls to
  // RevealLock() are balanced with RevealUnlock(). Reveal locks will persist
  // through calls to UpdateToolbarVisibility(). For example, the current
  // ToolbarVisibilityStyle is set to kAlways and RevealLock() has been called.
  // If ToolbarVisibilityStyle is then changed to kAutohide, top
  // chrome will stay on screen until RevealUnlock() is called. At that point
  // top chrome will autohide.
  void RevealLock();
  void RevealUnlock();
  int reveal_lock_count() { return reveal_lock_count_; }

  // When set to true, calls to RevealLock() and RevealUnlock() will have no
  // visual effect. The lock/unlock calls are still counted and will go into
  // effect when this function is called with false.
  void SetIgnoreRevealLocks(bool ignore);

  // Called when a reveal lock/unlock is ready to take effect.
  virtual void RevealLocked();
  virtual void RevealUnlocked();

  // Returns true if the toolbar is visible, either because there are
  // outstanding reveal locks, or the user hovers over the upper border of the
  // screen.
  bool IsToolbarRevealed();

  // Called when the reveal status changes.
  void OnToolbarRevealMaybeChanged();

  // Called when the menu bar reveal status changes.
  void OnMenuBarRevealChanged();

  // Called when a child window is added to the observed windows.
  // `ObserveChildWindows` controls which windows are being observed.
  virtual void OnChildWindowAdded(NSWindow* child);

  // Called when a child window is removed from the observed windows.
  virtual void OnChildWindowRemoved(NSWindow* child);

  // Start observing child windows of `window`.
  void ObserveChildWindows(NSWindow* window);

  // Stop observing child windows of `window`.
  void StopObservingChildWindows(NSWindow* window);

  // Return true if the child window should trigger OnChildWindowAdded and
  // OnChildWindowRemoved events, otherwise return false.
  // Called for browser window children that survive the transition to
  // fullscreen.
  virtual bool ShouldObserveChildWindow(NSWindow* child);

  NSWindow* browser_window();
  NativeWidgetMacOverlayNSWindow* overlay_window();
  BridgedContentView* overlay_content_view();

  // Called when `immersive_mode_titlebar_view_controller_`'s view is moved to
  // a different window.
  void ImmersiveModeViewWillMoveToWindow(NSWindow* window);

  // Returns true if immersive fullscreen is being used.
  virtual bool IsTabbed();
  bool IsContentFullscreen();

  ImmersiveModeTitlebarViewController*
  immersive_mode_titlebar_view_controller_for_testing() {
    return immersive_mode_titlebar_view_controller_;
  }

 protected:
  // Used by derived classes to manually set last_used_style_. Typically this is
  // used while a RevealLock is active, allowing for a style change after the
  // last RevealLock has been released.
  void set_last_used_style(std::optional<mojom::ToolbarVisibilityStyle> style) {
    last_used_style_ = style;
  }
  std::optional<mojom::ToolbarVisibilityStyle> last_used_style() {
    return last_used_style_;
  }

  // Layout the `window` on top of the `anchor_view`. The `window` will occupy
  // the same place on screen as the `anchor_view`, completely occluding the
  // `anchor_view`. The `window` is clear but needs to overlay the `anchor_view`
  // to handle drag events.
  // If the `anchor_view` is offscreen, the `window` will be moved offscreen.
  void LayoutWindowWithAnchorView(NSWindow* window, NSView* anchor_view);

  // Reanchor the overlay window with its anchor view.
  virtual void Reanchor();

 private:
  // Get offscreen y origin. Used for moving overlay windows offscreen.
  double GetOffscreenYOrigin();

  // Notify the browser window that the reveal status changes.
  void NotifyBrowserWindowAboutToolbarRevealChanged();

  // Updates the visibility of the thin controller. The thin controller will
  // only become visible when the toolbar is hidden.
  // TODO(crbug.com/40240734): Remove when fixed by Apple.
  void UpdateThinControllerVisibility();

  // Calls either RevealLocked() or RevealUnlocked() based on the current
  // reveal_lock_count_.
  void ApplyRevealLockState();

  // `UpdateToolbarVisibility(style)` will skip updating if `last_used_style_`
  // and `style` are the same. `ForceToolbarVisibilityUpdate()` forces a toolbar
  // visibility update of `last_used_style_`.
  void ForceToolbarVisibilityUpdate();

  // display::DisplayObserver:
  void OnPrimaryDisplayChanged() override;

  // See comment for `thin_titlebar_view_controller_`. These helpers abstract
  // the fact that on macOS < 13, the controller is added and removed as needed,
  // and on macOS 13+, it is permanent.
  // TODO(https://crbug.com/373722654): Clean these up when macOS 13 is minimum.
  void CreateThinControllerIfNecessary();
  void DisableThinControllerIfNecessary();

  bool initialized_ = false;

  int reveal_lock_count_ = 0;
  bool ignore_reveal_locks_ = false;

  bool is_toolbar_revealed_ = false;

  int menu_bar_height_ = 0;

  std::optional<mojom::ToolbarVisibilityStyle> last_used_style_;
  // Keeps the view controllers hidden until the fullscreen transition is
  // complete.
  bool fullscreen_transition_complete_ = false;

  BrowserNativeWidgetWindow* __weak browser_window_;
  NativeWidgetMacOverlayNSWindow* __weak overlay_window_;
  BridgedContentView* __weak overlay_content_view_;

  // A controller for top chrome.
  ImmersiveModeTitlebarViewController* __strong
      immersive_mode_titlebar_view_controller_;

  // A controller that keeps a small portion (0.5px) of the fullscreen AppKit
  // NSWindow on screen.
  // This controller is used as a workaround for an AppKit bug that displays a
  // black bar when changing a NSTitlebarAccessoryViewController's
  // fullScreenMinHeight from zero to non-zero.
  // TODO(crbug.com/40240734): Remove when fixed by Apple.
  NSTitlebarAccessoryViewController* __strong thin_titlebar_view_controller_;

  ImmersiveModeMapper* __strong immersive_mode_mapper_;

  // Keeps track of which windows have received titlebar and reveal locks.
  std::set<NSWindow*> window_lock_received_;

  base::ScopedObservation<display::Screen, display::DisplayObserver>
      display_observation_{this};

  base::WeakPtrFactory<ImmersiveModeControllerCocoa> weak_ptr_factory_;
};

}  // namespace remote_cocoa

// An empty NSView that is also opaque.
@interface OpaqueView : NSView
@end

#endif  // COMPONENTS_REMOTE_COCOA_APP_SHIM_IMMERSIVE_MODE_CONTROLLER_COCOA_H_