blob: 09c3a663aee3d1ac9b0af88df593b5560933eea2 [file] [log] [blame]
// Copyright 2016 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/mus/desktop_window_tree_host_mus.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/capture_client.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/transient_window_client.h"
#include "ui/aura/mus/focus_synchronizer.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/mus/mus_client.h"
#include "ui/views/mus/mus_property_mirror.h"
#include "ui/views/mus/window_manager_frame_values.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/cursor_manager.h"
#include "ui/wm/core/native_cursor_manager.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h"
#if defined(USE_OZONE)
#include "ui/base/cursor/ozone/cursor_data_factory_ozone.h"
#endif
namespace views {
namespace {
// As the window manager renderers the non-client decorations this class does
// very little but honor the client area insets from the window manager.
class ClientSideNonClientFrameView : public NonClientFrameView {
public:
explicit ClientSideNonClientFrameView(views::Widget* widget)
: widget_(widget) {}
~ClientSideNonClientFrameView() override {}
private:
// Returns the default values of client area insets from the window manager.
static gfx::Insets GetDefaultWindowManagerInsets(bool is_maximized) {
const WindowManagerFrameValues& values =
WindowManagerFrameValues::instance();
return is_maximized ? values.maximized_insets : values.normal_insets;
}
// NonClientFrameView:
gfx::Rect GetBoundsForClientView() const override {
gfx::Rect result(GetLocalBounds());
if (widget_->IsFullscreen())
return result;
result.Inset(GetDefaultWindowManagerInsets(widget_->IsMaximized()));
return result;
}
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override {
if (widget_->IsFullscreen())
return client_bounds;
const gfx::Insets insets(
GetDefaultWindowManagerInsets(widget_->IsMaximized()));
return gfx::Rect(client_bounds.x() - insets.left(),
client_bounds.y() - insets.top(),
client_bounds.width() + insets.width(),
client_bounds.height() + insets.height());
}
int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; }
void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override {
// The window manager provides the shape; do nothing.
}
void ResetWindowControls() override {
// TODO(sky): push to wm?
}
// These have no implementation. The Window Manager handles the actual
// rendering of the icon/title. See NonClientFrameViewMash. The values
// associated with these methods are pushed to the server by the way of
// NativeWidgetMus functions.
void UpdateWindowIcon() override {}
void UpdateWindowTitle() override {}
void SizeConstraintsChanged() override {}
gfx::Size CalculatePreferredSize() const override {
return widget_->non_client_view()
->GetWindowBoundsForClientBounds(
gfx::Rect(widget_->client_view()->GetPreferredSize()))
.size();
}
gfx::Size GetMinimumSize() const override {
return widget_->non_client_view()
->GetWindowBoundsForClientBounds(
gfx::Rect(widget_->client_view()->GetMinimumSize()))
.size();
}
gfx::Size GetMaximumSize() const override {
gfx::Size max_size = widget_->client_view()->GetMaximumSize();
gfx::Size converted_size =
widget_->non_client_view()
->GetWindowBoundsForClientBounds(gfx::Rect(max_size))
.size();
return gfx::Size(max_size.width() == 0 ? 0 : converted_size.width(),
max_size.height() == 0 ? 0 : converted_size.height());
}
views::Widget* widget_;
DISALLOW_COPY_AND_ASSIGN(ClientSideNonClientFrameView);
};
class NativeCursorManagerMus : public wm::NativeCursorManager {
public:
explicit NativeCursorManagerMus(aura::Window* window) : window_(window) {}
~NativeCursorManagerMus() override {}
// wm::NativeCursorManager:
void SetDisplay(const display::Display& display,
wm::NativeCursorManagerDelegate* delegate) override {
// We ignore this entirely, as cursor are set on the client.
}
void SetCursor(gfx::NativeCursor cursor,
wm::NativeCursorManagerDelegate* delegate) override {
ui::CursorData mojo_cursor;
if (cursor.platform()) {
#if defined(USE_OZONE)
mojo_cursor =
ui::CursorDataFactoryOzone::GetCursorData(cursor.platform());
#else
NOTIMPLEMENTED()
<< "Can't pass native platform cursors on non-ozone platforms";
mojo_cursor = ui::CursorData(ui::CursorType::kPointer);
#endif
} else {
mojo_cursor = ui::CursorData(cursor.native_type());
}
aura::WindowPortMus::Get(window_)->SetCursor(mojo_cursor);
delegate->CommitCursor(cursor);
}
void SetVisibility(bool visible,
wm::NativeCursorManagerDelegate* delegate) override {
delegate->CommitVisibility(visible);
if (visible) {
SetCursor(delegate->GetCursor(), delegate);
} else {
aura::WindowPortMus::Get(window_)->SetCursor(
ui::CursorData(ui::CursorType::kNone));
}
}
void SetCursorSize(ui::CursorSize cursor_size,
wm::NativeCursorManagerDelegate* delegate) override {
// TODO(erg): For now, ignore the difference between SET_NORMAL and
// SET_LARGE here. This feels like a thing that mus should decide instead.
//
// Also, it's NOTIMPLEMENTED() in the desktop version!? Including not
// acknowledging the call in the delegate.
NOTIMPLEMENTED();
}
void SetMouseEventsEnabled(
bool enabled,
wm::NativeCursorManagerDelegate* delegate) override {
// TODO(erg): How do we actually implement this?
//
// Mouse event dispatch is potentially done in a different process,
// definitely in a different mojo service. Each app is fairly locked down.
delegate->CommitMouseEventsEnabled(enabled);
NOTIMPLEMENTED();
}
private:
aura::Window* window_;
DISALLOW_COPY_AND_ASSIGN(NativeCursorManagerMus);
};
void OnMoveLoopEnd(bool* out_success,
base::Closure quit_closure,
bool in_success) {
*out_success = in_success;
quit_closure.Run();
}
} // namespace
DesktopWindowTreeHostMus::DesktopWindowTreeHostMus(
aura::WindowTreeHostMusInitParams init_params,
internal::NativeWidgetDelegate* native_widget_delegate,
DesktopNativeWidgetAura* desktop_native_widget_aura)
: aura::WindowTreeHostMus(std::move(init_params)),
native_widget_delegate_(native_widget_delegate),
desktop_native_widget_aura_(desktop_native_widget_aura),
close_widget_factory_(this) {
MusClient::Get()->AddObserver(this);
MusClient::Get()->window_tree_client()->focus_synchronizer()->AddObserver(
this);
content_window()->AddObserver(this);
// DesktopNativeWidgetAura registers the association between |content_window_|
// and Widget, but code may also want to go from the root (window()) to the
// Widget. This call enables that.
NativeWidgetAura::RegisterNativeWidgetForWindow(desktop_native_widget_aura,
window());
// TODO: use display id and bounds if available, likely need to pass in
// InitParams for that.
}
DesktopWindowTreeHostMus::~DesktopWindowTreeHostMus() {
// The cursor-client can be accessed during WindowTreeHostMus tear-down. So
// the cursor-client needs to be unset on the root-window before
// |cursor_manager_| is destroyed.
aura::client::SetCursorClient(window(), nullptr);
content_window()->RemoveObserver(this);
MusClient::Get()->RemoveObserver(this);
MusClient::Get()->window_tree_client()->focus_synchronizer()->RemoveObserver(
this);
desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
}
void DesktopWindowTreeHostMus::SendClientAreaToServer() {
if (!ShouldSendClientAreaToServer())
return;
NonClientView* non_client_view =
native_widget_delegate_->AsWidget()->non_client_view();
if (!non_client_view || !non_client_view->client_view())
return;
const gfx::Rect client_area_rect(non_client_view->client_view()->bounds());
SetClientArea(
gfx::Insets(
client_area_rect.y(), client_area_rect.x(),
non_client_view->bounds().height() - client_area_rect.bottom(),
non_client_view->bounds().width() - client_area_rect.right()),
std::vector<gfx::Rect>());
}
void DesktopWindowTreeHostMus::SendHitTestMaskToServer() {
if (!native_widget_delegate_->HasHitTestMask()) {
aura::WindowPortMus::Get(window())->SetHitTestMask(base::nullopt);
return;
}
gfx::Path mask_path;
native_widget_delegate_->GetHitTestMask(&mask_path);
// TODO(jamescook): Use the full path for the mask.
gfx::Rect mask_rect =
gfx::ToEnclosingRect(gfx::SkRectToRectF(mask_path.getBounds()));
aura::WindowPortMus::Get(window())->SetHitTestMask(mask_rect);
}
bool DesktopWindowTreeHostMus::IsFocusClientInstalledOnFocusSynchronizer()
const {
return MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->active_focus_client() == aura::client::GetFocusClient(window());
}
float DesktopWindowTreeHostMus::GetScaleFactor() const {
// TODO(sky): GetDisplayNearestWindow() should take a const aura::Window*.
return display::Screen::GetScreen()
->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
.device_scale_factor();
}
void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) {
SetBoundsInPixels(gfx::ConvertRectToPixel(GetScaleFactor(), bounds_in_dip));
}
bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
if (!auto_update_client_area_)
return false;
using WIP = views::Widget::InitParams;
const WIP::Type type = desktop_native_widget_aura_->widget_type();
return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL;
}
void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
// |TYPE_WINDOW| and |TYPE_PANEL| are forced to transparent as otherwise the
// window is opaque and the client decorations drawn by the window manager
// would not be seen.
const bool transparent =
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW ||
params.type == Widget::InitParams::TYPE_WINDOW ||
params.type == Widget::InitParams::TYPE_PANEL;
content_window()->SetTransparent(transparent);
window()->SetTransparent(transparent);
window()->SetProperty(aura::client::kShowStateKey, params.show_state);
if (!params.bounds.IsEmpty())
SetBoundsInDIP(params.bounds);
cursor_manager_ = std::make_unique<wm::CursorManager>(
std::make_unique<NativeCursorManagerMus>(window()));
aura::client::SetCursorClient(window(), cursor_manager_.get());
InitHost();
NativeWidgetAura::SetShadowElevationFromInitParams(window(), params);
// Transient parents are connected using the Window created by WindowTreeHost,
// which is owned by the window manager. This way the window manager can
// properly identify and honor transients.
if (params.parent && params.parent->GetHost()) {
aura::client::GetTransientWindowClient()->AddTransientChild(
params.parent->GetHost()->window(), window());
}
if (!params.accept_events)
window()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::NONE);
else
aura::WindowPortMus::Get(content_window())->SetCanAcceptDrops(true);
}
void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
const Widget::InitParams& params) {
window()->SetName(params.name);
content_window()->SetName("DesktopNativeWidgetAura - content window");
if (params.parent && params.parent->GetHost()) {
parent_ = static_cast<DesktopWindowTreeHostMus*>(params.parent->GetHost());
parent_->children_.insert(this);
}
native_widget_delegate_->OnNativeWidgetCreated(true);
}
void DesktopWindowTreeHostMus::OnActiveWindowChanged(bool active) {
// This function is called when there is a change in the active window the
// FocusClient for window() is associated with. This needs to potentially
// propagate to mus (the change may originate locally, not from mus).
// Propagating to the server is done by resetting the ActiveFocusClient.
if (active && !IsFocusClientInstalledOnFocusSynchronizer()) {
MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->SetActiveFocusClient(aura::client::GetFocusClient(window()),
window());
} else if (!active && IsFocusClientInstalledOnFocusSynchronizer()) {
MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->SetActiveFocusClient(nullptr, nullptr);
}
}
void DesktopWindowTreeHostMus::OnWidgetInitDone() {
// Because of construction order it's possible the bounds have changed before
// the NonClientView was created, which means we may not have sent the
// client-area and hit-test-mask.
SendClientAreaToServer();
SendHitTestMaskToServer();
MusClient::Get()->OnCaptureClientSet(
aura::client::GetCaptureClient(window()));
}
std::unique_ptr<corewm::Tooltip> DesktopWindowTreeHostMus::CreateTooltip() {
return std::make_unique<corewm::TooltipAura>();
}
std::unique_ptr<aura::client::DragDropClient>
DesktopWindowTreeHostMus::CreateDragDropClient(
DesktopNativeCursorManager* cursor_manager) {
// aura-mus handles installing a DragDropClient.
return nullptr;
}
void DesktopWindowTreeHostMus::Close() {
if (close_widget_factory_.HasWeakPtrs())
return;
// Even though we don't close immediately, we need to hide immediately
// (otherwise events may be processed, which is unexpected).
Hide();
// Close doesn't delete this immediately, as 'this' may still be on the stack
// resulting in possible crashes when the stack unwindes.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&DesktopWindowTreeHostMus::CloseNow,
close_widget_factory_.GetWeakPtr()));
}
void DesktopWindowTreeHostMus::CloseNow() {
MusClient::Get()->OnCaptureClientUnset(
aura::client::GetCaptureClient(window()));
native_widget_delegate_->OnNativeWidgetDestroying();
// If we have children, close them. Use a copy for iteration because they'll
// remove themselves from |children_|.
std::set<DesktopWindowTreeHostMus*> children_copy = children_;
for (DesktopWindowTreeHostMus* child : children_copy)
child->CloseNow();
DCHECK(children_.empty());
if (parent_) {
parent_->children_.erase(this);
parent_ = nullptr;
}
DestroyCompositor();
desktop_native_widget_aura_->OnHostClosed();
}
aura::WindowTreeHost* DesktopWindowTreeHostMus::AsWindowTreeHost() {
return this;
}
void DesktopWindowTreeHostMus::ShowWindowWithState(ui::WindowShowState state) {
if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN)
window()->SetProperty(aura::client::kShowStateKey, state);
window()->Show();
if (compositor())
compositor()->SetVisible(true);
native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
if (native_widget_delegate_->CanActivate()) {
if (state != ui::SHOW_STATE_INACTIVE)
Activate();
// SetInitialFocus() should be always be called, even for
// SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will
// do the right thing.
// Activate() might fail if the window is non-activatable. In this case, we
// should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial
// focused view from getting focused. See crbug.com/515594 for example.
native_widget_delegate_->SetInitialFocus(
IsActive() ? state : ui::SHOW_STATE_INACTIVE);
}
}
void DesktopWindowTreeHostMus::ShowMaximizedWithBounds(
const gfx::Rect& restored_bounds) {
window()->SetProperty(aura::client::kRestoreBoundsKey,
new gfx::Rect(restored_bounds));
ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
}
bool DesktopWindowTreeHostMus::IsVisible() const {
// Go through the DesktopNativeWidgetAura::IsVisible() for checking
// visibility of the parent as it has additional checks beyond checking the
// aura::Window.
return window()->IsVisible() &&
(!parent_ ||
static_cast<const internal::NativeWidgetPrivate*>(
parent_->desktop_native_widget_aura_)
->IsVisible());
}
void DesktopWindowTreeHostMus::SetSize(const gfx::Size& size) {
// Use GetBounds() as the origin of window() is always at 0, 0.
gfx::Rect screen_bounds =
gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
screen_bounds.set_size(size);
SetBoundsInDIP(screen_bounds);
}
void DesktopWindowTreeHostMus::StackAbove(aura::Window* relative) {
// Windows and X11 check for |relative| being nullptr and fail silently. It
// also looks like |relative| is usually multiple children deep in the root
// window, which we must pass instead.
if (relative && relative->GetRootWindow())
WindowTreeHostMus::StackAbove(relative->GetRootWindow());
}
void DesktopWindowTreeHostMus::StackAtTop() {
// Request to the server to stack our current mus window at the top. Our
// window() is a root, and we can't reach up past it so we can't just request
// a Reorder(), which is what we'd do to reorder our own subwindows.
WindowTreeHostMus::StackAtTop();
}
void DesktopWindowTreeHostMus::CenterWindow(const gfx::Size& size) {
gfx::Rect bounds_to_center_in = GetWorkAreaBoundsInScreen();
// If there is a transient parent and it fits |size|, then center over it.
if (wm::GetTransientParent(content_window())) {
gfx::Rect transient_parent_bounds =
wm::GetTransientParent(content_window())->GetBoundsInScreen();
if (transient_parent_bounds.height() >= size.height() &&
transient_parent_bounds.width() >= size.width()) {
bounds_to_center_in = transient_parent_bounds;
}
}
gfx::Rect resulting_bounds(bounds_to_center_in);
resulting_bounds.ClampToCenteredSize(size);
SetBoundsInDIP(resulting_bounds);
}
void DesktopWindowTreeHostMus::GetWindowPlacement(
gfx::Rect* bounds,
ui::WindowShowState* show_state) const {
// Implementation matches that of NativeWidgetAura.
*bounds = GetRestoredBounds();
*show_state = window()->GetProperty(aura::client::kShowStateKey);
}
gfx::Rect DesktopWindowTreeHostMus::GetWindowBoundsInScreen() const {
return gfx::ConvertRectToDIP(GetScaleFactor(), GetBoundsInPixels());
}
gfx::Rect DesktopWindowTreeHostMus::GetClientAreaBoundsInScreen() const {
// View-to-screen coordinate system transformations depend on this returning
// the full window bounds, for example View::ConvertPointToScreen().
return GetWindowBoundsInScreen();
}
gfx::Rect DesktopWindowTreeHostMus::GetRestoredBounds() const {
// Restored bounds should only be relevant if the window is minimized,
// maximized, or fullscreen. However, in some places the code expects
// GetRestoredBounds() to return the current window bounds if the window is
// not in either state.
if (IsMinimized() || IsMaximized() || IsFullscreen()) {
// Restore bounds are in screen coordinates, no need to convert.
gfx::Rect* restore_bounds =
window()->GetProperty(aura::client::kRestoreBoundsKey);
if (restore_bounds)
return *restore_bounds;
}
return GetWindowBoundsInScreen();
}
std::string DesktopWindowTreeHostMus::GetWorkspace() const {
// Only used on x11.
return std::string();
}
gfx::Rect DesktopWindowTreeHostMus::GetWorkAreaBoundsInScreen() const {
// TODO(sky): GetDisplayNearestWindow() should take a const aura::Window*.
return display::Screen::GetScreen()
->GetDisplayNearestWindow(const_cast<aura::Window*>(window()))
.work_area();
}
void DesktopWindowTreeHostMus::SetShape(
std::unique_ptr<Widget::ShapeRects> native_shape) {
NOTIMPLEMENTED();
}
void DesktopWindowTreeHostMus::Activate() {
if (!IsVisible())
return;
// This should result in OnActiveFocusClientChanged() being called, which
// triggers a call to DesktopNativeWidgetAura::HandleActivationChanged(),
// which focuses the right window.
MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->SetActiveFocusClient(aura::client::GetFocusClient(window()), window());
if (is_active_)
window()->SetProperty(aura::client::kDrawAttentionKey, false);
}
void DesktopWindowTreeHostMus::Deactivate() {
if (!is_active_)
return;
// Reset the active focus client, which will trigger resetting active status.
// This is done so that we deactivate immediately.
DCHECK(IsFocusClientInstalledOnFocusSynchronizer());
MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->SetActiveFocusClient(nullptr, nullptr);
DCHECK(!is_active_);
// Then ask the window manager to deactivate, which effectively means pick
// another window to activate.
DeactivateWindow();
}
bool DesktopWindowTreeHostMus::IsActive() const {
return is_active_;
}
void DesktopWindowTreeHostMus::Maximize() {
window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
}
void DesktopWindowTreeHostMus::Minimize() {
window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
}
void DesktopWindowTreeHostMus::Restore() {
window()->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
}
bool DesktopWindowTreeHostMus::IsMaximized() const {
return window()->GetProperty(aura::client::kShowStateKey) ==
ui::SHOW_STATE_MAXIMIZED;
}
bool DesktopWindowTreeHostMus::IsMinimized() const {
return window()->GetProperty(aura::client::kShowStateKey) ==
ui::SHOW_STATE_MINIMIZED;
}
bool DesktopWindowTreeHostMus::HasCapture() const {
// Capture state is held by DesktopNativeWidgetAura::content_window_.
// DesktopNativeWidgetAura::HasCapture() calls content_window_->HasCapture(),
// and this. That means this function can always return true.
return true;
}
void DesktopWindowTreeHostMus::SetAlwaysOnTop(bool always_on_top) {
window()->SetProperty(aura::client::kAlwaysOnTopKey, always_on_top);
}
bool DesktopWindowTreeHostMus::IsAlwaysOnTop() const {
return window()->GetProperty(aura::client::kAlwaysOnTopKey);
}
void DesktopWindowTreeHostMus::SetVisibleOnAllWorkspaces(bool always_visible) {
// Not applicable to chromeos.
}
bool DesktopWindowTreeHostMus::IsVisibleOnAllWorkspaces() const {
return false;
}
bool DesktopWindowTreeHostMus::SetWindowTitle(const base::string16& title) {
if (window()->GetTitle() == title)
return false;
window()->SetTitle(title);
return true;
}
void DesktopWindowTreeHostMus::ClearNativeFocus() {
aura::client::FocusClient* client = aura::client::GetFocusClient(window());
if (client && window()->Contains(client->GetFocusedWindow()))
client->ResetFocusWithinActiveWindow(window());
}
Widget::MoveLoopResult DesktopWindowTreeHostMus::RunMoveLoop(
const gfx::Vector2d& drag_offset,
Widget::MoveLoopSource source,
Widget::MoveLoopEscapeBehavior escape_behavior) {
static_cast<internal::NativeWidgetPrivate*>(
desktop_native_widget_aura_)->ReleaseCapture();
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
ui::mojom::MoveLoopSource mus_source =
source == Widget::MOVE_LOOP_SOURCE_MOUSE
? ui::mojom::MoveLoopSource::MOUSE
: ui::mojom::MoveLoopSource::TOUCH;
bool success = false;
gfx::Point cursor_location =
display::Screen::GetScreen()->GetCursorScreenPoint();
WindowTreeHostMus::PerformWindowMove(
mus_source, cursor_location,
base::Bind(OnMoveLoopEnd, &success, run_loop.QuitClosure()));
run_loop.Run();
return success ? Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
}
void DesktopWindowTreeHostMus::EndMoveLoop() {
WindowTreeHostMus::CancelWindowMove();
}
void DesktopWindowTreeHostMus::SetVisibilityChangedAnimationsEnabled(
bool value) {
window()->SetProperty(aura::client::kAnimationsDisabledKey, !value);
}
NonClientFrameView* DesktopWindowTreeHostMus::CreateNonClientFrameView() {
if (!ShouldSendClientAreaToServer())
return nullptr;
return new ClientSideNonClientFrameView(native_widget_delegate_->AsWidget());
}
bool DesktopWindowTreeHostMus::ShouldUseNativeFrame() const {
return false;
}
bool DesktopWindowTreeHostMus::ShouldWindowContentsBeTransparent() const {
return false;
}
void DesktopWindowTreeHostMus::FrameTypeChanged() {}
void DesktopWindowTreeHostMus::SetFullscreen(bool fullscreen) {
if (IsFullscreen() == fullscreen)
return; // Nothing to do.
wm::SetWindowFullscreen(window(), fullscreen);
}
bool DesktopWindowTreeHostMus::IsFullscreen() const {
return window()->GetProperty(aura::client::kShowStateKey) ==
ui::SHOW_STATE_FULLSCREEN;
}
void DesktopWindowTreeHostMus::SetOpacity(float opacity) {
WindowTreeHostMus::SetOpacity(opacity);
}
void DesktopWindowTreeHostMus::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
NativeWidgetAura::AssignIconToAuraWindow(window(), window_icon, app_icon);
}
void DesktopWindowTreeHostMus::InitModalType(ui::ModalType modal_type) {
window()->SetProperty(aura::client::kModalKey, modal_type);
}
void DesktopWindowTreeHostMus::FlashFrame(bool flash_frame) {
window()->SetProperty(aura::client::kDrawAttentionKey, flash_frame);
}
bool DesktopWindowTreeHostMus::IsAnimatingClosed() const {
return false;
}
bool DesktopWindowTreeHostMus::IsTranslucentWindowOpacitySupported() const {
return true;
}
void DesktopWindowTreeHostMus::SizeConstraintsChanged() {
int32_t behavior = ui::mojom::kResizeBehaviorNone;
Widget* widget = native_widget_delegate_->AsWidget();
if (widget->widget_delegate())
behavior = widget->widget_delegate()->GetResizeBehavior();
window()->SetProperty(aura::client::kResizeBehaviorKey, behavior);
}
bool DesktopWindowTreeHostMus::ShouldUpdateWindowTransparency() const {
// Needed so the window manager can render the client decorations.
return false;
}
bool DesktopWindowTreeHostMus::ShouldUseDesktopNativeCursorManager() const {
// We manage the cursor ourself.
return false;
}
bool DesktopWindowTreeHostMus::ShouldCreateVisibilityController() const {
// Window manager takes care of all top-level window animations.
return false;
}
void DesktopWindowTreeHostMus::OnWindowManagerFrameValuesChanged() {
NonClientView* non_client_view =
native_widget_delegate_->AsWidget()->non_client_view();
if (non_client_view) {
non_client_view->Layout();
non_client_view->SchedulePaint();
}
SendClientAreaToServer();
SendHitTestMaskToServer();
}
void DesktopWindowTreeHostMus::OnActiveFocusClientChanged(
aura::client::FocusClient* focus_client,
aura::Window* focus_client_root) {
if (focus_client_root == this->window()) {
is_active_ = true;
desktop_native_widget_aura_->HandleActivationChanged(true);
} else if (is_active_) {
is_active_ = false;
desktop_native_widget_aura_->HandleActivationChanged(false);
}
}
void DesktopWindowTreeHostMus::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
DCHECK_EQ(window, content_window());
DCHECK(!window->GetRootWindow() || this->window() == window->GetRootWindow());
if (!this->window())
return;
// Allow mus clients to mirror widget window properties to their root windows.
MusPropertyMirror* property_mirror = MusClient::Get()->mus_property_mirror();
if (property_mirror) {
property_mirror->MirrorPropertyFromWidgetWindowToRootWindow(
window, this->window(), key);
}
}
void DesktopWindowTreeHostMus::ShowImpl() {
native_widget_delegate_->OnNativeWidgetVisibilityChanging(true);
// Using ui::SHOW_STATE_NORMAL matches that of DesktopWindowTreeHostX11.
ShowWindowWithState(ui::SHOW_STATE_NORMAL);
WindowTreeHostMus::ShowImpl();
native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
}
void DesktopWindowTreeHostMus::HideImpl() {
// When hiding we can't possibly be active any more. Reset the FocusClient,
// which effectively triggers giving up focus (and activation). Mus will
// eventually generate a focus event, but that's async.
if (IsFocusClientInstalledOnFocusSynchronizer()) {
MusClient::Get()
->window_tree_client()
->focus_synchronizer()
->SetActiveFocusClient(nullptr, nullptr);
}
native_widget_delegate_->OnNativeWidgetVisibilityChanging(false);
WindowTreeHostMus::HideImpl();
window()->Hide();
native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
}
void DesktopWindowTreeHostMus::SetBoundsInPixels(
const gfx::Rect& bounds_in_pixels) {
gfx::Rect final_bounds_in_pixels = bounds_in_pixels;
if (GetBoundsInPixels().size() != bounds_in_pixels.size()) {
gfx::Size size = bounds_in_pixels.size();
size.SetToMax(gfx::ConvertSizeToPixel(
GetScaleFactor(), native_widget_delegate_->GetMinimumSize()));
const gfx::Size max_size_in_pixels = gfx::ConvertSizeToPixel(
GetScaleFactor(), native_widget_delegate_->GetMaximumSize());
if (!max_size_in_pixels.IsEmpty())
size.SetToMin(max_size_in_pixels);
final_bounds_in_pixels.set_size(size);
}
const gfx::Rect old_bounds_in_pixels = GetBoundsInPixels();
WindowTreeHostMus::SetBoundsInPixels(final_bounds_in_pixels);
if (old_bounds_in_pixels.size() != final_bounds_in_pixels.size()) {
SendClientAreaToServer();
SendHitTestMaskToServer();
}
}
aura::Window* DesktopWindowTreeHostMus::content_window() {
return desktop_native_widget_aura_->content_window();
}
} // namespace views