| // 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); |
| } |
| |
| 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 |