blob: 82b85cf6363210ce041460f55ebaf494bbfb68ed [file] [log] [blame]
// Copyright 2017 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 "chromecast/graphics/cast_window_manager_aura.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "chromecast/graphics/cast_focus_client_aura.h"
#include "chromecast/graphics/cast_touch_activity_observer.h"
#include "chromecast/graphics/cast_touch_event_gate.h"
#include "chromecast/graphics/gestures/cast_system_gesture_event_handler.h"
#include "chromecast/graphics/gestures/side_swipe_detector.h"
#include "ui/aura/client/default_capture_client.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/null_window_targeter.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host_platform.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_factory.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/platform_window/platform_window_init_properties.h"
#include "ui/wm/core/default_screen_position_client.h"
#if defined(OS_FUCHSIA)
#include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
#endif
namespace chromecast {
namespace {
gfx::Transform GetPrimaryDisplayRotationTransform() {
// NB: Using gfx::Transform::Rotate() introduces very small errors here
// which are later exacerbated by use of gfx::EnclosingRect() in
// WindowTreeHost::GetTransformedRootWindowBoundsInPixels().
const gfx::Transform rotate_90(0.f, -1.f, 0.f, 0.f, //
1.f, 0.f, 0.f, 0.f, //
0.f, 0.f, 1.f, 0.f, //
0.f, 0.f, 0.f, 1.f);
const gfx::Transform rotate_180 = rotate_90 * rotate_90;
const gfx::Transform rotate_270 = rotate_180 * rotate_90;
gfx::Transform translation;
display::Display display(display::Screen::GetScreen()->GetPrimaryDisplay());
switch (display.rotation()) {
case display::Display::ROTATE_0:
return translation;
case display::Display::ROTATE_90:
translation.Translate(display.bounds().height(), 0);
return translation * rotate_90;
case display::Display::ROTATE_180:
translation.Translate(display.bounds().width(),
display.bounds().height());
return translation * rotate_180;
case display::Display::ROTATE_270:
translation.Translate(0, display.bounds().width());
return translation * rotate_270;
}
}
gfx::Rect GetPrimaryDisplayHostBounds() {
display::Display display(display::Screen::GetScreen()->GetPrimaryDisplay());
gfx::Point display_origin_in_pixel = display.bounds().origin();
gfx::Size display_size_in_pixel = display.GetSizeInPixel();
switch (display.rotation()) {
case display::Display::ROTATE_90:
case display::Display::ROTATE_270:
return gfx::Rect(display_origin_in_pixel,
gfx::Size(display_size_in_pixel.height(),
display_size_in_pixel.width()));
case display::Display::ROTATE_0:
case display::Display::ROTATE_180:
// default:
return gfx::Rect(display_origin_in_pixel, display_size_in_pixel);
}
}
} // namespace
CastWindowTreeHost::CastWindowTreeHost(
bool enable_input,
ui::PlatformWindowInitProperties properties)
: WindowTreeHostPlatform(std::move(properties)),
enable_input_(enable_input) {
if (!enable_input)
window()->SetEventTargeter(std::make_unique<aura::NullWindowTargeter>());
}
CastWindowTreeHost::~CastWindowTreeHost() {}
void CastWindowTreeHost::DispatchEvent(ui::Event* event) {
if (!enable_input_) {
return;
}
WindowTreeHostPlatform::DispatchEvent(event);
}
gfx::Rect CastWindowTreeHost::GetTransformedRootWindowBoundsInPixels(
const gfx::Size& host_size_in_pixels) const {
gfx::RectF new_bounds(WindowTreeHost::GetTransformedRootWindowBoundsInPixels(
host_size_in_pixels));
new_bounds.set_origin(gfx::PointF());
return gfx::ToEnclosingRect(new_bounds);
}
// A layout manager owned by the root window.
class CastLayoutManager : public aura::LayoutManager {
public:
CastLayoutManager();
~CastLayoutManager() override;
private:
// aura::LayoutManager implementation:
void OnWindowResized() override;
void OnWindowAddedToLayout(aura::Window* child) override;
void OnWillRemoveWindowFromLayout(aura::Window* child) override;
void OnWindowRemovedFromLayout(aura::Window* child) override;
void OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) override;
void SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) override;
DISALLOW_COPY_AND_ASSIGN(CastLayoutManager);
};
CastLayoutManager::CastLayoutManager() {}
CastLayoutManager::~CastLayoutManager() {}
void CastLayoutManager::OnWindowResized() {
// Invoked when the root window of the window tree host has been resized.
}
void CastLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
// Invoked when a window is added to the window tree host.
}
void CastLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
// Invoked when the root window of the window tree host will be removed.
}
void CastLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
// Invoked when the root window of the window tree host has been removed.
}
void CastLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) {
aura::Window* parent = child->parent();
if (!visible || !parent->IsRootWindow()) {
return;
}
// We set z-order here, because the window's ID could be set after the window
// is added to the layout, particularly when using views::Widget to create the
// window. The window ID must be set prior to showing the window. Since we
// only process z-order on visibility changes for top-level windows, this
// logic will execute infrequently.
// Determine z-order relative to existing windows.
aura::Window::Windows windows = parent->children();
std::stable_sort(windows.begin(), windows.end(),
[child](aura::Window* lhs, aura::Window* rhs) {
// Promote |child| to the top of the stack of windows with
// the same ID.
if (lhs->id() == rhs->id() && rhs == child)
return true;
return lhs->id() < rhs->id();
});
for (size_t i = 0; i < windows.size(); ++i) {
if (i == 0)
parent->StackChildAtBottom(windows[i]);
else
parent->StackChildAbove(windows[i], windows[i - 1]);
}
}
void CastLayoutManager::SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) {
SetChildBoundsDirect(child, requested_bounds);
}
CastWindowManagerAura::CastWindowManagerAura(bool enable_input)
: enable_input_(enable_input) {}
CastWindowManagerAura::~CastWindowManagerAura() {
TearDown();
}
void CastWindowManagerAura::Setup() {
if (window_tree_host_) {
return;
}
DCHECK(display::Screen::GetScreen());
ui::InitializeInputMethodForTesting();
gfx::Rect host_bounds = GetPrimaryDisplayHostBounds();
ui::PlatformWindowInitProperties properties(host_bounds);
#if defined(OS_FUCHSIA)
// When using Scenic Ozone platform we need to supply a view_token to the
// window. This is not necessary when using the headless ozone platform.
if (ui::OzonePlatform::GetInstance()
->GetPlatformProperties()
.needs_view_token) {
ui::fuchsia::InitializeViewTokenAndPresentView(&properties);
}
#endif
LOG(INFO) << "Starting window manager, bounds: " << host_bounds.ToString();
CHECK(aura::Env::GetInstance());
window_tree_host_ = std::make_unique<CastWindowTreeHost>(
enable_input_, std::move(properties));
window_tree_host_->InitHost();
window_tree_host_->window()->SetLayoutManager(new CastLayoutManager());
window_tree_host_->SetRootTransform(GetPrimaryDisplayRotationTransform());
// Allow seeing through to the hardware video plane:
window_tree_host_->compositor()->SetBackgroundColor(SK_ColorTRANSPARENT);
focus_client_ = std::make_unique<CastFocusClientAura>();
aura::client::SetFocusClient(window_tree_host_->window(),
focus_client_.get());
wm::SetActivationClient(window_tree_host_->window(), focus_client_.get());
aura::client::SetWindowParentingClient(window_tree_host_->window(), this);
capture_client_.reset(
new aura::client::DefaultCaptureClient(window_tree_host_->window()));
screen_position_client_ = std::make_unique<wm::DefaultScreenPositionClient>();
aura::Window* root_window = window_tree_host_->window()->GetRootWindow();
aura::client::SetScreenPositionClient(root_window,
screen_position_client_.get());
window_tree_host_->Show();
// Install the CastTouchEventGate before other event rewriters. It has to be
// the first in the chain.
event_gate_ = std::make_unique<CastTouchEventGate>(root_window);
system_gesture_dispatcher_ = std::make_unique<CastSystemGestureDispatcher>();
system_gesture_event_handler_ =
std::make_unique<CastSystemGestureEventHandler>(
system_gesture_dispatcher_.get(), root_window);
side_swipe_detector_ = std::make_unique<SideSwipeDetector>(
system_gesture_dispatcher_.get(), root_window);
}
CastWindowTreeHost* CastWindowManagerAura::window_tree_host() const {
DCHECK(window_tree_host_);
return window_tree_host_.get();
}
void CastWindowManagerAura::TearDown() {
if (!window_tree_host_) {
return;
}
event_gate_.reset();
side_swipe_detector_.reset();
capture_client_.reset();
aura::client::SetWindowParentingClient(window_tree_host_->window(), nullptr);
wm::SetActivationClient(window_tree_host_->window(), nullptr);
aura::client::SetFocusClient(window_tree_host_->window(), nullptr);
focus_client_.reset();
system_gesture_event_handler_.reset();
window_tree_host_.reset();
}
void CastWindowManagerAura::SetWindowId(gfx::NativeView window,
WindowId window_id) {
window->set_id(window_id);
}
void CastWindowManagerAura::InjectEvent(ui::Event* event) {
if (!window_tree_host_) {
return;
}
window_tree_host_->DispatchEvent(event);
}
gfx::NativeView CastWindowManagerAura::GetRootWindow() {
Setup();
return window_tree_host_->window();
}
aura::Window* CastWindowManagerAura::GetDefaultParent(aura::Window* window,
const gfx::Rect& bounds) {
DCHECK(window_tree_host_);
return window_tree_host_->window();
}
void CastWindowManagerAura::AddWindow(gfx::NativeView child) {
LOG(INFO) << "Adding window: " << child->id() << ": " << child->GetName();
Setup();
DCHECK(child);
aura::Window* parent = window_tree_host_->window();
if (!parent->Contains(child)) {
parent->AddChild(child);
}
}
void CastWindowManagerAura::AddGestureHandler(CastGestureHandler* handler) {
DCHECK(system_gesture_event_handler_);
system_gesture_dispatcher_->AddGestureHandler(handler);
}
void CastWindowManagerAura::CastWindowManagerAura::RemoveGestureHandler(
CastGestureHandler* handler) {
DCHECK(system_gesture_event_handler_);
system_gesture_dispatcher_->RemoveGestureHandler(handler);
}
void CastWindowManagerAura::CastWindowManagerAura::SetColorInversion(
bool enable) {
DCHECK(window_tree_host_);
window_tree_host_->window()->layer()->SetLayerInverted(enable);
}
CastGestureHandler* CastWindowManagerAura::GetGestureHandler() const {
return system_gesture_dispatcher_.get();
}
void CastWindowManagerAura::SetTouchInputDisabled(bool disabled) {
event_gate_->SetEnabled(disabled);
}
void CastWindowManagerAura::AddTouchActivityObserver(
CastTouchActivityObserver* observer) {
event_gate_->AddObserver(observer);
}
void CastWindowManagerAura::RemoveTouchActivityObserver(
CastTouchActivityObserver* observer) {
event_gate_->RemoveObserver(observer);
}
} // namespace chromecast