blob: c16a4095bb72e66c5930409cb6869e408a3223bf [file] [log] [blame]
// Copyright (c) 2012 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.
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "services/ws/public/mojom/window_tree_constants.mojom.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_occlusion_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/class_property.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/views/corewm/tooltip.h"
#include "ui/views/corewm/tooltip_controller.h"
#include "ui/views/drag_utils.h"
#include "ui/views/view_constants_aura.h"
#include "ui/views/views_delegate.h"
#include "ui/views/widget/desktop_aura/desktop_capture_client.h"
#include "ui/views/widget/desktop_aura/desktop_event_client.h"
#include "ui/views/widget/desktop_aura/desktop_focus_rules.h"
#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h"
#include "ui/views/widget/drop_helper.h"
#include "ui/views/widget/focus_manager_event_handler.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/tooltip_manager_aura.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/window_reorderer.h"
#include "ui/wm/core/compound_event_filter.h"
#include "ui/wm/core/cursor_manager.h"
#include "ui/wm/core/focus_controller.h"
#include "ui/wm/core/native_cursor_manager.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_controller_delegate.h"
#include "ui/wm/core/shadow_types.h"
#include "ui/wm/core/visibility_controller.h"
#include "ui/wm/core/window_animations.h"
#include "ui/wm/core/window_modality_controller.h"
#include "ui/wm/public/activation_client.h"
#if defined(OS_WIN)
#include "ui/base/win/shell.h"
#endif
DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(VIEWS_EXPORT,
views::DesktopNativeWidgetAura*)
namespace views {
DEFINE_UI_CLASS_PROPERTY_KEY(DesktopNativeWidgetAura*,
kDesktopNativeWidgetAuraKey,
NULL)
namespace {
// This class provides functionality to create a top level widget to host a
// child window.
class DesktopNativeWidgetTopLevelHandler : public aura::WindowObserver {
public:
// This function creates a widget with the bounds passed in which eventually
// becomes the parent of the child window passed in.
static aura::Window* CreateParentWindow(aura::Window* child_window,
const gfx::Rect& bounds,
bool full_screen,
bool is_menu,
bool root_is_always_on_top) {
// This instance will get deleted when the widget is destroyed.
DesktopNativeWidgetTopLevelHandler* top_level_handler =
new DesktopNativeWidgetTopLevelHandler;
child_window->SetBounds(gfx::Rect(bounds.size()));
Widget::InitParams init_params;
init_params.type = full_screen ? Widget::InitParams::TYPE_WINDOW
: is_menu ? Widget::InitParams::TYPE_MENU
: Widget::InitParams::TYPE_POPUP;
init_params.bounds = bounds;
init_params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
init_params.layer_type = ui::LAYER_NOT_DRAWN;
init_params.activatable = full_screen ?
Widget::InitParams::ACTIVATABLE_YES :
Widget::InitParams::ACTIVATABLE_NO;
init_params.keep_on_top = root_is_always_on_top;
// This widget instance will get deleted when the window is
// destroyed.
top_level_handler->top_level_widget_ = new Widget();
// Ensure that we always use the DesktopNativeWidgetAura instance as the
// native widget here. If we enter this code path in tests then it is
// possible that we may end up with a NativeWidgetAura instance as the
// native widget which breaks this code path.
init_params.native_widget =
new DesktopNativeWidgetAura(top_level_handler->top_level_widget_);
top_level_handler->top_level_widget_->Init(init_params);
top_level_handler->top_level_widget_->SetFullscreen(full_screen);
top_level_handler->top_level_widget_->Show();
aura::Window* native_window =
top_level_handler->top_level_widget_->GetNativeView();
child_window->AddObserver(top_level_handler);
native_window->AddObserver(top_level_handler);
top_level_handler->child_window_ = child_window;
return native_window;
}
// aura::WindowObserver overrides
void OnWindowDestroying(aura::Window* window) override {
window->RemoveObserver(this);
// If the widget is being destroyed by the OS then we should not try and
// destroy it again.
if (top_level_widget_ &&
window == top_level_widget_->GetNativeView()) {
top_level_widget_ = nullptr;
return;
}
if (top_level_widget_) {
DCHECK(top_level_widget_->GetNativeView());
top_level_widget_->GetNativeView()->RemoveObserver(this);
// When we receive a notification that the child of the window created
// above is being destroyed we go ahead and initiate the destruction of
// the corresponding widget.
top_level_widget_->Close();
top_level_widget_ = nullptr;
}
delete this;
}
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override {
// The position of the window may have changed. Hence we use SetBounds in
// place of SetSize. We need to pass the bounds in screen coordinates to
// the Widget::SetBounds function.
if (top_level_widget_ && window == child_window_)
top_level_widget_->SetBounds(window->GetBoundsInScreen());
}
private:
DesktopNativeWidgetTopLevelHandler()
: top_level_widget_(nullptr), child_window_(nullptr) {}
~DesktopNativeWidgetTopLevelHandler() override = default;
Widget* top_level_widget_;
aura::Window* child_window_;
DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetTopLevelHandler);
};
class DesktopNativeWidgetAuraWindowParentingClient
: public aura::client::WindowParentingClient {
public:
explicit DesktopNativeWidgetAuraWindowParentingClient(
aura::Window* root_window)
: root_window_(root_window) {
aura::client::SetWindowParentingClient(root_window_, this);
}
~DesktopNativeWidgetAuraWindowParentingClient() override {
aura::client::SetWindowParentingClient(root_window_, nullptr);
}
// Overridden from client::WindowParentingClient:
aura::Window* GetDefaultParent(aura::Window* window,
const gfx::Rect& bounds) override {
bool is_fullscreen = window->GetProperty(aura::client::kShowStateKey) ==
ui::SHOW_STATE_FULLSCREEN;
bool is_menu = window->type() == aura::client::WINDOW_TYPE_MENU;
if (is_fullscreen || is_menu) {
bool root_is_always_on_top = false;
internal::NativeWidgetPrivate* native_widget =
DesktopNativeWidgetAura::ForWindow(root_window_);
if (native_widget)
root_is_always_on_top = native_widget->IsAlwaysOnTop();
return DesktopNativeWidgetTopLevelHandler::CreateParentWindow(
window, bounds, is_fullscreen, is_menu, root_is_always_on_top);
}
return root_window_;
}
private:
aura::Window* root_window_;
DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAuraWindowParentingClient);
};
} // namespace
class RootWindowDestructionObserver : public aura::WindowObserver {
public:
explicit RootWindowDestructionObserver(DesktopNativeWidgetAura* parent)
: parent_(parent) {}
~RootWindowDestructionObserver() override = default;
private:
// Overridden from aura::WindowObserver:
void OnWindowDestroyed(aura::Window* window) override {
parent_->RootWindowDestroyed();
window->RemoveObserver(this);
delete this;
}
DesktopNativeWidgetAura* parent_;
DISALLOW_COPY_AND_ASSIGN(RootWindowDestructionObserver);
};
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, public:
int DesktopNativeWidgetAura::cursor_reference_count_ = 0;
DesktopNativeCursorManager* DesktopNativeWidgetAura::native_cursor_manager_ =
nullptr;
wm::CursorManager* DesktopNativeWidgetAura::cursor_manager_ = nullptr;
DesktopNativeWidgetAura::DesktopNativeWidgetAura(
internal::NativeWidgetDelegate* delegate)
: desktop_window_tree_host_(nullptr),
ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
content_window_(new aura::Window(this)),
native_widget_delegate_(delegate),
last_drop_operation_(ui::DragDropTypes::DRAG_NONE),
restore_focus_on_activate_(false),
cursor_(gfx::kNullCursor),
widget_type_(Widget::InitParams::TYPE_WINDOW),
close_widget_factory_(this) {
aura::client::SetFocusChangeObserver(content_window_, this);
wm::SetActivationChangeObserver(content_window_, this);
}
DesktopNativeWidgetAura::~DesktopNativeWidgetAura() {
if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
delete native_widget_delegate_;
else
CloseNow();
}
// static
DesktopNativeWidgetAura* DesktopNativeWidgetAura::ForWindow(
aura::Window* window) {
return window->GetProperty(kDesktopNativeWidgetAuraKey);
}
void DesktopNativeWidgetAura::SetDesktopWindowTreeHost(
std::unique_ptr<DesktopWindowTreeHost> desktop_window_tree_host) {
DCHECK(!desktop_window_tree_host_);
desktop_window_tree_host_ = desktop_window_tree_host.get();
host_.reset(desktop_window_tree_host.release()->AsWindowTreeHost());
}
void DesktopNativeWidgetAura::OnHostClosed() {
// Don't invoke Widget::OnNativeWidgetDestroying(), its done by
// DesktopWindowTreeHost.
// The WindowModalityController is at the front of the event pretarget
// handler list. We destroy it first to preserve order symantics.
if (window_modality_controller_)
window_modality_controller_.reset();
// Make sure we don't have capture. Otherwise CaptureController and
// WindowEventDispatcher are left referencing a deleted Window.
{
aura::Window* capture_window = capture_client_->GetCaptureWindow();
if (capture_window && host_->window()->Contains(capture_window))
capture_window->ReleaseCapture();
}
// DesktopWindowTreeHost owns the ActivationController which ShadowController
// references. Make sure we destroy ShadowController early on.
shadow_controller_.reset();
tooltip_manager_.reset();
if (tooltip_controller_.get()) {
host_->window()->RemovePreTargetHandler(tooltip_controller_.get());
wm::SetTooltipClient(host_->window(), nullptr);
tooltip_controller_.reset();
}
window_parenting_client_.reset(); // Uses host_->dispatcher() at destruction.
capture_client_.reset(); // Uses host_->dispatcher() at destruction.
focus_manager_event_handler_.reset();
// FocusController uses |content_window_|. Destroy it now so that we don't
// have to worry about the possibility of FocusController attempting to use
// |content_window_| after it's been destroyed but before all child windows
// have been destroyed.
host_->window()->RemovePreTargetHandler(focus_client_.get());
aura::client::SetFocusClient(host_->window(), nullptr);
wm::SetActivationClient(host_->window(), nullptr);
focus_client_.reset();
host_->window()->RemovePreTargetHandler(root_window_event_filter_.get());
host_->RemoveObserver(this);
host_.reset();
// WindowEventDispatcher owns |desktop_window_tree_host_|.
desktop_window_tree_host_ = nullptr;
content_window_ = nullptr;
// |OnNativeWidgetDestroyed| may delete |this| if the object does not own
// itself.
bool should_delete_this =
(ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET);
native_widget_delegate_->OnNativeWidgetDestroyed();
if (should_delete_this)
delete this;
}
void DesktopNativeWidgetAura::OnDesktopWindowTreeHostDestroyed(
aura::WindowTreeHost* host) {
if (use_desktop_native_cursor_manager_) {
// We explicitly do NOT clear the cursor client property. Since the cursor
// manager is a singleton, it can outlive any window hierarchy, and it's
// important that objects attached to this destroying window hierarchy have
// an opportunity to deregister their observers from the cursor manager.
// They may want to do this when they are notified that they're being
// removed from the window hierarchy, which happens soon after this
// function when DesktopWindowTreeHost* calls DestroyDispatcher().
native_cursor_manager_->RemoveHost(host);
}
aura::client::SetScreenPositionClient(host->window(), nullptr);
position_client_.reset();
aura::client::SetDragDropClient(host->window(), nullptr);
drag_drop_client_.reset();
aura::client::SetEventClient(host->window(), nullptr);
event_client_.reset();
}
void DesktopNativeWidgetAura::NotifyAccessibilityEvent(
ax::mojom::Event event_type) {
if (!GetWidget() || !GetWidget()->GetRootView())
return;
GetWidget()->GetRootView()->NotifyAccessibilityEvent(event_type, true);
}
void DesktopNativeWidgetAura::HandleActivationChanged(bool active) {
if (!native_widget_delegate_->OnNativeWidgetActivationChanged(active))
return;
wm::ActivationClient* activation_client =
wm::GetActivationClient(host_->window());
if (!activation_client)
return;
if (active) {
// TODO(nektar): We need to harmonize the firing of accessibility
// events between platforms.
// https://crbug.com/897177
NotifyAccessibilityEvent(ax::mojom::Event::kWindowActivated);
if (GetWidget()->HasFocusManager()) {
// This function can be called before the focus manager has had a
// chance to set the focused view. In which case we should get the
// last focused view.
views::FocusManager* focus_manager = GetWidget()->GetFocusManager();
View* view_for_activation = focus_manager->GetFocusedView()
? focus_manager->GetFocusedView()
: focus_manager->GetStoredFocusView();
if (!view_for_activation || !view_for_activation->GetWidget()) {
view_for_activation = GetWidget()->GetRootView();
} else if (view_for_activation == focus_manager->GetStoredFocusView()) {
// When desktop native widget has modal transient child, we don't
// restore focused view here, as the modal transient child window will
// get activated and focused. Thus, we are not left with multiple
// focuses. For aura child widgets, since their views are managed by
// |focus_manager|, we then allow restoring focused view.
if (!wm::GetModalTransient(GetWidget()->GetNativeView())) {
focus_manager->RestoreFocusedView();
// Set to false if desktop native widget has activated activation
// change, so that aura window activation change focus restore
// operation can be ignored.
restore_focus_on_activate_ = false;
}
}
activation_client->ActivateWindow(
view_for_activation->GetWidget()->GetNativeView());
// Refreshes the focus info to IMF in case that IMF cached the old info
// about focused text input client when it was "inactive".
GetInputMethod()->OnFocus();
}
} else {
// TODO(nektar): We need to harmonize the firing of accessibility
// events between platforms.
// https://crbug.com/897177
NotifyAccessibilityEvent(ax::mojom::Event::kWindowDeactivated);
// If we're not active we need to deactivate the corresponding
// aura::Window. This way if a child widget is active it gets correctly
// deactivated (child widgets don't get native desktop activation changes,
// only aura activation changes).
aura::Window* active_window = activation_client->GetActiveWindow();
if (active_window) {
activation_client->DeactivateWindow(active_window);
GetInputMethod()->OnBlur();
}
}
}
gfx::NativeWindow DesktopNativeWidgetAura::GetNativeWindow() const {
return content_window_;
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation:
void DesktopNativeWidgetAura::InitNativeWidget(
const Widget::InitParams& params) {
ownership_ = params.ownership;
widget_type_ = params.type;
name_ = params.name;
NativeWidgetAura::RegisterNativeWidgetForWindow(this, content_window_);
content_window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
content_window_->Init(params.layer_type);
wm::SetShadowElevation(content_window_, wm::kShadowElevationNone);
if (!desktop_window_tree_host_) {
if (params.desktop_window_tree_host) {
desktop_window_tree_host_ = params.desktop_window_tree_host;
} else if (!ViewsDelegate::GetInstance()
->desktop_window_tree_host_factory()
.is_null()) {
desktop_window_tree_host_ =
ViewsDelegate::GetInstance()
->desktop_window_tree_host_factory()
.Run(params, native_widget_delegate_, this)
.release();
} else {
desktop_window_tree_host_ =
DesktopWindowTreeHost::Create(native_widget_delegate_, this);
}
host_.reset(desktop_window_tree_host_->AsWindowTreeHost());
}
desktop_window_tree_host_->Init(params);
host_->window()->AddChild(content_window_);
host_->window()->SetProperty(kDesktopNativeWidgetAuraKey, this);
host_->window()->AddObserver(new RootWindowDestructionObserver(this));
// The WindowsModalityController event filter should be at the head of the
// pre target handlers list. This ensures that it handles input events first
// when modal windows are at the top of the Zorder.
if (widget_type_ == Widget::InitParams::TYPE_WINDOW)
window_modality_controller_.reset(
new wm::WindowModalityController(host_->window()));
// |root_window_event_filter_| must be created before
// OnWindowTreeHostCreated() is invoked.
// CEF sets focus to the window the user clicks down on.
// TODO(beng): see if we can't do this some other way. CEF seems a heavy-
// handed way of accomplishing focus.
// No event filter for aura::Env. Create CompoundEventFilter per
// WindowEventDispatcher.
root_window_event_filter_.reset(new wm::CompoundEventFilter);
host_->window()->AddPreTargetHandler(root_window_event_filter_.get());
use_desktop_native_cursor_manager_ =
desktop_window_tree_host_->ShouldUseDesktopNativeCursorManager();
if (use_desktop_native_cursor_manager_) {
// The host's dispatcher must be added to |native_cursor_manager_| before
// OnNativeWidgetCreated() is called.
cursor_reference_count_++;
if (!native_cursor_manager_)
native_cursor_manager_ = new DesktopNativeCursorManager();
if (!cursor_manager_) {
cursor_manager_ = new wm::CursorManager(
std::unique_ptr<wm::NativeCursorManager>(native_cursor_manager_));
}
native_cursor_manager_->AddHost(host());
aura::client::SetCursorClient(host_->window(), cursor_manager_);
}
host_->window()->SetName(params.name);
content_window_->SetName("DesktopNativeWidgetAura - content window");
desktop_window_tree_host_->OnNativeWidgetCreated(params);
UpdateWindowTransparency();
capture_client_.reset(new DesktopCaptureClient(host_->window()));
wm::FocusController* focus_controller =
new wm::FocusController(new DesktopFocusRules(content_window_));
focus_client_.reset(focus_controller);
aura::client::SetFocusClient(host_->window(), focus_controller);
wm::SetActivationClient(host_->window(), focus_controller);
host_->window()->AddPreTargetHandler(focus_controller);
position_client_ = desktop_window_tree_host_->CreateScreenPositionClient();
drag_drop_client_ = desktop_window_tree_host_->CreateDragDropClient(
native_cursor_manager_);
// Mus returns null from CreateDragDropClient().
if (drag_drop_client_)
aura::client::SetDragDropClient(host_->window(), drag_drop_client_.get());
wm::SetActivationDelegate(content_window_, this);
aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
OnHostResized(host());
host_->AddObserver(this);
window_parenting_client_.reset(
new DesktopNativeWidgetAuraWindowParentingClient(host_->window()));
drop_helper_.reset(new DropHelper(GetWidget()->GetRootView()));
aura::client::SetDragDropDelegate(content_window_, this);
if (params.type != Widget::InitParams::TYPE_TOOLTIP) {
tooltip_manager_.reset(new TooltipManagerAura(GetWidget()));
tooltip_controller_.reset(
new corewm::TooltipController(
desktop_window_tree_host_->CreateTooltip()));
wm::SetTooltipClient(host_->window(), tooltip_controller_.get());
host_->window()->AddPreTargetHandler(tooltip_controller_.get());
}
if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW &&
desktop_window_tree_host_->ShouldCreateVisibilityController()) {
visibility_controller_ = std::make_unique<wm::VisibilityController>();
aura::client::SetVisibilityClient(host_->window(),
visibility_controller_.get());
wm::SetChildWindowVisibilityChangesAnimated(host_->window());
}
if (params.type == Widget::InitParams::TYPE_WINDOW) {
focus_manager_event_handler_ = std::make_unique<FocusManagerEventHandler>(
GetWidget(), host_->window());
}
event_client_.reset(new DesktopEventClient);
aura::client::SetEventClient(host_->window(), event_client_.get());
shadow_controller_.reset(new wm::ShadowController(
wm::GetActivationClient(host_->window()), nullptr));
OnSizeConstraintsChanged();
window_reorderer_.reset(new WindowReorderer(content_window_,
GetWidget()->GetRootView()));
}
void DesktopNativeWidgetAura::OnWidgetInitDone() {
desktop_window_tree_host_->OnWidgetInitDone();
}
NonClientFrameView* DesktopNativeWidgetAura::CreateNonClientFrameView() {
return desktop_window_tree_host_->CreateNonClientFrameView();
}
bool DesktopNativeWidgetAura::ShouldUseNativeFrame() const {
return desktop_window_tree_host_->ShouldUseNativeFrame();
}
bool DesktopNativeWidgetAura::ShouldWindowContentsBeTransparent() const {
return desktop_window_tree_host_->ShouldWindowContentsBeTransparent();
}
void DesktopNativeWidgetAura::FrameTypeChanged() {
desktop_window_tree_host_->FrameTypeChanged();
UpdateWindowTransparency();
}
Widget* DesktopNativeWidgetAura::GetWidget() {
return native_widget_delegate_->AsWidget();
}
const Widget* DesktopNativeWidgetAura::GetWidget() const {
return native_widget_delegate_->AsWidget();
}
gfx::NativeView DesktopNativeWidgetAura::GetNativeView() const {
return content_window_;
}
Widget* DesktopNativeWidgetAura::GetTopLevelWidget() {
return GetWidget();
}
const ui::Compositor* DesktopNativeWidgetAura::GetCompositor() const {
return content_window_ ? content_window_->layer()->GetCompositor() : nullptr;
}
const ui::Layer* DesktopNativeWidgetAura::GetLayer() const {
return content_window_ ? content_window_->layer() : nullptr;
}
void DesktopNativeWidgetAura::ReorderNativeViews() {
if (!content_window_)
return;
// Reordering native views causes multiple changes to the window tree.
// Instantiate a ScopedPause to recompute occlusion once at the end of this
// scope rather than after each individual change.
// https://crbug.com/829918
aura::WindowOcclusionTracker::ScopedPause pause_occlusion(
content_window_->env());
window_reorderer_->ReorderChildWindows();
}
void DesktopNativeWidgetAura::ViewRemoved(View* view) {
DCHECK(drop_helper_.get() != nullptr);
drop_helper_->ResetTargetViewIfEquals(view);
}
void DesktopNativeWidgetAura::SetNativeWindowProperty(const char* name,
void* value) {
if (content_window_)
content_window_->SetNativeWindowProperty(name, value);
}
void* DesktopNativeWidgetAura::GetNativeWindowProperty(const char* name) const {
return content_window_ ? content_window_->GetNativeWindowProperty(name)
: nullptr;
}
TooltipManager* DesktopNativeWidgetAura::GetTooltipManager() const {
return tooltip_manager_.get();
}
void DesktopNativeWidgetAura::SetCapture() {
if (!content_window_)
return;
content_window_->SetCapture();
}
void DesktopNativeWidgetAura::ReleaseCapture() {
if (!content_window_)
return;
content_window_->ReleaseCapture();
}
bool DesktopNativeWidgetAura::HasCapture() const {
return content_window_ && content_window_->HasCapture() &&
desktop_window_tree_host_->HasCapture();
}
ui::InputMethod* DesktopNativeWidgetAura::GetInputMethod() {
return host() ? host()->GetInputMethod() : nullptr;
}
void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) {
if (content_window_)
desktop_window_tree_host_->CenterWindow(size);
}
void DesktopNativeWidgetAura::GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* maximized) const {
if (content_window_)
desktop_window_tree_host_->GetWindowPlacement(bounds, maximized);
}
bool DesktopNativeWidgetAura::SetWindowTitle(const base::string16& title) {
if (!content_window_)
return false;
return desktop_window_tree_host_->SetWindowTitle(title);
}
void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
if (content_window_)
desktop_window_tree_host_->SetWindowIcons(window_icon, app_icon);
NativeWidgetAura::AssignIconToAuraWindow(content_window_, window_icon,
app_icon);
}
void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) {
// 99% of the time, we should not be asked to create a
// DesktopNativeWidgetAura that is modal. We only support window modal
// dialogs on the same lines as non AURA.
desktop_window_tree_host_->InitModalType(modal_type);
}
gfx::Rect DesktopNativeWidgetAura::GetWindowBoundsInScreen() const {
return content_window_ ?
desktop_window_tree_host_->GetWindowBoundsInScreen() : gfx::Rect();
}
gfx::Rect DesktopNativeWidgetAura::GetClientAreaBoundsInScreen() const {
return content_window_ ?
desktop_window_tree_host_->GetClientAreaBoundsInScreen() : gfx::Rect();
}
gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const {
return content_window_ ?
desktop_window_tree_host_->GetRestoredBounds() : gfx::Rect();
}
std::string DesktopNativeWidgetAura::GetWorkspace() const {
return content_window_ ?
desktop_window_tree_host_->GetWorkspace() : std::string();
}
void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
if (!content_window_)
return;
desktop_window_tree_host_->SetBoundsInDIP(bounds);
}
void DesktopNativeWidgetAura::SetBoundsConstrained(const gfx::Rect& bounds) {
if (!content_window_)
return;
SetBounds(NativeWidgetPrivate::ConstrainBoundsToDisplayWorkArea(bounds));
}
void DesktopNativeWidgetAura::SetSize(const gfx::Size& size) {
if (content_window_)
desktop_window_tree_host_->SetSize(size);
}
void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) {
if (content_window_)
desktop_window_tree_host_->StackAbove(native_view);
}
void DesktopNativeWidgetAura::StackAtTop() {
if (content_window_)
desktop_window_tree_host_->StackAtTop();
}
void DesktopNativeWidgetAura::SetShape(
std::unique_ptr<Widget::ShapeRects> shape) {
if (content_window_)
desktop_window_tree_host_->SetShape(std::move(shape));
}
void DesktopNativeWidgetAura::Close() {
if (!content_window_)
return;
content_window_->SuppressPaint();
desktop_window_tree_host_->Close();
}
void DesktopNativeWidgetAura::CloseNow() {
if (content_window_)
desktop_window_tree_host_->CloseNow();
}
void DesktopNativeWidgetAura::Show(ui::WindowShowState show_state,
const gfx::Rect& restore_bounds) {
if (!content_window_)
return;
desktop_window_tree_host_->Show(show_state, restore_bounds);
}
void DesktopNativeWidgetAura::Hide() {
if (!content_window_)
return;
desktop_window_tree_host_->AsWindowTreeHost()->Hide();
content_window_->Hide();
}
bool DesktopNativeWidgetAura::IsVisible() const {
// The objects checked here should be the same objects changed in
// ShowWithWindowState and ShowMaximizedWithBounds. For example, MS Windows
// platform code might show the desktop window tree host early, meaning we
// aren't fully visible as we haven't shown the content window. Callers may
// short-circuit a call to show this widget if they think its already visible.
return content_window_ && content_window_->TargetVisibility() &&
desktop_window_tree_host_->IsVisible();
}
void DesktopNativeWidgetAura::Activate() {
if (content_window_) {
bool was_active = IsActive();
desktop_window_tree_host_->Activate();
// If the whole window tree host was already active,
// treat this as a request to focus |content_window_|.
//
// Note: it might make sense to always focus |content_window_|,
// since if client code is calling Widget::Activate() they probably
// want that particular widget to be activated, not just something
// within that widget hierarchy.
if (was_active && focus_client_->GetFocusedWindow() != content_window_)
focus_client_->FocusWindow(content_window_);
}
}
void DesktopNativeWidgetAura::Deactivate() {
if (content_window_)
desktop_window_tree_host_->Deactivate();
}
bool DesktopNativeWidgetAura::IsActive() const {
return content_window_ && desktop_window_tree_host_->IsActive();
}
void DesktopNativeWidgetAura::SetAlwaysOnTop(bool always_on_top) {
if (content_window_)
desktop_window_tree_host_->SetAlwaysOnTop(always_on_top);
}
bool DesktopNativeWidgetAura::IsAlwaysOnTop() const {
return content_window_ && desktop_window_tree_host_->IsAlwaysOnTop();
}
void DesktopNativeWidgetAura::SetVisibleOnAllWorkspaces(bool always_visible) {
if (content_window_)
desktop_window_tree_host_->SetVisibleOnAllWorkspaces(always_visible);
}
bool DesktopNativeWidgetAura::IsVisibleOnAllWorkspaces() const {
return content_window_ &&
desktop_window_tree_host_->IsVisibleOnAllWorkspaces();
}
void DesktopNativeWidgetAura::Maximize() {
if (content_window_)
desktop_window_tree_host_->Maximize();
}
void DesktopNativeWidgetAura::Minimize() {
if (content_window_)
desktop_window_tree_host_->Minimize();
internal::RootView* root_view =
static_cast<internal::RootView*>(GetWidget()->GetRootView());
root_view->ResetEventHandlers();
}
bool DesktopNativeWidgetAura::IsMaximized() const {
return content_window_ && desktop_window_tree_host_->IsMaximized();
}
bool DesktopNativeWidgetAura::IsMinimized() const {
return content_window_ && desktop_window_tree_host_->IsMinimized();
}
void DesktopNativeWidgetAura::Restore() {
if (content_window_)
desktop_window_tree_host_->Restore();
}
void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen) {
if (content_window_)
desktop_window_tree_host_->SetFullscreen(fullscreen);
}
bool DesktopNativeWidgetAura::IsFullscreen() const {
return content_window_ && desktop_window_tree_host_->IsFullscreen();
}
void DesktopNativeWidgetAura::SetCanAppearInExistingFullscreenSpaces(
bool can_appear_in_existing_fullscreen_spaces) {}
void DesktopNativeWidgetAura::SetOpacity(float opacity) {
if (content_window_)
desktop_window_tree_host_->SetOpacity(opacity);
}
void DesktopNativeWidgetAura::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
if (content_window_)
desktop_window_tree_host_->SetAspectRatio(aspect_ratio);
}
void DesktopNativeWidgetAura::FlashFrame(bool flash_frame) {
if (content_window_)
desktop_window_tree_host_->FlashFrame(flash_frame);
}
void DesktopNativeWidgetAura::RunShellDrag(
View* view,
const ui::OSExchangeData& data,
const gfx::Point& location,
int operation,
ui::DragDropTypes::DragEventSource source) {
views::RunShellDrag(content_window_, data, location, operation, source);
}
void DesktopNativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
if (content_window_)
content_window_->SchedulePaintInRect(rect);
}
void DesktopNativeWidgetAura::SetCursor(gfx::NativeCursor cursor) {
cursor_ = cursor;
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(host_->window());
if (cursor_client)
cursor_client->SetCursor(cursor);
}
bool DesktopNativeWidgetAura::IsMouseEventsEnabled() const {
// We explicitly check |host_| here because it can be null during the process
// of widget shutdown (even if |content_window_| is not), and must be valid to
// determine if mouse events are enabled.
if (!content_window_ || !host_)
return false;
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(host_->window());
return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
}
bool DesktopNativeWidgetAura::IsMouseButtonDown() const {
return content_window_ ? content_window_->env()->IsMouseButtonDown()
: aura::Env::GetInstance()->IsMouseButtonDown();
}
void DesktopNativeWidgetAura::ClearNativeFocus() {
desktop_window_tree_host_->ClearNativeFocus();
if (ShouldActivate()) {
aura::client::GetFocusClient(content_window_)->
ResetFocusWithinActiveWindow(content_window_);
}
}
gfx::Rect DesktopNativeWidgetAura::GetWorkAreaBoundsInScreen() const {
return desktop_window_tree_host_ ?
desktop_window_tree_host_->GetWorkAreaBoundsInScreen() : gfx::Rect();
}
Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
if (!content_window_)
return Widget::MOVE_LOOP_CANCELED;
return desktop_window_tree_host_->RunMoveLoop(drag_offset, source,
escape_behavior);
}
void DesktopNativeWidgetAura::EndMoveLoop() {
if (content_window_)
desktop_window_tree_host_->EndMoveLoop();
}
void DesktopNativeWidgetAura::SetVisibilityChangedAnimationsEnabled(
bool value) {
if (content_window_)
desktop_window_tree_host_->SetVisibilityChangedAnimationsEnabled(value);
}
void DesktopNativeWidgetAura::SetVisibilityAnimationDuration(
const base::TimeDelta& duration) {
wm::SetWindowVisibilityAnimationDuration(content_window_, duration);
}
void DesktopNativeWidgetAura::SetVisibilityAnimationTransition(
Widget::VisibilityTransition transition) {
wm::WindowVisibilityAnimationTransition wm_transition = wm::ANIMATE_NONE;
switch (transition) {
case Widget::ANIMATE_SHOW:
wm_transition = wm::ANIMATE_SHOW;
break;
case Widget::ANIMATE_HIDE:
wm_transition = wm::ANIMATE_HIDE;
break;
case Widget::ANIMATE_BOTH:
wm_transition = wm::ANIMATE_BOTH;
break;
case Widget::ANIMATE_NONE:
wm_transition = wm::ANIMATE_NONE;
break;
}
wm::SetWindowVisibilityAnimationTransition(content_window_, wm_transition);
}
bool DesktopNativeWidgetAura::IsTranslucentWindowOpacitySupported() const {
return content_window_ &&
desktop_window_tree_host_->IsTranslucentWindowOpacitySupported();
}
ui::GestureRecognizer* DesktopNativeWidgetAura::GetGestureRecognizer() {
return content_window_->env()->gesture_recognizer();
}
void DesktopNativeWidgetAura::OnSizeConstraintsChanged() {
int32_t behavior = ws::mojom::kResizeBehaviorNone;
if (GetWidget()->widget_delegate())
behavior = GetWidget()->widget_delegate()->GetResizeBehavior();
content_window_->SetProperty(aura::client::kResizeBehaviorKey, behavior);
desktop_window_tree_host_->SizeConstraintsChanged();
}
void DesktopNativeWidgetAura::OnCanActivateChanged() {
desktop_window_tree_host_->OnCanActivateChanged();
}
std::string DesktopNativeWidgetAura::GetName() const {
return name_;
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, aura::WindowDelegate implementation:
gfx::Size DesktopNativeWidgetAura::GetMinimumSize() const {
return native_widget_delegate_->GetMinimumSize();
}
gfx::Size DesktopNativeWidgetAura::GetMaximumSize() const {
return native_widget_delegate_->GetMaximumSize();
}
gfx::NativeCursor DesktopNativeWidgetAura::GetCursor(const gfx::Point& point) {
return cursor_;
}
int DesktopNativeWidgetAura::GetNonClientComponent(
const gfx::Point& point) const {
return native_widget_delegate_->GetNonClientComponent(point);
}
bool DesktopNativeWidgetAura::ShouldDescendIntoChildForEventHandling(
aura::Window* child,
const gfx::Point& location) {
return native_widget_delegate_->ShouldDescendIntoChildForEventHandling(
content_window_->layer(), child, child->layer(), location);
}
bool DesktopNativeWidgetAura::CanFocus() {
return true;
}
void DesktopNativeWidgetAura::OnCaptureLost() {
native_widget_delegate_->OnMouseCaptureLost();
}
void DesktopNativeWidgetAura::OnPaint(const ui::PaintContext& context) {
native_widget_delegate_->OnNativeWidgetPaint(context);
}
void DesktopNativeWidgetAura::OnDeviceScaleFactorChanged(
float old_device_scale_factor,
float new_device_scale_factor) {}
void DesktopNativeWidgetAura::OnWindowDestroying(aura::Window* window) {
// Cleanup happens in OnHostClosed().
}
void DesktopNativeWidgetAura::OnWindowDestroyed(aura::Window* window) {
// Cleanup happens in OnHostClosed(). We own |content_window_| (indirectly by
// way of |dispatcher_|) so there should be no need to do any processing
// here.
}
void DesktopNativeWidgetAura::OnWindowTargetVisibilityChanged(bool visible) {
}
bool DesktopNativeWidgetAura::HasHitTestMask() const {
return native_widget_delegate_->HasHitTestMask();
}
void DesktopNativeWidgetAura::GetHitTestMask(SkPath* mask) const {
native_widget_delegate_->GetHitTestMask(mask);
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, ui::EventHandler implementation:
void DesktopNativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) {
if (event->is_char()) {
// If a ui::InputMethod object is attached to the root window, character
// events are handled inside the object and are not passed to this function.
// If such object is not attached, character events might be sent (e.g. on
// Windows). In this case, we just skip these.
return;
}
// Renderer may send a key event back to us if the key event wasn't handled,
// and the window may be invisible by that time.
if (!content_window_->IsVisible())
return;
native_widget_delegate_->OnKeyEvent(event);
}
void DesktopNativeWidgetAura::OnMouseEvent(ui::MouseEvent* event) {
DCHECK(content_window_->IsVisible());
if (tooltip_manager_.get())
tooltip_manager_->UpdateTooltip();
TooltipManagerAura::UpdateTooltipManagerForCapture(GetWidget());
native_widget_delegate_->OnMouseEvent(event);
// WARNING: we may have been deleted.
}
void DesktopNativeWidgetAura::OnScrollEvent(ui::ScrollEvent* event) {
if (event->type() == ui::ET_SCROLL) {
native_widget_delegate_->OnScrollEvent(event);
if (event->handled())
return;
// Convert unprocessed scroll events into wheel events.
ui::MouseWheelEvent mwe(*event->AsScrollEvent());
native_widget_delegate_->OnMouseEvent(&mwe);
if (mwe.handled())
event->SetHandled();
} else {
native_widget_delegate_->OnScrollEvent(event);
}
}
void DesktopNativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
native_widget_delegate_->OnGestureEvent(event);
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, wm::ActivationDelegate implementation:
bool DesktopNativeWidgetAura::ShouldActivate() const {
return native_widget_delegate_->CanActivate();
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, wm::ActivationChangeObserver implementation:
void DesktopNativeWidgetAura::OnWindowActivated(
wm::ActivationChangeObserver::ActivationReason reason,
aura::Window* gained_active,
aura::Window* lost_active) {
DCHECK(content_window_ == gained_active || content_window_ == lost_active);
if (gained_active == content_window_ && restore_focus_on_activate_) {
restore_focus_on_activate_ = false;
// For OS_LINUX, desktop native widget may not be activated when child
// widgets gets aura activation changes. Only when desktop native widget is
// active, we can rely on aura activation to restore focused view.
if (GetWidget()->IsActive())
GetWidget()->GetFocusManager()->RestoreFocusedView();
} else if (lost_active == content_window_ && GetWidget()->HasFocusManager()) {
DCHECK(!restore_focus_on_activate_);
restore_focus_on_activate_ = true;
// Pass in false so that ClearNativeFocus() isn't invoked.
GetWidget()->GetFocusManager()->StoreFocusedView(false);
}
// Give the native widget a chance to handle any specific changes it needs.
desktop_window_tree_host_->OnActiveWindowChanged(content_window_ ==
gained_active);
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, aura::client::FocusChangeObserver implementation:
void DesktopNativeWidgetAura::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
if (content_window_ == gained_focus) {
native_widget_delegate_->OnNativeFocus();
} else if (content_window_ == lost_focus) {
native_widget_delegate_->OnNativeBlur();
}
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, aura::WindowDragDropDelegate implementation:
void DesktopNativeWidgetAura::OnDragEntered(const ui::DropTargetEvent& event) {
DCHECK(drop_helper_.get() != nullptr);
last_drop_operation_ = drop_helper_->OnDragOver(event.data(),
event.location(), event.source_operations());
}
int DesktopNativeWidgetAura::OnDragUpdated(const ui::DropTargetEvent& event) {
DCHECK(drop_helper_.get() != nullptr);
last_drop_operation_ = drop_helper_->OnDragOver(event.data(),
event.location(), event.source_operations());
return last_drop_operation_;
}
void DesktopNativeWidgetAura::OnDragExited() {
DCHECK(drop_helper_.get() != nullptr);
drop_helper_->OnDragExit();
}
int DesktopNativeWidgetAura::OnPerformDrop(const ui::DropTargetEvent& event) {
DCHECK(drop_helper_.get() != nullptr);
if (ShouldActivate())
Activate();
return drop_helper_->OnDrop(event.data(), event.location(),
last_drop_operation_);
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, aura::WindowTreeHostObserver implementation:
void DesktopNativeWidgetAura::OnHostCloseRequested(aura::WindowTreeHost* host) {
GetWidget()->Close();
}
void DesktopNativeWidgetAura::OnHostResized(aura::WindowTreeHost* host) {
// Don't update the bounds of the child layers when animating closed. If we
// did it would force a paint, which we don't want. We don't want the paint
// as we can't assume any of the children are valid.
if (desktop_window_tree_host_->IsAnimatingClosed())
return;
gfx::Rect new_bounds = gfx::Rect(host->window()->bounds().size());
content_window_->SetBounds(new_bounds);
native_widget_delegate_->OnNativeWidgetSizeChanged(new_bounds.size());
}
void DesktopNativeWidgetAura::OnHostWorkspaceChanged(
aura::WindowTreeHost* host) {
native_widget_delegate_->OnNativeWidgetWorkspaceChanged();
}
void DesktopNativeWidgetAura::OnHostMovedInPixels(
aura::WindowTreeHost* host,
const gfx::Point& new_origin_in_pixels) {
TRACE_EVENT1("views", "DesktopNativeWidgetAura::OnHostMovedInPixels",
"new_origin_in_pixels", new_origin_in_pixels.ToString());
native_widget_delegate_->OnNativeWidgetMove();
}
////////////////////////////////////////////////////////////////////////////////
// DesktopNativeWidgetAura, private:
void DesktopNativeWidgetAura::UpdateWindowTransparency() {
if (!desktop_window_tree_host_->ShouldUpdateWindowTransparency())
return;
content_window_->SetTransparent(
desktop_window_tree_host_->ShouldWindowContentsBeTransparent());
// Regardless of transparency or not, this root content window will always
// fill its bounds completely, so set this flag to true to avoid an
// unecessary clear before update.
content_window_->SetFillsBoundsCompletely(true);
}
void DesktopNativeWidgetAura::RootWindowDestroyed() {
cursor_reference_count_--;
if (cursor_reference_count_ == 0) {
// We are the last DesktopNativeWidgetAura instance, and we are responsible
// for cleaning up |cursor_manager_|.
delete cursor_manager_;
native_cursor_manager_ = nullptr;
cursor_manager_ = nullptr;
}
}
} // namespace views