blob: 530b36f297686dfec52ad120e2993f3e5046648f [file] [log] [blame]
// 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_H_
#define COMPONENTS_REMOTE_COCOA_APP_SHIM_IMMERSIVE_MODE_CONTROLLER_H_
#import <AppKit/AppKit.h>
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/mac/scoped_nsobject.h"
#import "components/remote_cocoa/app_shim/bridged_content_view.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"
@class ClearTitlebarViewController;
@class ImmersiveModeMapper;
@class ImmersiveModeTitlebarObserver;
@class ImmersiveModeTitlebarViewController;
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);
class REMOTE_COCOA_APP_SHIM_EXPORT ImmersiveModeController {
public:
explicit ImmersiveModeController(NSWindow* browser_window,
NSWindow* overlay_window,
base::OnceClosure callback);
virtual ~ImmersiveModeController();
virtual void Enable();
bool is_enabled() { return enabled_; }
virtual void FullscreenTransitionCompleted();
virtual void OnTopViewBoundsChanged(const gfx::Rect& bounds);
virtual void UpdateToolbarVisibility(mojom::ToolbarVisibilityStyle style);
mojom::ToolbarVisibilityStyle last_used_style() { return last_used_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.
virtual void RevealLock();
virtual void RevealUnlock();
int reveal_lock_count() { return reveal_lock_count_; }
// Called when the NSTitlebarContainerView frame changes.
virtual void OnTitlebarFrameDidChange(NSRect frame);
// 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() { return browser_window_; }
NSWindow* overlay_window() { return overlay_window_; }
BridgedContentView* overlay_content_view() { return overlay_content_view_; }
// Caled when `immersive_mode_titlebar_view_controller_`'s view is moved to
// a different window.
void ImmersiveModeViewWillMoveToWindow(NSWindow* window);
// Returns true if kImmersiveFullscreenTabs is being used.
virtual bool IsTabbed();
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(mojom::ToolbarVisibilityStyle style) {
last_used_style_ = 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);
private:
bool enabled_ = false;
NSWindow* const browser_window_;
NSWindow* const overlay_window_;
BridgedContentView* overlay_content_view_;
// A controller for top chrome.
base::scoped_nsobject<ImmersiveModeTitlebarViewController>
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(https://crbug.com/1369643): Remove when fixed by Apple.
base::scoped_nsobject<NSTitlebarAccessoryViewController>
thin_titlebar_view_controller_;
base::scoped_nsobject<ImmersiveModeMapper> immersive_mode_mapper_;
base::scoped_nsobject<ImmersiveModeTitlebarObserver>
immersive_mode_titlebar_observer_;
int reveal_lock_count_ = 0;
mojom::ToolbarVisibilityStyle last_used_style_ =
mojom::ToolbarVisibilityStyle::kAutohide;
// Keeps the view controllers hidden until the fullscreen transition is
// complete.
bool fullscreen_transition_complete_ = false;
// Keeps track of which windows have received titlebar and reveal locks.
std::set<NSWindow*> window_lock_received_;
base::WeakPtrFactory<ImmersiveModeController> weak_ptr_factory_;
};
} // namespace remote_cocoa
// A small class that moves the overlay window along the y axis.
//
// The overlay's content view (top chrome) is not hosted in the overlay window.
// It is moved to the AppKit controlled fullscreen window via the
// NSTitlebarAccessoryViewController API. However the overlay window is still
// important.
// * It is the parent window for top chrome popups. Moving the overlay window
// in turn moves the child windows.
// * Its origin in important for dragging operations.
//
// This class will keep the position of the overlay window in sync with its
// original content (top chrome).
REMOTE_COCOA_APP_SHIM_EXPORT @interface ImmersiveModeTitlebarObserver : NSObject
- (instancetype)initWithController:
(base::WeakPtr<remote_cocoa::ImmersiveModeController>)
controller
titlebarContainerView:(NSView*)titlebarContainerView;
@end
#endif // COMPONENTS_REMOTE_COCOA_APP_SHIM_IMMERSIVE_MODE_CONTROLLER_H_