// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_
#define UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_
#include <memory>
#include <string>
#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "ui/base/ime/ime_key_event_dispatcher.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/base/window_open_disposition.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget_observer.h"
#if defined(__OBJC__)
@class NativeWidgetMacNSWindow;
#else
class NativeWidgetMacNSWindow;
#endif
namespace remote_cocoa {
namespace mojom {
class CreateWindowParams;
class NativeWidgetNSWindow;
class ValidateUserInterfaceItemResult;
} // namespace mojom
class ApplicationHost;
class NativeWidgetNSWindowBridge;
} // namespace remote_cocoa
namespace views {
namespace test {
class MockNativeWidgetMac;
class NativeWidgetMacTest;
} // namespace test
class NativeWidgetMacNSWindowHost;
class Widget;
class VIEWS_EXPORT NativeWidgetMac : public internal::NativeWidgetPrivate,
public FocusChangeListener,
public ui::ImeKeyEventDispatcher,
public WidgetObserver {
public:
explicit NativeWidgetMac(internal::NativeWidgetDelegate* delegate);
NativeWidgetMac(const NativeWidgetMac&) = delete;
NativeWidgetMac& operator=(const NativeWidgetMac&) = delete;
~NativeWidgetMac() override;
// Informs |delegate_| that the native widget is about to be destroyed.
// NativeWidgetNSWindowBridge::OnWindowWillClose() invokes this early when the
// NSWindowDelegate informs the bridge that the window is being closed (later,
// invoking OnWindowDestroyed()).
void WindowDestroying();
// Deletes |bridge_| and informs |delegate_| that the native widget is
// destroyed.
void WindowDestroyed();
// Called when the backing NSWindow gains or loses key status.
void OnWindowKeyStatusChanged(bool is_key, bool is_content_first_responder);
// The vertical position from which sheets should be anchored, from the top
// of the content view.
virtual int32_t SheetOffsetY();
// Returns in |override_titlebar_height| whether or not to override the
// titlebar height and in |titlebar_height| the height of the titlebar.
virtual void GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
float* titlebar_height);
// Called when the window begins transitioning to or from being fullscreen.
virtual void OnWindowFullscreenTransitionStart() {}
// Called when the window has completed its transition to or from being
// fullscreen. Note that if there are multiple consecutive transitions
// (because a new transition was initiated before the previous one completed)
// then this will only be called when all transitions have competed.
virtual void OnWindowFullscreenTransitionComplete() {}
// Handle "Move focus to the window toolbar" shortcut.
virtual void OnFocusWindowToolbar() {}
// Allows subclasses to override the behavior for
// -[NSUserInterfaceValidations validateUserInterfaceItem].
virtual void ValidateUserInterfaceItem(
int32_t command,
remote_cocoa::mojom::ValidateUserInterfaceItemResult* result) {}
// Returns in |will_execute| whether or not ExecuteCommand() will execute
// the chrome command |command| with |window_open_disposition| and
// |is_before_first_responder|.
virtual bool WillExecuteCommand(int32_t command,
WindowOpenDisposition window_open_disposition,
bool is_before_first_responder);
// Execute the chrome command |command| with |window_open_disposition|. If
// |is_before_first_responder| then only call ExecuteCommand if the command
// is reserved and extension shortcut handling is not suspended. Returns in
// |was_executed| whether or not ExecuteCommand was called (regardless of what
// the return value for ExecuteCommand was).
virtual bool ExecuteCommand(int32_t command,
WindowOpenDisposition window_open_disposition,
bool is_before_first_responder);
ui::Compositor* GetCompositor() {
return const_cast<ui::Compositor*>(
const_cast<const NativeWidgetMac*>(this)->GetCompositor());
}
// internal::NativeWidgetPrivate:
void InitNativeWidget(Widget::InitParams params) override;
void OnWidgetInitDone() override;
void ReparentNativeViewImpl(gfx::NativeView new_parent) override;
std::unique_ptr<NonClientFrameView> CreateNonClientFrameView() override;
bool ShouldUseNativeFrame() const override;
bool ShouldWindowContentsBeTransparent() const override;
void FrameTypeChanged() override;
Widget* GetWidget() override;
const Widget* GetWidget() const override;
gfx::NativeView GetNativeView() const override;
gfx::NativeWindow GetNativeWindow() const override;
Widget* GetTopLevelWidget() override;
const ui::Compositor* GetCompositor() const override;
const ui::Layer* GetLayer() const override;
void ReorderNativeViews() override;
void ViewRemoved(View* view) override;
void SetNativeWindowProperty(const char* name, void* value) override;
void* GetNativeWindowProperty(const char* name) const override;
TooltipManager* GetTooltipManager() const override;
void SetCapture() override;
void ReleaseCapture() override;
bool HasCapture() const override;
ui::InputMethod* GetInputMethod() override;
void CenterWindow(const gfx::Size& size) override;
void GetWindowPlacement(gfx::Rect* bounds,
ui::WindowShowState* show_state) const override;
bool SetWindowTitle(const std::u16string& title) override;
void SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) override;
const gfx::ImageSkia* GetWindowIcon() override;
const gfx::ImageSkia* GetWindowAppIcon() override;
void InitModalType(ui::mojom::ModalType modal_type) override;
gfx::Rect GetWindowBoundsInScreen() const override;
gfx::Rect GetClientAreaBoundsInScreen() const override;
gfx::Rect GetRestoredBounds() const override;
std::string GetWorkspace() const override;
void SetBounds(const gfx::Rect& bounds) override;
void SetBoundsConstrained(const gfx::Rect& bounds) override;
void SetSize(const gfx::Size& size) override;
void StackAbove(gfx::NativeView native_view) override;
void StackAtTop() override;
bool IsStackedAbove(gfx::NativeView native_view) override;
void SetShape(std::unique_ptr<Widget::ShapeRects> shape) override;
void Close() override;
void CloseNow() override;
void Show(ui::WindowShowState show_state,
const gfx::Rect& restore_bounds) override;
void Hide() override;
bool IsVisible() const override;
void Activate() override;
void Deactivate() override;
bool IsActive() const override;
void SetZOrderLevel(ui::ZOrderLevel order) override;
ui::ZOrderLevel GetZOrderLevel() const override;
void SetVisibleOnAllWorkspaces(bool always_visible) override;
bool IsVisibleOnAllWorkspaces() const override;
void Maximize() override;
void Minimize() override;
bool IsMaximized() const override;
bool IsMinimized() const override;
void Restore() override;
void SetFullscreen(bool fullscreen, int64_t target_display_id) override;
bool IsFullscreen() const override;
void SetCanAppearInExistingFullscreenSpaces(
bool can_appear_in_existing_fullscreen_spaces) override;
void SetOpacity(float opacity) override;
void SetAspectRatio(const gfx::SizeF& aspect_ratio,
const gfx::Size& excluded_margin) override;
void FlashFrame(bool flash_frame) override;
void RunShellDrag(std::unique_ptr<ui::OSExchangeData> data,
const gfx::Point& location,
int operation,
ui::mojom::DragEventSource source) override;
void CancelShellDrag(View* view) override;
void SchedulePaintInRect(const gfx::Rect& rect) override;
void ScheduleLayout() override;
void SetCursor(const ui::Cursor& cursor) override;
void ShowEmojiPanel() override;
bool IsMouseEventsEnabled() const override;
bool IsMouseButtonDown() const override;
void ClearNativeFocus() override;
gfx::Rect GetWorkAreaBoundsInScreen() const override;
Widget::MoveLoopResult RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) override;
void EndMoveLoop() override;
void SetVisibilityChangedAnimationsEnabled(bool value) override;
void SetVisibilityAnimationDuration(const base::TimeDelta& duration) override;
void SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) override;
ui::GestureRecognizer* GetGestureRecognizer() override;
ui::GestureConsumer* GetGestureConsumer() override;
void OnSizeConstraintsChanged() override;
void OnNativeViewHierarchyWillChange() override;
void OnNativeViewHierarchyChanged() override;
bool SetAllowScreenshots(bool allow) override;
bool AreScreenshotsAllowed() override;
std::string GetName() const override;
base::WeakPtr<internal::NativeWidgetPrivate> GetWeakPtr() override;
// Calls |callback| with the newly created NativeWidget whenever a
// NativeWidget is created.
static base::CallbackListSubscription RegisterInitNativeWidgetCallback(
const base::RepeatingCallback<void(NativeWidgetMac*)>& callback);
protected:
// The argument to SetBounds is sometimes in screen coordinates and sometimes
// in parent window coordinates. This function will take that bounds argument
// and convert it to screen coordinates if needed.
gfx::Rect ConvertBoundsToScreenIfNeeded(const gfx::Rect& bounds) const;
virtual void PopulateCreateWindowParams(
const Widget::InitParams& widget_params,
remote_cocoa::mojom::CreateWindowParams* params);
// Creates the NSWindow that will be passed to the NativeWidgetNSWindowBridge.
// Called by InitNativeWidget.
virtual NativeWidgetMacNSWindow* CreateNSWindow(
const remote_cocoa::mojom::CreateWindowParams* params);
// Return the BridgeFactoryHost that is to be used for creating this window
// and all of its child windows. This will return nullptr if the native
// windows are to be created in the current process.
virtual remote_cocoa::ApplicationHost* GetRemoteCocoaApplicationHost();
// Called after the window has been initialized. Allows subclasses to perform
// additional initialization.
virtual void OnWindowInitialized() {}
// Optional hook for subclasses invoked by WindowDestroying().
virtual void OnWindowDestroying(gfx::NativeWindow window) {}
internal::NativeWidgetDelegate* delegate_for_testing() {
return delegate_.get();
}
// Return the mojo interface for the NSWindow. The interface may be
// implemented in-process or out-of-process.
remote_cocoa::mojom::NativeWidgetNSWindow* GetNSWindowMojo() const;
// Return the bridge structure only if this widget is in-process.
remote_cocoa::NativeWidgetNSWindowBridge* GetInProcessNSWindowBridge() const;
NativeWidgetMacNSWindowHost* GetNSWindowHost() const {
return ns_window_host_.get();
}
// Unregister focus listeners from previous focus manager, and register them
// with the |new_focus_manager|. Updates |focus_manager_|.
void SetFocusManager(FocusManager* new_focus_manager);
// FocusChangeListener:
void OnWillChangeFocus(View* focused_before, View* focused_now) override;
void OnDidChangeFocus(View* focused_before, View* focused_now) override;
// ui::ImeKeyEventDispatcher:
ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override;
// WidgetObserver:
void OnWidgetDestroyed(Widget* widget) override;
private:
friend class test::MockNativeWidgetMac;
friend class views::test::NativeWidgetMacTest;
class ZoomFocusMonitor;
// Applies to all `Widget::InitParams::Ownership` types.
const base::WeakPtr<internal::NativeWidgetDelegate> delegate_;
// Only applies to `Widget::InitParams::Ownership::NATIVE_WIDGET_OWNS_WIDGET`.
std::unique_ptr<internal::NativeWidgetDelegate> owned_delegate_;
std::unique_ptr<NativeWidgetMacNSWindowHost> ns_window_host_;
Widget::InitParams::Ownership ownership_ =
Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
// Internal name.
std::string name_;
ui::ZOrderLevel z_order_level_ = ui::ZOrderLevel::kNormal;
Widget::InitParams::Type type_;
// Weak pointer to the FocusManager with with |zoom_focus_monitor_| and
// |ns_window_host_| are registered.
raw_ptr<FocusManager> focus_manager_ = nullptr;
std::unique_ptr<ui::InputMethod> input_method_;
std::unique_ptr<ZoomFocusMonitor> zoom_focus_monitor_;
// Held while this widget is active if it's a child.
std::unique_ptr<Widget::PaintAsActiveLock> parent_key_lock_;
base::ScopedObservation<Widget, WidgetObserver> widget_observation_{this};
// The following factory is used to provide references to the NativeWidgetMac
// instance.
base::WeakPtrFactory<NativeWidgetMac> weak_factory{this};
};
} // namespace views
#endif // UI_VIEWS_WIDGET_NATIVE_WIDGET_MAC_H_