blob: 492386c61ac6701fc38c5e90976b4e5f638189de [file] [log] [blame]
// Copyright 2018 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.
#ifndef UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NS_WINDOW_HOST_H_
#define UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NS_WINDOW_HOST_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h"
#include "components/remote_cocoa/app_shim/ns_view_ids.h"
#include "components/remote_cocoa/browser/application_host.h"
#include "components/remote_cocoa/common/native_widget_ns_window.mojom.h"
#include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/base/cocoa/accessibility_focus_overrider.h"
#include "ui/compositor/layer_owner.h"
#include "ui/display/mac/display_link_mac.h"
#include "ui/views/cocoa/drag_drop_client_mac.h"
#include "ui/views/views_export.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_observer.h"
@class NativeWidgetMacNSWindow;
@class NSAccessibilityRemoteUIElement;
@class NSView;
namespace remote_cocoa {
class NativeWidgetNSWindowBridge;
class ScopedNativeWindowMapping;
} // namespace remote_cocoa
namespace ui {
class RecyclableCompositorMac;
} // namespace ui
namespace views {
class NativeWidgetMac;
class TextInputHost;
// The portion of NativeWidgetMac that lives in the browser process. This
// communicates to the NativeWidgetNSWindowBridge, which interacts with the
// Cocoa APIs, and which may live in an app shim process.
class VIEWS_EXPORT NativeWidgetMacNSWindowHost
: public remote_cocoa::NativeWidgetNSWindowHostHelper,
public remote_cocoa::ApplicationHost::Observer,
public remote_cocoa::mojom::NativeWidgetNSWindowHost,
public DialogObserver,
public ui::AccessibilityFocusOverrider::Client,
public ui::LayerDelegate,
public ui::LayerOwner,
public ui::AcceleratedWidgetMacNSView {
public:
// Retrieves the bridge host associated with the given NativeWindow. Returns
// null if the supplied handle has no associated Widget.
static NativeWidgetMacNSWindowHost* GetFromNativeWindow(
gfx::NativeWindow window);
static NativeWidgetMacNSWindowHost* GetFromNativeView(gfx::NativeView view);
// Unique integer id handles are used to bridge between the
// NativeWidgetMacNSWindowHost in one process and the NativeWidgetNSWindowHost
// potentially in another.
static NativeWidgetMacNSWindowHost* GetFromId(
uint64_t bridged_native_widget_id);
uint64_t bridged_native_widget_id() const { return widget_id_; }
// Creates one side of the bridge. |owner| must not be NULL.
explicit NativeWidgetMacNSWindowHost(NativeWidgetMac* owner);
~NativeWidgetMacNSWindowHost() override;
// The NativeWidgetMac that owns |this|.
views::NativeWidgetMac* native_widget_mac() const {
return native_widget_mac_;
}
NativeWidgetMacNSWindowHost* parent() const { return parent_; }
std::vector<NativeWidgetMacNSWindowHost*> children() const {
return children_;
}
// The bridge factory that was used to create the true NSWindow for this
// widget. This is nullptr for in-process windows.
remote_cocoa::ApplicationHost* application_host() const {
return application_host_;
}
TextInputHost* text_input_host() const { return text_input_host_.get(); }
// A NSWindow that is guaranteed to exist in this process. If the bridge
// object for this host is in this process, then this points to the bridge's
// NSWindow. Otherwise, it mirrors the id and bounds of the child window.
NativeWidgetMacNSWindow* GetInProcessNSWindow() const;
// Return the accessibility object for the content NSView.
gfx::NativeViewAccessible GetNativeViewAccessibleForNSView() const;
// Return the accessibility object for the NSWindow.
gfx::NativeViewAccessible GetNativeViewAccessibleForNSWindow() const;
// The mojo interface through which to communicate with the underlying
// NSWindow and NSView. This points to either |remote_ns_window_remote_| or
// |in_process_ns_window_bridge_|.
remote_cocoa::mojom::NativeWidgetNSWindow* GetNSWindowMojo() const;
// Direct access to the NativeWidgetNSWindowBridge that this is hosting.
// TODO(ccameron): Remove all accesses to this member, and replace them
// with methods that may be sent across processes.
remote_cocoa::NativeWidgetNSWindowBridge* GetInProcessNSWindowBridge() const {
return in_process_ns_window_bridge_.get();
}
TooltipManager* tooltip_manager() { return tooltip_manager_.get(); }
DragDropClientMac* drag_drop_client() const {
return drag_drop_client_.get();
}
// Create and set the bridge object to be in this process.
void CreateInProcessNSWindowBridge(
base::scoped_nsobject<NativeWidgetMacNSWindow> window);
// Create and set the bridge object to be potentially in another process.
void CreateRemoteNSWindow(
remote_cocoa::ApplicationHost* application_host,
remote_cocoa::mojom::CreateWindowParamsPtr window_create_params);
void InitWindow(const Widget::InitParams& params,
const gfx::Rect& initial_bounds_in_screen);
// Close the window immediately. This function may result in |this| being
// deleted.
void CloseWindowNow();
// Changes the bounds of the window and the hosted layer if present. The
// argument is always a location in screen coordinates (in contrast to the
// views::Widget::SetBounds method, when the argument is only sometimes in
// screen coordinates).
void SetBoundsInScreen(const gfx::Rect& bounds);
// Tell the window to transition to being fullscreen or not-fullscreen.
void SetFullscreen(bool fullscreen);
// The ultimate fullscreen state that is being targeted (irrespective of any
// active transitions).
bool target_fullscreen_state() const { return target_fullscreen_state_; }
// Set the root view (set during initialization and un-set during teardown).
void SetRootView(views::View* root_view);
// Return the id through which the NSView for |root_view_| may be looked up.
uint64_t GetRootViewNSViewId() const { return root_view_id_; }
// Initialize the ui::Compositor and ui::Layer.
void CreateCompositor(const Widget::InitParams& params);
// Set the window's title, returning true if the title has changed.
bool SetWindowTitle(const base::string16& title);
// Called when the owning Widget's Init method has completed.
void OnWidgetInitDone();
// Redispatch a keyboard event using the widget's window's CommandDispatcher.
// Return true if the event is handled.
bool RedispatchKeyEvent(NSEvent* event);
// Geometry of the window, in DIPs.
const gfx::Rect& GetWindowBoundsInScreen() const {
return window_bounds_in_screen_;
}
// Geometry of the content area of the window, in DIPs. Note that this is not
// necessarily the same as the views::View's size.
const gfx::Rect& GetContentBoundsInScreen() const {
return content_bounds_in_screen_;
}
// The display that the window is currently on (or best guess thereof).
const display::Display& GetCurrentDisplay() const { return display_; }
// The restored bounds will be derived from the current NSWindow frame unless
// fullscreen or transitioning between fullscreen states.
gfx::Rect GetRestoredBounds() const;
// An opaque blob of AppKit data which includes, among other things, a
// window's workspace and fullscreen state, and can be retrieved from or
// applied to a window.
const std::vector<uint8_t>& GetWindowStateRestorationData() const;
// Set |parent_| and update the old and new parents' |children_|. It is valid
// to set |new_parent| to nullptr. Propagate this to the BridgedNativeWidget.
void SetParent(NativeWidgetMacNSWindowHost* new_parent);
// Properties set and queried by views. Not actually native.
void SetNativeWindowProperty(const char* name, void* value);
void* GetNativeWindowProperty(const char* name) const;
// Updates |attached_native_view_host_views_| on
// NativeViewHost::Attach()/Detach().
void OnNativeViewHostAttach(const views::View* view, NSView* native_view);
void OnNativeViewHostDetach(const views::View* view);
// Sorts child NSViews according to NativeViewHosts order in views hierarchy.
void ReorderChildViews();
bool IsVisible() const { return is_visible_; }
bool IsMiniaturized() const { return is_miniaturized_; }
bool IsWindowKey() const { return is_window_key_; }
bool IsMouseCaptureActive() const { return is_mouse_capture_active_; }
// Used by NativeWidgetPrivate::GetGlobalCapture.
static NSView* GetGlobalCaptureView();
private:
friend class TextInputHost;
void UpdateCompositorProperties();
void DestroyCompositor();
// Sort |attached_native_view_host_views_| by the order in which their
// NSViews should appear as subviews. This does a recursive pre-order
// traversal of the views::View tree starting at |view|.
void GetAttachedNativeViewHostViewsRecursive(
View* view,
std::vector<NSView*>* attached_native_view_host_views_ordered) const;
// If we are accessing the BridgedNativeWidget through mojo, then
// |in_process_ns_window_| is not the true window that is resized. This
// function updates the frame of |in_process_ns_window_| to keep it in sync
// for any native calls that may use it (e.g, for context menu positioning).
void UpdateLocalWindowFrame(const gfx::Rect& frame);
// NativeWidgetNSWindowHostHelper:
id GetNativeViewAccessible() override;
void DispatchKeyEvent(ui::KeyEvent* event) override;
bool DispatchKeyEventToMenuController(ui::KeyEvent* event) override;
void GetWordAt(const gfx::Point& location_in_content,
bool* found_word,
gfx::DecoratedText* decorated_word,
gfx::Point* baseline_point) override;
remote_cocoa::DragDropClient* GetDragDropClient() override;
ui::TextInputClient* GetTextInputClient() override;
// remote_cocoa::ApplicationHost::Observer:
void OnApplicationHostDestroying(
remote_cocoa::ApplicationHost* host) override;
// remote_cocoa::mojom::NativeWidgetNSWindowHost:
void OnVisibilityChanged(bool visible) override;
void OnWindowNativeThemeChanged() override;
void OnViewSizeChanged(const gfx::Size& new_size) override;
bool GetSheetOffsetY(int32_t* offset_y) override;
void SetKeyboardAccessible(bool enabled) override;
void OnIsFirstResponderChanged(bool is_first_responder) override;
void OnMouseCaptureActiveChanged(bool capture_is_active) override;
void OnScrollEvent(std::unique_ptr<ui::Event> event) override;
void OnMouseEvent(std::unique_ptr<ui::Event> event) override;
void OnGestureEvent(std::unique_ptr<ui::Event> event) override;
bool DispatchKeyEventRemote(std::unique_ptr<ui::Event> event,
bool* event_handled) override;
bool DispatchKeyEventToMenuControllerRemote(std::unique_ptr<ui::Event> event,
bool* event_swallowed,
bool* event_handled) override;
bool GetHasMenuController(bool* has_menu_controller) override;
bool GetIsDraggableBackgroundAt(const gfx::Point& location_in_content,
bool* is_draggable_background) override;
bool GetTooltipTextAt(const gfx::Point& location_in_content,
base::string16* new_tooltip_text) override;
bool GetWidgetIsModal(bool* widget_is_modal) override;
bool GetIsFocusedViewTextual(bool* is_textual) override;
void OnWindowGeometryChanged(
const gfx::Rect& window_bounds_in_screen_dips,
const gfx::Rect& content_bounds_in_screen_dips) override;
void OnWindowFullscreenTransitionStart(bool target_fullscreen_state) override;
void OnWindowFullscreenTransitionComplete(
bool target_fullscreen_state) override;
void OnWindowMiniaturizedChanged(bool miniaturized) override;
void OnWindowDisplayChanged(const display::Display& display) override;
void OnWindowWillClose() override;
void OnWindowHasClosed() override;
void OnWindowKeyStatusChanged(bool is_key,
bool is_content_first_responder,
bool full_keyboard_access_enabled) override;
void OnWindowStateRestorationDataChanged(
const std::vector<uint8_t>& data) override;
void DoDialogButtonAction(ui::DialogButton button) override;
bool GetDialogButtonInfo(ui::DialogButton type,
bool* button_exists,
base::string16* button_label,
bool* is_button_enabled,
bool* is_button_default) override;
bool GetDoDialogButtonsExist(bool* buttons_exist) override;
bool GetShouldShowWindowTitle(bool* should_show_window_title) override;
bool GetCanWindowBecomeKey(bool* can_window_become_key) override;
bool GetAlwaysRenderWindowAsKey(bool* always_render_as_key) override;
bool OnWindowCloseRequested(bool* can_window_close) override;
bool GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
float* titlebar_height) override;
void OnFocusWindowToolbar() override;
void SetRemoteAccessibilityTokens(
const std::vector<uint8_t>& window_token,
const std::vector<uint8_t>& view_token) override;
bool GetRootViewAccessibilityToken(int64_t* pid,
std::vector<uint8_t>* token) override;
bool ValidateUserInterfaceItem(
int32_t command,
remote_cocoa::mojom::ValidateUserInterfaceItemResultPtr* out_result)
override;
bool ExecuteCommand(int32_t command,
WindowOpenDisposition window_open_disposition,
bool is_before_first_responder,
bool* was_executed) override;
bool HandleAccelerator(const ui::Accelerator& accelerator,
bool require_priority_handler,
bool* was_handled) override;
// remote_cocoa::mojom::NativeWidgetNSWindowHost, synchronous callbacks:
void GetSheetOffsetY(GetSheetOffsetYCallback callback) override;
void DispatchKeyEventRemote(std::unique_ptr<ui::Event> event,
DispatchKeyEventRemoteCallback callback) override;
void DispatchKeyEventToMenuControllerRemote(
std::unique_ptr<ui::Event> event,
DispatchKeyEventToMenuControllerRemoteCallback callback) override;
void GetHasMenuController(GetHasMenuControllerCallback callback) override;
void GetIsDraggableBackgroundAt(
const gfx::Point& location_in_content,
GetIsDraggableBackgroundAtCallback callback) override;
void GetTooltipTextAt(const gfx::Point& location_in_content,
GetTooltipTextAtCallback callback) override;
void GetWidgetIsModal(GetWidgetIsModalCallback callback) override;
void GetIsFocusedViewTextual(
GetIsFocusedViewTextualCallback callback) override;
void GetDialogButtonInfo(ui::DialogButton button,
GetDialogButtonInfoCallback callback) override;
void GetDoDialogButtonsExist(
GetDoDialogButtonsExistCallback callback) override;
void GetShouldShowWindowTitle(
GetShouldShowWindowTitleCallback callback) override;
void GetCanWindowBecomeKey(GetCanWindowBecomeKeyCallback callback) override;
void GetAlwaysRenderWindowAsKey(
GetAlwaysRenderWindowAsKeyCallback callback) override;
void OnWindowCloseRequested(OnWindowCloseRequestedCallback callback) override;
void GetWindowFrameTitlebarHeight(
GetWindowFrameTitlebarHeightCallback callback) override;
void GetRootViewAccessibilityToken(
GetRootViewAccessibilityTokenCallback callback) override;
void ValidateUserInterfaceItem(
int32_t command,
ValidateUserInterfaceItemCallback callback) override;
void ExecuteCommand(int32_t command,
WindowOpenDisposition window_open_disposition,
bool is_before_first_responder,
ExecuteCommandCallback callback) override;
void HandleAccelerator(const ui::Accelerator& accelerator,
bool require_priority_handler,
HandleAcceleratorCallback callback) override;
// DialogObserver:
void OnDialogChanged() override;
// ui::AccessibilityFocusOverrider::Client:
id GetAccessibilityFocusedUIElement() override;
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override;
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override;
void UpdateVisualState() override;
// ui::AcceleratedWidgetMacNSView:
void AcceleratedWidgetCALayerParamsUpdated() override;
// The id that this bridge may be looked up from.
const uint64_t widget_id_;
views::NativeWidgetMac* const native_widget_mac_; // Weak. Owns |this_|.
// Structure used to look up this structure's interfaces from its
// gfx::NativeWindow.
std::unique_ptr<remote_cocoa::ScopedNativeWindowMapping>
native_window_mapping_;
// Parent and child widgets.
NativeWidgetMacNSWindowHost* parent_ = nullptr;
std::vector<NativeWidgetMacNSWindowHost*> children_;
// The factory that was used to create |remote_ns_window_remote_|. This must
// be the same as |parent_->application_host_|.
remote_cocoa::ApplicationHost* application_host_ = nullptr;
Widget::InitParams::Type widget_type_ = Widget::InitParams::TYPE_WINDOW;
// The id that may be used to look up the NSView for |root_view_|.
const uint64_t root_view_id_;
// Weak. Owned by |native_widget_mac_|.
views::View* root_view_ = nullptr;
std::unique_ptr<DragDropClientMac> drag_drop_client_;
// The mojo remote for a BridgedNativeWidget, which may exist in another
// process.
mojo::AssociatedRemote<remote_cocoa::mojom::NativeWidgetNSWindow>
remote_ns_window_remote_;
// Remote accessibility objects corresponding to the NSWindow and its root
// NSView.
base::scoped_nsobject<NSAccessibilityRemoteUIElement>
remote_window_accessible_;
base::scoped_nsobject<NSAccessibilityRemoteUIElement> remote_view_accessible_;
// Used to force the NSApplication's focused accessibility element to be the
// views::Views accessibility tree when the NSView for this is focused.
ui::AccessibilityFocusOverrider accessibility_focus_overrider_;
// TODO(ccameron): Rather than instantiate a NativeWidgetNSWindowBridge here,
// we will instantiate a mojo NativeWidgetNSWindowBridge interface to a Cocoa
// instance that may be in another process.
std::unique_ptr<remote_cocoa::NativeWidgetNSWindowBridge>
in_process_ns_window_bridge_;
// Window that is guaranteed to exist in this process (see
// GetInProcessNSWindow).
base::scoped_nsobject<NativeWidgetMacNSWindow> in_process_ns_window_;
// Id mapping for |in_process_ns_window_|'s content NSView.
std::unique_ptr<remote_cocoa::ScopedNSViewIdMapping>
in_process_view_id_mapping_;
std::unique_ptr<TooltipManager> tooltip_manager_;
std::unique_ptr<TextInputHost> text_input_host_;
base::string16 window_title_;
// The display that the window is currently on.
display::Display display_;
// Display link for getting vsync info for |display_|.
scoped_refptr<ui::DisplayLinkMac> display_link_;
// The geometry of the window and its contents view, in screen coordinates.
gfx::Rect window_bounds_in_screen_;
gfx::Rect content_bounds_in_screen_;
std::vector<uint8_t> state_restoration_data_;
bool is_visible_ = false;
bool target_fullscreen_state_ = false;
bool in_fullscreen_transition_ = false;
bool is_miniaturized_ = false;
bool is_window_key_ = false;
bool is_mouse_capture_active_ = false;
gfx::Rect window_bounds_before_fullscreen_;
std::unique_ptr<ui::RecyclableCompositorMac> compositor_;
// Properties used by Set/GetNativeWindowProperty.
std::map<std::string, void*> native_window_properties_;
// Contains NativeViewHost->gfx::NativeView associations for NativeViewHosts
// attached to |this|.
std::map<const views::View*, NSView*> attached_native_view_host_views_;
mojo::AssociatedReceiver<remote_cocoa::mojom::NativeWidgetNSWindowHost>
remote_ns_window_host_receiver_{this};
DISALLOW_COPY_AND_ASSIGN(NativeWidgetMacNSWindowHost);
};
} // namespace views
#endif // UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NS_WINDOW_HOST_H_