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_
|