| // Copyright 2014 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/aura/mus/window_tree_client.h" |
| |
| #include <stddef.h> |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/auto_reset.h" |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/callback_helpers.h" |
| #include "base/command_line.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/threading/thread.h" |
| #include "cc/base/switches.h" |
| #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" |
| #include "mojo/public/cpp/bindings/map.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "services/ui/common/accelerator_util.h" |
| #include "services/ui/common/util.h" |
| #include "services/ui/public/cpp/gpu/gpu.h" |
| #include "services/ui/public/cpp/property_type_converters.h" |
| #include "services/ui/public/interfaces/constants.mojom.h" |
| #include "services/ui/public/interfaces/window_manager.mojom.h" |
| #include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h" |
| #include "services/ui/public/interfaces/window_tree_host_factory.mojom.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/client/drag_drop_client.h" |
| #include "ui/aura/client/transient_window_client.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/env_input_state_controller.h" |
| #include "ui/aura/mus/capture_synchronizer.h" |
| #include "ui/aura/mus/drag_drop_controller_mus.h" |
| #include "ui/aura/mus/focus_synchronizer.h" |
| #include "ui/aura/mus/in_flight_change.h" |
| #include "ui/aura/mus/input_method_mus.h" |
| #include "ui/aura/mus/mus_context_factory.h" |
| #include "ui/aura/mus/property_converter.h" |
| #include "ui/aura/mus/property_utils.h" |
| #include "ui/aura/mus/window_manager_delegate.h" |
| #include "ui/aura/mus/window_mus.h" |
| #include "ui/aura/mus/window_port_mus.h" |
| #include "ui/aura/mus/window_tree_client_delegate.h" |
| #include "ui/aura/mus/window_tree_client_observer.h" |
| #include "ui/aura/mus/window_tree_client_test_observer.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/aura/window_delegate.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/aura/window_port_for_shutdown.h" |
| #include "ui/aura/window_tracker.h" |
| #include "ui/base/layout.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/base/ui_base_switches_util.h" |
| #include "ui/base/ui_base_types.h" |
| #include "ui/display/screen.h" |
| #include "ui/display/types/display_constants.h" |
| #include "ui/events/event.h" |
| #include "ui/gfx/geometry/dip_util.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace aura { |
| namespace { |
| |
| struct WindowPortPropertyDataMus : public ui::PropertyData { |
| std::string transport_name; |
| std::unique_ptr<std::vector<uint8_t>> transport_value; |
| }; |
| |
| // Handles acknowledgment of an input event, either immediately when a nested |
| // message loop starts, or upon destruction. |
| class EventAckHandler : public base::RunLoop::NestingObserver { |
| public: |
| explicit EventAckHandler(std::unique_ptr<EventResultCallback> ack_callback) |
| : ack_callback_(std::move(ack_callback)) { |
| DCHECK(ack_callback_); |
| base::RunLoop::AddNestingObserverOnCurrentThread(this); |
| } |
| |
| ~EventAckHandler() override { |
| base::RunLoop::RemoveNestingObserverOnCurrentThread(this); |
| if (ack_callback_) { |
| ack_callback_->Run(handled_ ? ui::mojom::EventResult::HANDLED |
| : ui::mojom::EventResult::UNHANDLED); |
| } |
| } |
| |
| void set_handled(bool handled) { handled_ = handled; } |
| |
| // base::RunLoop::NestingObserver: |
| void OnBeginNestedRunLoop() override { |
| // Acknowledge the event immediately if a nested run loop starts. |
| // Otherwise we appear unresponsive for the life of the nested run loop. |
| if (ack_callback_) { |
| ack_callback_->Run(ui::mojom::EventResult::HANDLED); |
| ack_callback_.reset(); |
| } |
| } |
| |
| private: |
| std::unique_ptr<EventResultCallback> ack_callback_; |
| bool handled_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(EventAckHandler); |
| }; |
| |
| WindowTreeHostMus* GetWindowTreeHostMus(Window* window) { |
| return WindowTreeHostMus::ForWindow(window); |
| } |
| |
| WindowTreeHostMus* GetWindowTreeHostMus(WindowMus* window) { |
| return GetWindowTreeHostMus(window->GetWindow()); |
| } |
| |
| bool IsInternalProperty(const void* key) { |
| return key == client::kModalKey || key == client::kChildModalParentKey; |
| } |
| |
| void SetWindowTypeFromProperties( |
| Window* window, |
| const std::unordered_map<std::string, std::vector<uint8_t>>& properties) { |
| auto type_iter = |
| properties.find(ui::mojom::WindowManager::kWindowType_InitProperty); |
| if (type_iter == properties.end()) |
| return; |
| |
| // TODO: need to validate type! http://crbug.com/654924. |
| ui::mojom::WindowType window_type = static_cast<ui::mojom::WindowType>( |
| mojo::ConvertTo<int32_t>(type_iter->second)); |
| SetWindowType(window, window_type); |
| } |
| |
| // Create and return a MouseEvent or TouchEvent from |event| if |event| is a |
| // PointerEvent, otherwise return the copy of |event|. |
| std::unique_ptr<ui::Event> MapEvent(const ui::Event& event) { |
| if (event.IsPointerEvent()) { |
| const ui::PointerEvent& pointer_event = *event.AsPointerEvent(); |
| // Use a switch statement in case more pointer types are added. |
| switch (pointer_event.pointer_details().pointer_type) { |
| case ui::EventPointerType::POINTER_TYPE_MOUSE: |
| if (event.type() == ui::ET_POINTER_WHEEL_CHANGED) |
| return std::make_unique<ui::MouseWheelEvent>(pointer_event); |
| return std::make_unique<ui::MouseEvent>(pointer_event); |
| case ui::EventPointerType::POINTER_TYPE_TOUCH: |
| case ui::EventPointerType::POINTER_TYPE_PEN: |
| return std::make_unique<ui::TouchEvent>(pointer_event); |
| case ui::EventPointerType::POINTER_TYPE_ERASER: |
| NOTIMPLEMENTED(); |
| break; |
| case ui::EventPointerType::POINTER_TYPE_UNKNOWN: |
| NOTREACHED(); |
| break; |
| } |
| } |
| return ui::Event::Clone(event); |
| } |
| |
| // Use for acks from mus that are expected to always succeed and if they don't |
| // a crash is triggered. |
| void OnAckMustSucceed(const base::Location& from_here, bool success) { |
| CHECK(success) << "Context: " << from_here.ToString(); |
| } |
| |
| ui::Id GetServerIdForWindow(Window* window) { |
| return window ? WindowMus::Get(window)->server_id() : kInvalidServerId; |
| } |
| |
| } // namespace |
| |
| // static |
| std::unique_ptr<WindowTreeClient> WindowTreeClient::CreateForWindowManager( |
| service_manager::Connector* connector, |
| WindowTreeClientDelegate* delegate, |
| WindowManagerDelegate* window_manager_delegate, |
| bool automatically_create_display_roots, |
| bool create_discardable_memory) { |
| std::unique_ptr<WindowTreeClient> wtc( |
| new WindowTreeClient(connector, delegate, window_manager_delegate, |
| nullptr, nullptr, create_discardable_memory)); |
| |
| ui::mojom::WindowManagerWindowTreeFactoryPtr factory; |
| connector->BindInterface(ui::mojom::kServiceName, &factory); |
| ui::mojom::WindowTreePtr window_tree; |
| ui::mojom::WindowTreeClientPtr client; |
| wtc->binding_.Bind(MakeRequest(&client)); |
| factory->CreateWindowTree(MakeRequest(&window_tree), std::move(client), |
| automatically_create_display_roots); |
| wtc->SetWindowTree(std::move(window_tree)); |
| return wtc; |
| } |
| |
| // static |
| std::unique_ptr<WindowTreeClient> WindowTreeClient::CreateForEmbedding( |
| service_manager::Connector* connector, |
| WindowTreeClientDelegate* delegate, |
| ui::mojom::WindowTreeClientRequest request, |
| bool create_discardable_memory) { |
| std::unique_ptr<WindowTreeClient> wtc( |
| new WindowTreeClient(connector, delegate, nullptr, std::move(request), |
| nullptr, create_discardable_memory)); |
| return wtc; |
| } |
| |
| // static |
| std::unique_ptr<WindowTreeClient> WindowTreeClient::CreateForWindowTreeFactory( |
| service_manager::Connector* connector, |
| WindowTreeClientDelegate* delegate, |
| bool create_discardable_memory, |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { |
| std::unique_ptr<WindowTreeClient> wtc( |
| new WindowTreeClient(connector, delegate, nullptr, nullptr, nullptr, |
| create_discardable_memory)); |
| ui::mojom::WindowTreeFactoryPtr factory; |
| connector->BindInterface(ui::mojom::kServiceName, &factory); |
| ui::mojom::WindowTreePtr window_tree; |
| ui::mojom::WindowTreeClientPtr client; |
| wtc->binding_.Bind(MakeRequest(&client)); |
| factory->CreateWindowTree(MakeRequest(&window_tree), std::move(client)); |
| wtc->SetWindowTree(std::move(window_tree)); |
| return wtc; |
| } |
| |
| // static |
| std::unique_ptr<WindowTreeClient> |
| WindowTreeClient::CreateForWindowTreeHostFactory( |
| service_manager::Connector* connector, |
| WindowTreeClientDelegate* delegate, |
| bool create_discardable_memory) { |
| std::unique_ptr<WindowTreeClient> wtc( |
| new WindowTreeClient(connector, delegate, nullptr, nullptr, nullptr, |
| create_discardable_memory)); |
| ui::mojom::WindowTreeHostFactoryPtr factory; |
| connector->BindInterface(ui::mojom::kServiceName, &factory); |
| |
| ui::mojom::WindowTreeHostPtr window_tree_host; |
| ui::mojom::WindowTreeClientPtr client; |
| wtc->binding_.Bind(MakeRequest(&client)); |
| factory->CreateWindowTreeHost(MakeRequest(&window_tree_host), |
| std::move(client)); |
| return wtc; |
| } |
| |
| WindowTreeClient::~WindowTreeClient() { |
| in_destructor_ = true; |
| |
| if (discardable_shared_memory_manager_) |
| base::DiscardableMemoryAllocator::SetInstance(nullptr); |
| |
| for (WindowTreeClientObserver& observer : observers_) |
| observer.OnWillDestroyClient(this); |
| |
| capture_synchronizer_.reset(); |
| |
| // Some tests may not create a TransientWindowClient. |
| if (client::GetTransientWindowClient()) |
| client::GetTransientWindowClient()->RemoveObserver(this); |
| |
| Env* env = Env::GetInstance(); |
| if (compositor_context_factory_ && |
| env->context_factory() == compositor_context_factory_.get()) { |
| env->set_context_factory(initial_context_factory_); |
| } |
| |
| // Allow for windows to exist (and be created) after we are destroyed. This |
| // is necessary because of shutdown ordering (WindowTreeClient is destroyed |
| // before windows). |
| in_shutdown_ = true; |
| |
| // Windows of type WindowMusType::OTHER were implicitly created from the |
| // server and may not have been destroyed. Delete them to ensure we don't |
| // leak. |
| WindowTracker windows_to_destroy; |
| for (auto& pair : windows_) { |
| if (pair.second->window_mus_type() == WindowMusType::OTHER) |
| windows_to_destroy.Add(pair.second->GetWindow()); |
| } |
| while (!windows_to_destroy.windows().empty()) |
| delete windows_to_destroy.Pop(); |
| |
| IdToWindowMap windows; |
| std::swap(windows, windows_); |
| for (auto& pair : windows) |
| WindowPortForShutdown::Install(pair.second->GetWindow()); |
| |
| env->WindowTreeClientDestroyed(this); |
| CHECK(windows_.empty()); |
| } |
| |
| void WindowTreeClient::SetCanFocus(Window* window, bool can_focus) { |
| DCHECK(tree_); |
| DCHECK(window); |
| tree_->SetCanFocus(WindowMus::Get(window)->server_id(), can_focus); |
| } |
| |
| void WindowTreeClient::SetCursor(WindowMus* window, |
| const ui::CursorData& old_cursor, |
| const ui::CursorData& new_cursor) { |
| DCHECK(tree_); |
| |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<InFlightCursorChange>(window, old_cursor)); |
| tree_->SetCursor(change_id, window->server_id(), new_cursor); |
| } |
| |
| void WindowTreeClient::SetWindowTextInputState( |
| WindowMus* window, |
| ui::mojom::TextInputStatePtr state) { |
| DCHECK(tree_); |
| tree_->SetWindowTextInputState(window->server_id(), std::move(state)); |
| } |
| |
| void WindowTreeClient::SetImeVisibility(WindowMus* window, |
| bool visible, |
| ui::mojom::TextInputStatePtr state) { |
| DCHECK(tree_); |
| tree_->SetImeVisibility(window->server_id(), visible, std::move(state)); |
| } |
| |
| void WindowTreeClient::SetHitTestMask( |
| WindowMus* window, |
| const base::Optional<gfx::Rect>& mask_rect) { |
| base::Optional<gfx::Rect> out_rect = base::nullopt; |
| if (mask_rect) { |
| out_rect = gfx::ConvertRectToPixel(window->GetDeviceScaleFactor(), |
| mask_rect.value()); |
| } |
| |
| tree_->SetHitTestMask(window->server_id(), out_rect); |
| } |
| |
| void WindowTreeClient::Embed( |
| Window* window, |
| ui::mojom::WindowTreeClientPtr client, |
| uint32_t flags, |
| const ui::mojom::WindowTree::EmbedCallback& callback) { |
| DCHECK(tree_); |
| // Window::Init() must be called before Embed() (otherwise the server hasn't |
| // been told about the window). |
| DCHECK(window->layer()); |
| if (!window->children().empty()) { |
| // The window server removes all children before embedding. In other words, |
| // it's generally an error to Embed() with existing children. So, fail |
| // early. |
| callback.Run(false); |
| return; |
| } |
| |
| tree_->Embed(WindowMus::Get(window)->server_id(), std::move(client), flags, |
| callback); |
| } |
| |
| void WindowTreeClient::ScheduleEmbed( |
| ui::mojom::WindowTreeClientPtr client, |
| base::OnceCallback<void(const base::UnguessableToken&)> callback) { |
| tree_->ScheduleEmbed(std::move(client), |
| base::AdaptCallbackForRepeating(std::move(callback))); |
| } |
| |
| void WindowTreeClient::AttachCompositorFrameSink( |
| ui::Id window_id, |
| viz::mojom::CompositorFrameSinkRequest compositor_frame_sink, |
| viz::mojom::CompositorFrameSinkClientPtr client) { |
| DCHECK(tree_); |
| tree_->AttachCompositorFrameSink(window_id, std::move(compositor_frame_sink), |
| std::move(client)); |
| } |
| |
| WindowTreeClient::WindowTreeClient( |
| service_manager::Connector* connector, |
| WindowTreeClientDelegate* delegate, |
| WindowManagerDelegate* window_manager_delegate, |
| mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request, |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| bool create_discardable_memory) |
| : connector_(connector), |
| next_window_id_(1), |
| next_change_id_(1), |
| delegate_(delegate), |
| window_manager_delegate_(window_manager_delegate), |
| binding_(this), |
| tree_(nullptr), |
| in_destructor_(false), |
| weak_factory_(this) { |
| DCHECK(delegate_); |
| // Allow for a null request in tests. |
| if (request.is_pending()) |
| binding_.Bind(std::move(request)); |
| // Some tests may not create a TransientWindowClient. |
| if (client::GetTransientWindowClient()) |
| client::GetTransientWindowClient()->AddObserver(this); |
| if (window_manager_delegate) |
| window_manager_delegate->SetWindowManagerClient(this); |
| if (connector) { // |connector| can be null in tests. |
| if (!io_task_runner) { |
| // |io_task_runner| is null in most case. But for the browser process, |
| // the |io_task_runner| is the browser's IO thread. |
| io_thread_ = std::make_unique<base::Thread>("IOThread"); |
| base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0); |
| thread_options.priority = base::ThreadPriority::NORMAL; |
| CHECK(io_thread_->StartWithOptions(thread_options)); |
| io_task_runner = io_thread_->task_runner(); |
| } |
| |
| if (base::FeatureList::IsEnabled(features::kMash)) { |
| gpu_ = |
| ui::Gpu::Create(connector, ui::mojom::kServiceName, io_task_runner); |
| compositor_context_factory_ = |
| std::make_unique<MusContextFactory>(gpu_.get()); |
| initial_context_factory_ = Env::GetInstance()->context_factory(); |
| Env::GetInstance()->set_context_factory( |
| compositor_context_factory_.get()); |
| } |
| |
| // WindowServerTest will create more than one WindowTreeClient. We will not |
| // create the discardable memory manager for those tests. |
| if (create_discardable_memory) { |
| discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr; |
| connector->BindInterface(ui::mojom::kServiceName, &manager_ptr); |
| discardable_shared_memory_manager_ = std::make_unique< |
| discardable_memory::ClientDiscardableSharedMemoryManager>( |
| std::move(manager_ptr), std::move(io_task_runner)); |
| base::DiscardableMemoryAllocator::SetInstance( |
| discardable_shared_memory_manager_.get()); |
| } |
| } |
| } |
| |
| void WindowTreeClient::RegisterWindowMus(WindowMus* window) { |
| DCHECK(windows_.find(window->server_id()) == windows_.end()); |
| windows_[window->server_id()] = window; |
| if (window->GetWindow()) { |
| auto* port = WindowPortMus::Get(window->GetWindow()); |
| window->GetWindow()->set_frame_sink_id( |
| port->GenerateFrameSinkIdFromServerId()); |
| } |
| } |
| |
| WindowMus* WindowTreeClient::GetWindowByServerId(ui::Id id) { |
| IdToWindowMap::const_iterator it = windows_.find(id); |
| return it != windows_.end() ? it->second : nullptr; |
| } |
| |
| bool WindowTreeClient::IsWindowKnown(aura::Window* window) { |
| WindowMus* window_mus = WindowMus::Get(window); |
| return windows_.count(window_mus->server_id()) > 0; |
| } |
| |
| void WindowTreeClient::ConvertPointerEventLocationToDip( |
| int64_t display_id, |
| WindowMus* window, |
| ui::LocatedEvent* event) const { |
| // PointerEvents shouldn't have the target set. |
| DCHECK(!event->target()); |
| if (window_manager_delegate_) { |
| ConvertPointerEventLocationToDipInWindowManager(display_id, window, event); |
| return; |
| } |
| display::Screen* screen = display::Screen::GetScreen(); |
| display::Display display; |
| // TODO(sky): this needs to take into account the ui display scale. |
| // http://crbug.com/758399. |
| if (!screen->GetDisplayWithDisplayId(display_id, &display) || |
| display.device_scale_factor() == 1.f) { |
| return; |
| } |
| const gfx::Point root_location = gfx::ConvertPointToDIP( |
| display.device_scale_factor(), event->root_location()); |
| event->set_root_location(root_location); |
| if (window) { |
| const gfx::Point host_location = gfx::ConvertPointToDIP( |
| display.device_scale_factor(), event->location()); |
| event->set_location(host_location); |
| } else { |
| // When there is no window force the root and location to be the same. They |
| // may differ it |window| was valid at the time of the event, but was since |
| // deleted. |
| event->set_location(root_location); |
| } |
| } |
| |
| void WindowTreeClient::ConvertPointerEventLocationToDipInWindowManager( |
| int64_t display_id, |
| WindowMus* window, |
| ui::LocatedEvent* event) const { |
| const WindowTreeHostMus* window_tree_host = |
| GetWindowTreeHostForDisplayId(display_id); |
| if (!window_tree_host) |
| return; |
| |
| ui::Event::DispatcherApi dispatcher_api(event); |
| if (window) { |
| dispatcher_api.set_target(window->GetWindow()); |
| } else { |
| // UpdateForRootTransform() in the case of no target uses |location_|. |
| // |location_| may be relative to a window that wasn't found. To ensure we |
| // convert from the root, reset |location_| to |root_location_|. |
| event->set_location_f(event->root_location_f()); |
| } |
| event->UpdateForRootTransform( |
| window_tree_host->GetInverseRootTransform(), |
| window_tree_host->GetInverseRootTransformForLocalEventCoordinates()); |
| dispatcher_api.set_target(nullptr); |
| } |
| |
| InFlightChange* WindowTreeClient::GetOldestInFlightChangeMatching( |
| const InFlightChange& change) { |
| for (const auto& pair : in_flight_map_) { |
| if (pair.second->window() == change.window() && |
| pair.second->change_type() == change.change_type() && |
| pair.second->Matches(change)) { |
| return pair.second.get(); |
| } |
| } |
| return nullptr; |
| } |
| |
| uint32_t WindowTreeClient::ScheduleInFlightChange( |
| std::unique_ptr<InFlightChange> change) { |
| DCHECK(!change->window() || |
| windows_.count(change->window()->server_id()) > 0); |
| ChangeType t = change->change_type(); |
| const uint32_t change_id = next_change_id_++; |
| in_flight_map_[change_id] = std::move(change); |
| for (auto& observer : test_observers_) |
| observer.OnChangeStarted(change_id, t); |
| return change_id; |
| } |
| |
| bool WindowTreeClient::ApplyServerChangeToExistingInFlightChange( |
| const InFlightChange& change) { |
| InFlightChange* existing_change = GetOldestInFlightChangeMatching(change); |
| if (!existing_change) |
| return false; |
| |
| existing_change->SetRevertValueFrom(change); |
| return true; |
| } |
| |
| void WindowTreeClient::BuildWindowTree( |
| const std::vector<ui::mojom::WindowDataPtr>& windows) { |
| for (const auto& window_data : windows) |
| CreateOrUpdateWindowFromWindowData(*window_data); |
| } |
| |
| void WindowTreeClient::CreateOrUpdateWindowFromWindowData( |
| const ui::mojom::WindowData& window_data) { |
| WindowMus* parent = window_data.parent_id == kInvalidServerId |
| ? nullptr |
| : GetWindowByServerId(window_data.parent_id); |
| WindowMus* window = GetWindowByServerId(window_data.window_id); |
| if (!window) |
| window = NewWindowFromWindowData(parent, window_data); |
| else if (parent) |
| parent->AddChildFromServer(window); |
| |
| if (window_data.transient_parent_id == kInvalidServerId) |
| return; |
| |
| // Some tests may not create a TransientWindowClient. |
| client::TransientWindowClient* transient_window_client = |
| client::GetTransientWindowClient(); |
| if (!transient_window_client) |
| return; |
| |
| // Adjust the transient parent if necessary. |
| Window* existing_transient_parent = |
| transient_window_client->GetTransientParent(window->GetWindow()); |
| WindowMus* new_transient_parent = |
| GetWindowByServerId(window_data.transient_parent_id); |
| if (!new_transient_parent && existing_transient_parent) { |
| WindowMus::Get(existing_transient_parent) |
| ->RemoveTransientChildFromServer(window); |
| } else if (new_transient_parent && |
| new_transient_parent->GetWindow() != existing_transient_parent) { |
| if (existing_transient_parent) { |
| WindowMus::Get(existing_transient_parent) |
| ->RemoveTransientChildFromServer(window); |
| } |
| new_transient_parent->AddTransientChildFromServer(window); |
| } |
| } |
| |
| std::unique_ptr<WindowPortMus> WindowTreeClient::CreateWindowPortMus( |
| const ui::mojom::WindowData& window_data, |
| WindowMusType window_mus_type) { |
| std::unique_ptr<WindowPortMus> window_port_mus( |
| std::make_unique<WindowPortMus>(this, window_mus_type)); |
| window_port_mus->set_server_id(window_data.window_id); |
| RegisterWindowMus(window_port_mus.get()); |
| return window_port_mus; |
| } |
| |
| void WindowTreeClient::SetLocalPropertiesFromServerProperties( |
| WindowMus* window, |
| const ui::mojom::WindowData& window_data) { |
| for (auto& pair : window_data.properties) |
| window->SetPropertyFromServer(pair.first, &pair.second); |
| } |
| |
| const WindowTreeHostMus* WindowTreeClient::GetWindowTreeHostForDisplayId( |
| int64_t display_id) const { |
| if (!window_manager_delegate_) |
| return nullptr; |
| |
| for (WindowMus* window : roots_) { |
| WindowTreeHostMus* window_tree_host = |
| static_cast<WindowTreeHostMus*>(window->GetWindow()->GetHost()); |
| if (window_tree_host->display_id() == display_id) |
| return window_tree_host; |
| } |
| return nullptr; |
| } |
| |
| std::unique_ptr<WindowTreeHostMus> WindowTreeClient::CreateWindowTreeHost( |
| WindowMusType window_mus_type, |
| const ui::mojom::WindowData& window_data, |
| int64_t display_id, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| std::unique_ptr<WindowPortMus> window_port = |
| CreateWindowPortMus(window_data, window_mus_type); |
| roots_.insert(window_port.get()); |
| WindowTreeHostMusInitParams init_params; |
| init_params.window_port = std::move(window_port); |
| init_params.window_tree_client = this; |
| init_params.display_id = display_id; |
| if (window_manager_delegate_ && |
| (window_mus_type == WindowMusType::EMBED || |
| window_mus_type == WindowMusType::DISPLAY_AUTOMATICALLY_CREATED)) { |
| init_params.uses_real_accelerated_widget = |
| !::base::FeatureList::IsEnabled(features::kMash); |
| } |
| std::unique_ptr<WindowTreeHostMus> window_tree_host = |
| std::make_unique<WindowTreeHostMus>(std::move(init_params)); |
| window_tree_host->InitHost(); |
| SetLocalPropertiesFromServerProperties( |
| WindowMus::Get(window_tree_host->window()), window_data); |
| if (window_data.visible) { |
| SetWindowVisibleFromServer(WindowMus::Get(window_tree_host->window()), |
| true); |
| } |
| WindowMus* window = WindowMus::Get(window_tree_host->window()); |
| |
| SetWindowBoundsFromServer(window, window_data.bounds, local_surface_id); |
| return window_tree_host; |
| } |
| |
| WindowMus* WindowTreeClient::NewWindowFromWindowData( |
| WindowMus* parent, |
| const ui::mojom::WindowData& window_data) { |
| // This function is only called for windows coming from other clients. |
| std::unique_ptr<WindowPortMus> window_port_mus( |
| CreateWindowPortMus(window_data, WindowMusType::OTHER)); |
| WindowPortMus* window_port_mus_ptr = window_port_mus.get(); |
| // Children of windows created from another client need to be restacked by |
| // the client that created them. To do otherwise means two clients will |
| // attempt to restack the same windows, leading to raciness (and most likely |
| // be rejected by the server anyway). |
| window_port_mus_ptr->should_restack_transient_children_ = false; |
| Window* window = new Window(nullptr, std::move(window_port_mus)); |
| WindowMus* window_mus = window_port_mus_ptr; |
| SetWindowTypeFromProperties(window, window_data.properties); |
| window->Init(ui::LAYER_NOT_DRAWN); |
| SetLocalPropertiesFromServerProperties(window_mus, window_data); |
| window_mus->SetBoundsFromServer( |
| gfx::ConvertRectToDIP(window_mus->GetDeviceScaleFactor(), |
| window_data.bounds), |
| base::nullopt); |
| if (parent) |
| parent->AddChildFromServer(window_port_mus_ptr); |
| if (window_data.visible) |
| window_mus->SetVisibleFromServer(true); |
| return window_port_mus_ptr; |
| } |
| |
| void WindowTreeClient::SetWindowTree(ui::mojom::WindowTreePtr window_tree_ptr) { |
| tree_ptr_ = std::move(window_tree_ptr); |
| |
| WindowTreeConnectionEstablished(tree_ptr_.get()); |
| tree_ptr_->GetCursorLocationMemory( |
| base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory, |
| weak_factory_.GetWeakPtr())); |
| |
| tree_ptr_.set_connection_error_handler(base::Bind( |
| &WindowTreeClient::OnConnectionLost, weak_factory_.GetWeakPtr())); |
| |
| if (window_manager_delegate_) { |
| tree_ptr_->GetWindowManagerClient( |
| MakeRequest(&window_manager_internal_client_)); |
| window_manager_client_ = window_manager_internal_client_.get(); |
| } |
| } |
| |
| void WindowTreeClient::WindowTreeConnectionEstablished( |
| ui::mojom::WindowTree* window_tree) { |
| tree_ = window_tree; |
| |
| drag_drop_controller_ = std::make_unique<DragDropControllerMus>(this, tree_); |
| capture_synchronizer_ = std::make_unique<CaptureSynchronizer>(this, tree_); |
| focus_synchronizer_ = std::make_unique<FocusSynchronizer>(this, tree_); |
| } |
| |
| void WindowTreeClient::OnConnectionLost() { |
| delegate_->OnLostConnection(this); |
| } |
| |
| bool WindowTreeClient::HandleInternalPropertyChanged(WindowMus* window, |
| const void* key, |
| int64_t old_value) { |
| if (key == client::kModalKey) { |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<InFlightSetModalTypeChange>( |
| window, static_cast<ui::ModalType>(old_value))); |
| tree_->SetModalType(change_id, window->server_id(), |
| window->GetWindow()->GetProperty(client::kModalKey)); |
| return true; |
| } |
| if (key == client::kChildModalParentKey) { |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<CrashInFlightChange>( |
| window, ChangeType::CHILD_MODAL_PARENT)); |
| Window* child_modal_parent = |
| window->GetWindow()->GetProperty(client::kChildModalParentKey); |
| tree_->SetChildModalParent( |
| change_id, window->server_id(), |
| child_modal_parent ? WindowMus::Get(child_modal_parent)->server_id() |
| : kInvalidServerId); |
| return true; |
| } |
| return false; |
| } |
| |
| void WindowTreeClient::OnEmbedImpl( |
| ui::mojom::WindowTree* window_tree, |
| ui::mojom::WindowDataPtr root_data, |
| int64_t display_id, |
| ui::Id focused_window_id, |
| bool drawn, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| WindowTreeConnectionEstablished(window_tree); |
| |
| DCHECK(roots_.empty()); |
| std::unique_ptr<WindowTreeHostMus> window_tree_host = CreateWindowTreeHost( |
| WindowMusType::EMBED, *root_data, display_id, local_surface_id); |
| |
| focus_synchronizer_->SetFocusFromServer( |
| GetWindowByServerId(focused_window_id)); |
| |
| delegate_->OnEmbed(std::move(window_tree_host)); |
| } |
| |
| WindowTreeHostMus* WindowTreeClient::WmNewDisplayAddedImpl( |
| const display::Display& display, |
| ui::mojom::WindowDataPtr root_data, |
| bool parent_drawn, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| DCHECK(window_manager_delegate_); |
| |
| got_initial_displays_ = true; |
| |
| window_manager_delegate_->OnWmWillCreateDisplay(display); |
| |
| std::unique_ptr<WindowTreeHostMus> window_tree_host = |
| CreateWindowTreeHost(WindowMusType::DISPLAY_AUTOMATICALLY_CREATED, |
| *root_data, display.id(), local_surface_id); |
| |
| WindowTreeHostMus* window_tree_host_ptr = window_tree_host.get(); |
| window_manager_delegate_->OnWmNewDisplay(std::move(window_tree_host), |
| display); |
| return window_tree_host_ptr; |
| } |
| |
| std::unique_ptr<EventResultCallback> |
| WindowTreeClient::CreateEventResultCallback(int32_t event_id) { |
| return std::make_unique<EventResultCallback>( |
| base::Bind(&ui::mojom::WindowTree::OnWindowInputEventAck, |
| base::Unretained(tree_), event_id)); |
| } |
| |
| void WindowTreeClient::OnReceivedCursorLocationMemory( |
| mojo::ScopedSharedBufferHandle handle) { |
| cursor_location_mapping_ = handle->Map(sizeof(base::subtle::Atomic32)); |
| DCHECK(cursor_location_mapping_); |
| } |
| |
| void WindowTreeClient::SetWindowBoundsFromServer( |
| WindowMus* window, |
| const gfx::Rect& revert_bounds_in_pixels, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| if (IsRoot(window)) { |
| // WindowTreeHost expects bounds to be in pixels. |
| GetWindowTreeHostMus(window)->SetBoundsFromServer(revert_bounds_in_pixels); |
| if (local_surface_id && local_surface_id->is_valid()) { |
| ui::Compositor* compositor = window->GetWindow()->GetHost()->compositor(); |
| compositor->SetLocalSurfaceId(*local_surface_id); |
| } |
| return; |
| } |
| |
| window->SetBoundsFromServer( |
| gfx::ConvertRectToDIP(window->GetDeviceScaleFactor(), |
| revert_bounds_in_pixels), |
| local_surface_id); |
| } |
| |
| void WindowTreeClient::SetWindowTransformFromServer( |
| WindowMus* window, |
| const gfx::Transform& transform) { |
| window->SetTransformFromServer(transform); |
| } |
| |
| void WindowTreeClient::SetWindowVisibleFromServer(WindowMus* window, |
| bool visible) { |
| if (!IsRoot(window)) { |
| window->SetVisibleFromServer(visible); |
| return; |
| } |
| |
| std::unique_ptr<WindowMusChangeData> data = |
| window->PrepareForServerVisibilityChange(visible); |
| WindowTreeHostMus* window_tree_host = GetWindowTreeHostMus(window); |
| if (visible) |
| window_tree_host->Show(); |
| else |
| window_tree_host->Hide(); |
| } |
| |
| void WindowTreeClient::ScheduleInFlightBoundsChange( |
| WindowMus* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<InFlightBoundsChange>( |
| this, window, old_bounds, window->GetLocalSurfaceId())); |
| base::Optional<viz::LocalSurfaceId> local_surface_id; |
| if (window->window_mus_type() == WindowMusType::TOP_LEVEL_IN_WM || |
| window->window_mus_type() == WindowMusType::EMBED_IN_OWNER || |
| window->window_mus_type() == WindowMusType::DISPLAY_MANUALLY_CREATED || |
| window->HasLocalLayerTreeFrameSink()) { |
| local_surface_id = window->GetOrAllocateLocalSurfaceId(new_bounds.size()); |
| // |window_tree_host| may be null if this is called during creation of |
| // the window associated with the WindowTreeHostMus. |
| WindowTreeHost* window_tree_host = window->GetWindow()->GetHost(); |
| if (window_tree_host) |
| window_tree_host->compositor()->OnChildResizing(); |
| } |
| tree_->SetWindowBounds(change_id, window->server_id(), new_bounds, |
| local_surface_id); |
| } |
| |
| void WindowTreeClient::OnWindowMusCreated(WindowMus* window) { |
| if (window->server_id() != kInvalidServerId) |
| return; |
| |
| window->set_server_id(next_window_id_++); |
| RegisterWindowMus(window); |
| |
| DCHECK(window_manager_delegate_ || !IsRoot(window)); |
| |
| std::unordered_map<std::string, std::vector<uint8_t>> transport_properties; |
| std::set<const void*> property_keys = |
| window->GetWindow()->GetAllPropertyKeys(); |
| PropertyConverter* property_converter = delegate_->GetPropertyConverter(); |
| for (const void* key : property_keys) { |
| std::string transport_name; |
| std::unique_ptr<std::vector<uint8_t>> transport_value; |
| if (!property_converter->ConvertPropertyForTransport( |
| window->GetWindow(), key, &transport_name, &transport_value)) { |
| continue; |
| } |
| transport_properties[transport_name] = |
| transport_value ? std::move(*transport_value) : std::vector<uint8_t>(); |
| } |
| |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(window, ChangeType::NEW_WINDOW)); |
| tree_->NewWindow(change_id, window->server_id(), |
| std::move(transport_properties)); |
| if (window->GetWindow()->event_targeting_policy() != |
| ui::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS) { |
| SetEventTargetingPolicy(window, |
| window->GetWindow()->event_targeting_policy()); |
| } |
| if (window->window_mus_type() == WindowMusType::DISPLAY_MANUALLY_CREATED) { |
| WindowTreeHostMus* window_tree_host = GetWindowTreeHostMus(window); |
| std::unique_ptr<DisplayInitParams> display_init_params = |
| window_tree_host->ReleaseDisplayInitParams(); |
| DCHECK(display_init_params); |
| display::Display display; |
| if (display_init_params->display) { |
| display = *display_init_params->display; |
| } else { |
| const bool has_display = |
| display::Screen::GetScreen()->GetDisplayWithDisplayId( |
| window_tree_host->display_id(), &display); |
| DCHECK(has_display); |
| } |
| // As |window| is a root, changes to its bounds are ignored (it's assumed |
| // bounds changes are routed through OnWindowTreeHostBoundsWillChange()). |
| // But the display is created with an initial bounds, and we need to push |
| // that to the server. |
| ScheduleInFlightBoundsChange( |
| window, gfx::Rect(), |
| gfx::Rect( |
| display_init_params->viewport_metrics.bounds_in_pixels.size())); |
| |
| if (window_manager_client_) { |
| window_manager_client_->SetDisplayRoot( |
| display, display_init_params->viewport_metrics.Clone(), |
| display_init_params->is_primary_display, window->server_id(), |
| base::FeatureList::IsEnabled(features::kMash) |
| ? display_init_params->mirrors |
| : std::vector<display::Display>(), |
| base::Bind(&OnAckMustSucceed, FROM_HERE)); |
| } |
| } |
| } |
| |
| void WindowTreeClient::OnWindowMusDestroyed(WindowMus* window, Origin origin) { |
| if (focus_synchronizer_->focused_window() == window) |
| focus_synchronizer_->OnFocusedWindowDestroyed(); |
| |
| // If we're |in_shutdown_| there is no point in telling the server about the |
| // deletion. The connection to the server is about to be dropped and the |
| // server will take appropriate action. |
| // TODO: decide how to deal with windows not owned by this client. |
| if (!in_shutdown_ && origin == Origin::CLIENT && |
| (WasCreatedByThisClient(window) || IsRoot(window))) { |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<CrashInFlightChange>( |
| window, ChangeType::DELETE_WINDOW)); |
| tree_->DeleteWindow(change_id, window->server_id()); |
| } |
| |
| windows_.erase(window->server_id()); |
| |
| for (auto& entry : embedded_windows_) { |
| auto it = entry.second.find(window->GetWindow()); |
| if (it != entry.second.end()) { |
| entry.second.erase(it); |
| break; |
| } |
| } |
| |
| // Remove any InFlightChanges associated with the window. |
| std::set<uint32_t> in_flight_change_ids_to_remove; |
| for (const auto& pair : in_flight_map_) { |
| if (pair.second->window() == window) |
| in_flight_change_ids_to_remove.insert(pair.first); |
| } |
| for (auto change_id : in_flight_change_ids_to_remove) |
| in_flight_map_.erase(change_id); |
| |
| roots_.erase(window); |
| } |
| |
| void WindowTreeClient::OnWindowMusBoundsChanged(WindowMus* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| // Changes to bounds of root windows are routed through |
| // OnWindowTreeHostBoundsWillChange(). Any bounds that happen here are a side |
| // effect of those and can be ignored. |
| if (IsRoot(window)) { |
| // NOTE: this has to happen to here as during the call to |
| // OnWindowTreeHostBoundsWillChange() the compositor hasn't been updated |
| // yet. |
| if (window->window_mus_type() == WindowMusType::DISPLAY_MANUALLY_CREATED) { |
| WindowTreeHost* window_tree_host = window->GetWindow()->GetHost(); |
| // |window_tree_host| may be null if this is called during creation of |
| // the window associated with the WindowTreeHostMus. |
| if (window_tree_host) { |
| viz::LocalSurfaceId local_surface_id = |
| window->GetOrAllocateLocalSurfaceId( |
| window_tree_host->GetBoundsInPixels().size()); |
| DCHECK(local_surface_id.is_valid()); |
| window_tree_host->compositor()->SetLocalSurfaceId(local_surface_id); |
| } |
| } |
| return; |
| } |
| |
| float device_scale_factor = window->GetDeviceScaleFactor(); |
| ScheduleInFlightBoundsChange( |
| window, gfx::ConvertRectToPixel(device_scale_factor, old_bounds), |
| gfx::ConvertRectToPixel(device_scale_factor, new_bounds)); |
| } |
| |
| void WindowTreeClient::OnWindowMusTransformChanged( |
| WindowMus* window, |
| const gfx::Transform& old_transform, |
| const gfx::Transform& new_transform) { |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<InFlightTransformChange>(this, window, old_transform)); |
| tree_->SetWindowTransform(change_id, window->server_id(), new_transform); |
| } |
| |
| void WindowTreeClient::OnWindowMusAddChild(WindowMus* parent, |
| WindowMus* child) { |
| // TODO: add checks to ensure this can work. |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(parent, ChangeType::ADD_CHILD)); |
| tree_->AddWindow(change_id, parent->server_id(), child->server_id()); |
| } |
| |
| void WindowTreeClient::OnWindowMusRemoveChild(WindowMus* parent, |
| WindowMus* child) { |
| // TODO: add checks to ensure this can work. |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(parent, ChangeType::REMOVE_CHILD)); |
| tree_->RemoveWindowFromParent(change_id, child->server_id()); |
| } |
| |
| void WindowTreeClient::OnWindowMusMoveChild(WindowMus* parent, |
| size_t current_index, |
| size_t dest_index) { |
| DCHECK_NE(current_index, dest_index); |
| // TODO: add checks to ensure this can work, e.g. we own the parent. |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(parent, ChangeType::REORDER)); |
| WindowMus* window = |
| WindowMus::Get(parent->GetWindow()->children()[current_index]); |
| WindowMus* relative_window = nullptr; |
| ui::mojom::OrderDirection direction; |
| if (dest_index < current_index) { |
| relative_window = |
| WindowMus::Get(parent->GetWindow()->children()[dest_index]); |
| direction = ui::mojom::OrderDirection::BELOW; |
| } else { |
| relative_window = |
| WindowMus::Get(parent->GetWindow()->children()[dest_index]); |
| direction = ui::mojom::OrderDirection::ABOVE; |
| } |
| tree_->ReorderWindow(change_id, window->server_id(), |
| relative_window->server_id(), direction); |
| } |
| |
| void WindowTreeClient::OnWindowMusSetVisible(WindowMus* window, bool visible) { |
| // TODO: add checks to ensure this can work. |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<InFlightVisibleChange>(this, window, !visible)); |
| tree_->SetWindowVisibility(change_id, window->server_id(), visible); |
| } |
| |
| std::unique_ptr<ui::PropertyData> |
| WindowTreeClient::OnWindowMusWillChangeProperty(WindowMus* window, |
| const void* key) { |
| if (IsInternalProperty(key)) |
| return nullptr; |
| |
| std::unique_ptr<WindowPortPropertyDataMus> data( |
| std::make_unique<WindowPortPropertyDataMus>()); |
| if (!delegate_->GetPropertyConverter()->ConvertPropertyForTransport( |
| window->GetWindow(), key, &data->transport_name, |
| &data->transport_value)) { |
| return nullptr; |
| } |
| return std::move(data); |
| } |
| |
| void WindowTreeClient::OnWindowMusPropertyChanged( |
| WindowMus* window, |
| const void* key, |
| int64_t old_value, |
| std::unique_ptr<ui::PropertyData> data) { |
| if (HandleInternalPropertyChanged(window, key, old_value) || !data) |
| return; |
| |
| WindowPortPropertyDataMus* data_mus = |
| static_cast<WindowPortPropertyDataMus*>(data.get()); |
| |
| std::string transport_name; |
| std::unique_ptr<std::vector<uint8_t>> transport_value; |
| if (!delegate_->GetPropertyConverter()->ConvertPropertyForTransport( |
| window->GetWindow(), key, &transport_name, &transport_value)) { |
| return; |
| } |
| DCHECK_EQ(transport_name, data_mus->transport_name); |
| |
| base::Optional<std::vector<uint8_t>> transport_value_mojo; |
| if (transport_value) |
| transport_value_mojo.emplace(std::move(*transport_value)); |
| |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<InFlightPropertyChange>( |
| window, transport_name, std::move(data_mus->transport_value))); |
| tree_->SetWindowProperty(change_id, window->server_id(), transport_name, |
| transport_value_mojo); |
| } |
| |
| void WindowTreeClient::OnWindowMusDeviceScaleFactorChanged( |
| WindowMus* window, |
| float old_scale_factor, |
| float new_scale_factor) { |
| // Root changes are handled else where. |
| if (IsRoot(window)) |
| return; |
| |
| const gfx::Rect old_bounds = |
| gfx::ConvertRectToPixel(old_scale_factor, window->GetWindow()->bounds()); |
| const gfx::Rect new_bounds = |
| gfx::ConvertRectToPixel(new_scale_factor, window->GetWindow()->bounds()); |
| ScheduleInFlightBoundsChange(window, old_bounds, new_bounds); |
| } |
| |
| void WindowTreeClient::OnWmMoveLoopCompleted(uint32_t change_id, |
| bool completed) { |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(change_id, completed); |
| |
| if (change_id == current_wm_move_loop_change_) { |
| current_wm_move_loop_change_ = 0; |
| current_wm_move_loop_window_id_ = 0; |
| } |
| } |
| |
| std::set<Window*> WindowTreeClient::GetRoots() { |
| std::set<Window*> roots; |
| for (WindowMus* window : roots_) |
| roots.insert(window->GetWindow()); |
| return roots; |
| } |
| |
| bool WindowTreeClient::WasCreatedByThisClient(const WindowMus* window) const { |
| // Windows created via CreateTopLevelWindow() are not owned by us, but don't |
| // have high-word set. const_cast is required by set. |
| return !ui::ClientIdFromTransportId(window->server_id()) && |
| roots_.count(const_cast<WindowMus*>(window)) == 0; |
| } |
| |
| gfx::Point WindowTreeClient::GetCursorScreenPoint() { |
| // We raced initialization. Return (0, 0). |
| if (!cursor_location_memory()) |
| return gfx::Point(); |
| |
| base::subtle::Atomic32 location = |
| base::subtle::NoBarrier_Load(cursor_location_memory()); |
| return gfx::Point(static_cast<int16_t>(location >> 16), |
| static_cast<int16_t>(location & 0xFFFF)); |
| } |
| |
| void WindowTreeClient::StartPointerWatcher(bool want_moves) { |
| if (has_pointer_watcher_) |
| StopPointerWatcher(); |
| has_pointer_watcher_ = true; |
| tree_->StartPointerWatcher(want_moves); |
| } |
| |
| void WindowTreeClient::StopPointerWatcher() { |
| DCHECK(has_pointer_watcher_); |
| tree_->StopPointerWatcher(); |
| has_pointer_watcher_ = false; |
| } |
| |
| void WindowTreeClient::AddObserver(WindowTreeClientObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void WindowTreeClient::RemoveObserver(WindowTreeClientObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void WindowTreeClient::AddTestObserver(WindowTreeClientTestObserver* observer) { |
| test_observers_.AddObserver(observer); |
| } |
| |
| void WindowTreeClient::RemoveTestObserver( |
| WindowTreeClientTestObserver* observer) { |
| test_observers_.RemoveObserver(observer); |
| } |
| |
| void WindowTreeClient::SetCanAcceptDrops(WindowMus* window, |
| bool can_accept_drops) { |
| DCHECK(tree_); |
| tree_->SetCanAcceptDrops(window->server_id(), can_accept_drops); |
| } |
| |
| void WindowTreeClient::SetEventTargetingPolicy( |
| WindowMus* window, |
| ui::mojom::EventTargetingPolicy policy) { |
| DCHECK(tree_); |
| tree_->SetEventTargetingPolicy(window->server_id(), policy); |
| } |
| |
| void WindowTreeClient::OnEmbed( |
| ui::mojom::WindowDataPtr root_data, |
| ui::mojom::WindowTreePtr tree, |
| int64_t display_id, |
| ui::Id focused_window_id, |
| bool drawn, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| DCHECK(!tree_ptr_); |
| tree_ptr_ = std::move(tree); |
| |
| is_from_embed_ = true; |
| got_initial_displays_ = true; |
| |
| if (window_manager_delegate_) { |
| tree_ptr_->GetWindowManagerClient( |
| MakeRequest(&window_manager_internal_client_)); |
| window_manager_client_ = window_manager_internal_client_.get(); |
| } |
| OnEmbedImpl(tree_ptr_.get(), std::move(root_data), display_id, |
| focused_window_id, drawn, local_surface_id); |
| } |
| |
| void WindowTreeClient::OnEmbeddedAppDisconnected(ui::Id window_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) |
| window->NotifyEmbeddedAppDisconnected(); |
| } |
| |
| void WindowTreeClient::OnUnembed(ui::Id window_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| delegate_->OnUnembed(window->GetWindow()); |
| delete window; |
| } |
| |
| void WindowTreeClient::OnCaptureChanged(ui::Id new_capture_window_id, |
| ui::Id old_capture_window_id) { |
| WindowMus* new_capture_window = GetWindowByServerId(new_capture_window_id); |
| WindowMus* lost_capture_window = GetWindowByServerId(old_capture_window_id); |
| if (!new_capture_window && !lost_capture_window) |
| return; |
| |
| InFlightCaptureChange change(this, capture_synchronizer_.get(), |
| new_capture_window); |
| if (ApplyServerChangeToExistingInFlightChange(change)) |
| return; |
| |
| capture_synchronizer_->SetCaptureFromServer(new_capture_window); |
| } |
| |
| void WindowTreeClient::OnFrameSinkIdAllocated( |
| ui::Id window_id, |
| const viz::FrameSinkId& frame_sink_id) { |
| if (!base::FeatureList::IsEnabled(features::kMash)) |
| return; |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| window->SetFrameSinkIdFromServer(frame_sink_id); |
| } |
| |
| void WindowTreeClient::OnTopLevelCreated( |
| uint32_t change_id, |
| ui::mojom::WindowDataPtr data, |
| int64_t display_id, |
| bool drawn, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| // The server ack'd the top level window we created and supplied the state |
| // of the window at the time the server created it. For properties we do not |
| // have changes in flight for we can update them immediately. For properties |
| // with changes in flight we set the revert value from the server. |
| |
| if (!in_flight_map_.count(change_id)) { |
| // The window may have been destroyed locally before the server could finish |
| // creating the window, and before the server received the notification that |
| // the window has been destroyed. |
| return; |
| } |
| std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id])); |
| in_flight_map_.erase(change_id); |
| |
| WindowMus* window = change->window(); |
| WindowTreeHostMus* window_tree_host = GetWindowTreeHostMus(window); |
| |
| // Drawn state and display-id always come from the server (they can't be |
| // modified locally). |
| window_tree_host->set_display_id(display_id); |
| |
| // The default visibilty is false, we only need update visibility if it |
| // differs from that. |
| if (data->visible) { |
| InFlightVisibleChange visible_change(this, window, data->visible); |
| InFlightChange* current_change = |
| GetOldestInFlightChangeMatching(visible_change); |
| if (current_change) |
| current_change->SetRevertValueFrom(visible_change); |
| else |
| SetWindowVisibleFromServer(window, true); |
| } |
| |
| const gfx::Rect bounds(data->bounds); |
| { |
| InFlightBoundsChange bounds_change(this, window, bounds, local_surface_id); |
| InFlightChange* current_change = |
| GetOldestInFlightChangeMatching(bounds_change); |
| if (current_change) { |
| current_change->SetRevertValueFrom(bounds_change); |
| } else if (gfx::ConvertRectToPixel(window->GetDeviceScaleFactor(), |
| window->GetWindow()->bounds()) != |
| bounds) { |
| SetWindowBoundsFromServer(window, bounds, local_surface_id); |
| } |
| } |
| |
| // There is currently no API to bulk set properties, so we iterate over each |
| // property individually. |
| for (const auto& pair : data->properties) { |
| std::unique_ptr<std::vector<uint8_t>> revert_value( |
| std::make_unique<std::vector<uint8_t>>(pair.second)); |
| InFlightPropertyChange property_change(window, pair.first, |
| std::move(revert_value)); |
| InFlightChange* current_change = |
| GetOldestInFlightChangeMatching(property_change); |
| if (current_change) { |
| current_change->SetRevertValueFrom(property_change); |
| } else { |
| window->SetPropertyFromServer(pair.first, &pair.second); |
| } |
| } |
| |
| // Top level windows should not have a parent. |
| DCHECK_EQ(0u, data->parent_id); |
| } |
| |
| void WindowTreeClient::OnWindowBoundsChanged( |
| ui::Id window_id, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightBoundsChange new_change(this, window, new_bounds, local_surface_id); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| SetWindowBoundsFromServer(window, new_bounds, local_surface_id); |
| } |
| |
| void WindowTreeClient::OnWindowTransformChanged( |
| ui::Id window_id, |
| const gfx::Transform& old_transform, |
| const gfx::Transform& new_transform) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightTransformChange new_change(this, window, new_transform); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| SetWindowTransformFromServer(window, new_transform); |
| } |
| |
| void WindowTreeClient::OnClientAreaChanged( |
| ui::Id window_id, |
| const gfx::Insets& new_client_area, |
| const std::vector<gfx::Rect>& new_additional_client_areas) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| float device_scale_factor = window->GetDeviceScaleFactor(); |
| std::vector<gfx::Rect> new_additional_client_areas_in_dip; |
| for (const gfx::Rect& area : new_additional_client_areas) { |
| new_additional_client_areas_in_dip.push_back( |
| gfx::ConvertRectToDIP(device_scale_factor, area)); |
| } |
| window_manager_delegate_->OnWmSetClientArea( |
| window->GetWindow(), |
| gfx::ConvertInsetsToDIP(device_scale_factor, new_client_area), |
| new_additional_client_areas_in_dip); |
| } |
| |
| void WindowTreeClient::OnTransientWindowAdded(ui::Id window_id, |
| ui::Id transient_window_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| WindowMus* transient_window = GetWindowByServerId(transient_window_id); |
| // window or transient_window or both may be null if a local delete occurs |
| // with an in flight add from the server. |
| if (window && transient_window) |
| window->AddTransientChildFromServer(transient_window); |
| } |
| |
| void WindowTreeClient::OnTransientWindowRemoved(ui::Id window_id, |
| ui::Id transient_window_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| WindowMus* transient_window = GetWindowByServerId(transient_window_id); |
| // window or transient_window or both may be null if a local delete occurs |
| // with an in flight delete from the server. |
| if (window && transient_window) |
| window->RemoveTransientChildFromServer(transient_window); |
| } |
| |
| void WindowTreeClient::OnWindowHierarchyChanged( |
| ui::Id window_id, |
| ui::Id old_parent_id, |
| ui::Id new_parent_id, |
| std::vector<ui::mojom::WindowDataPtr> windows) { |
| const bool was_window_known = GetWindowByServerId(window_id) != nullptr; |
| |
| BuildWindowTree(windows); |
| |
| // If the window was not known, then BuildWindowTree() will have created it |
| // and parented the window. |
| if (!was_window_known) |
| return; |
| |
| WindowMus* new_parent = GetWindowByServerId(new_parent_id); |
| WindowMus* old_parent = GetWindowByServerId(old_parent_id); |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (new_parent) |
| new_parent->AddChildFromServer(window); |
| else |
| old_parent->RemoveChildFromServer(window); |
| } |
| |
| void WindowTreeClient::OnWindowReordered(ui::Id window_id, |
| ui::Id relative_window_id, |
| ui::mojom::OrderDirection direction) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| WindowMus* relative_window = GetWindowByServerId(relative_window_id); |
| WindowMus* parent = WindowMus::Get(window->GetWindow()->parent()); |
| if (window && relative_window && parent && |
| parent == WindowMus::Get(relative_window->GetWindow()->parent())) { |
| parent->ReorderFromServer(window, relative_window, direction); |
| } |
| } |
| |
| void WindowTreeClient::OnWindowDeleted(ui::Id window_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| if (roots_.count(window)) { |
| // Roots are associated with WindowTreeHosts. The WindowTreeHost owns the |
| // root, so we have to delete the WindowTreeHost to indirectly delete the |
| // Window. Additionally clients may want to do extra processing before the |
| // delete, so call to the delegate to handle it. Let the window know it is |
| // going to be deleted so we don't callback to the server. |
| window->PrepareForDestroy(); |
| delegate_->OnEmbedRootDestroyed(GetWindowTreeHostMus(window)); |
| } else { |
| window->DestroyFromServer(); |
| } |
| } |
| |
| void WindowTreeClient::OnWindowVisibilityChanged(ui::Id window_id, |
| bool visible) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightVisibleChange new_change(this, window, visible); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| SetWindowVisibleFromServer(window, visible); |
| } |
| |
| void WindowTreeClient::OnWindowOpacityChanged(ui::Id window_id, |
| float old_opacity, |
| float new_opacity) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightOpacityChange new_change(window, new_opacity); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| window->SetOpacityFromServer(new_opacity); |
| } |
| |
| void WindowTreeClient::OnWindowParentDrawnStateChanged(ui::Id window_id, |
| bool drawn) { |
| // TODO: route to WindowTreeHost. |
| /* |
| Window* window = GetWindowByServerId(window_id); |
| if (window) |
| WindowPrivate(window).LocalSetParentDrawn(drawn); |
| */ |
| } |
| |
| void WindowTreeClient::OnWindowSharedPropertyChanged( |
| ui::Id window_id, |
| const std::string& name, |
| const base::Optional<std::vector<uint8_t>>& transport_data) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| std::unique_ptr<std::vector<uint8_t>> data; |
| if (transport_data.has_value()) |
| data = std::make_unique<std::vector<uint8_t>>(transport_data.value()); |
| |
| InFlightPropertyChange new_change(window, name, std::move(data)); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| window->SetPropertyFromServer( |
| name, transport_data.has_value() ? &transport_data.value() : nullptr); |
| } |
| |
| void WindowTreeClient::OnWindowInputEvent( |
| uint32_t event_id, |
| ui::Id window_id, |
| int64_t display_id, |
| ui::Id display_root_window_id, |
| const gfx::PointF& event_location_in_screen_pixel_layout, |
| std::unique_ptr<ui::Event> event, |
| bool matches_pointer_watcher) { |
| DCHECK(event); |
| WindowMus* window = GetWindowByServerId(window_id); // May be null. |
| |
| if (matches_pointer_watcher && has_pointer_watcher_) { |
| DCHECK(event->IsPointerEvent()); |
| std::unique_ptr<ui::Event> event_in_dip(ui::Event::Clone(*event)); |
| ConvertPointerEventLocationToDip(display_id, window, |
| event_in_dip->AsLocatedEvent()); |
| delegate_->OnPointerEventObserved(*event_in_dip->AsPointerEvent(), |
| window ? window->GetWindow() : nullptr); |
| } |
| |
| // If the window has already been deleted, use |event| to update event states |
| // kept in aura::Env. |
| if (!window || !window->GetWindow()->GetHost()) { |
| EnvInputStateController* env_controller = |
| Env::GetInstance()->env_controller(); |
| std::unique_ptr<ui::Event> mapped_event = MapEvent(*event.get()); |
| if (mapped_event->IsMouseEvent()) { |
| env_controller->UpdateStateForMouseEvent(nullptr, |
| *mapped_event->AsMouseEvent()); |
| } else if (mapped_event->IsTouchEvent()) { |
| env_controller->UpdateStateForTouchEvent(*mapped_event->AsTouchEvent()); |
| } |
| tree_->OnWindowInputEventAck(event_id, ui::mojom::EventResult::UNHANDLED); |
| return; |
| } |
| |
| if (event->IsKeyEvent()) { |
| InputMethodMus* input_method = GetWindowTreeHostMus(window)->input_method(); |
| if (input_method) { |
| ignore_result(input_method->DispatchKeyEvent( |
| event->AsKeyEvent(), CreateEventResultCallback(event_id))); |
| return; |
| } |
| } |
| |
| EventAckHandler ack_handler(CreateEventResultCallback(event_id)); |
| // TODO(moshayedi): crbug.com/617222. No need to convert to ui::MouseEvent or |
| // ui::TouchEvent once we have proper support for pointer events. |
| std::unique_ptr<ui::Event> mapped_event = MapEvent(*event.get()); |
| ui::Event* event_to_dispatch = mapped_event.get(); |
| // Ash wants the native events in one place (see ExtendedMouseWarpController). |
| // By using the constructor that takes a MouseEvent we ensure the MouseEvent |
| // has a NativeEvent that can be used to extract the pixel coordinates. |
| // |
| // TODO: this should really be covered by |root_location|. See 608547 for |
| // details. |
| #if defined(USE_OZONE) |
| std::unique_ptr<ui::MouseEvent> mapped_event_with_native; |
| if (mapped_event->type() == ui::ET_MOUSE_MOVED || |
| mapped_event->type() == ui::ET_MOUSE_DRAGGED) { |
| mapped_event_with_native = std::make_unique<ui::MouseEvent>( |
| static_cast<const base::NativeEvent&>(mapped_event.get())); |
| // MouseEvent(NativeEvent) sets the root_location to location. |
| mapped_event_with_native->set_root_location_f( |
| event_location_in_screen_pixel_layout); |
| // |mapped_event| is now the NativeEvent. It's expected the location of the |
| // NativeEvent is the same as root_location. |
| mapped_event->AsMouseEvent()->set_location_f( |
| event_location_in_screen_pixel_layout); |
| event_to_dispatch = mapped_event_with_native.get(); |
| } |
| #endif |
| |
| WindowMus* display_root_window = GetWindowByServerId(display_root_window_id); |
| if (display_root_window && event->IsLocatedEvent() && |
| display::Screen::GetScreen()->GetPrimaryDisplay().id() == |
| display::kUnifiedDisplayId) { |
| // In Ash's unified desktop mode, each physical display mirrors part of a |
| // single virtual display. Dispatch events to the root window of the mirror |
| // display supplying the event, using locations relative to that display. |
| // Use a null target to ensure events reach the MusUnifiedEventTargeter. |
| // This paralells the behavior of unified desktop mode in classic Ash. |
| ui::Event::DispatcherApi(event_to_dispatch).set_target(nullptr); |
| ui::LocatedEvent* located_event = event_to_dispatch->AsLocatedEvent(); |
| located_event->set_location_f(located_event->root_location_f()); |
| window = display_root_window; |
| } else if (!event->IsKeyEvent()) { |
| // Set |window| as the target, except for key events. Key events go to the |
| // focused window, which may have changed by the time we process the event. |
| ui::Event::DispatcherApi(event_to_dispatch).set_target(window->GetWindow()); |
| } |
| GetWindowTreeHostMus(window)->SendEventToSink(event_to_dispatch); |
| |
| ack_handler.set_handled(event_to_dispatch->handled()); |
| } |
| |
| void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event, |
| ui::Id window_id, |
| int64_t display_id) { |
| DCHECK(event); |
| DCHECK(event->IsPointerEvent()); |
| if (!has_pointer_watcher_) |
| return; |
| |
| WindowMus* target_window = GetWindowByServerId(window_id); |
| ConvertPointerEventLocationToDip(display_id, target_window, |
| event->AsLocatedEvent()); |
| delegate_->OnPointerEventObserved( |
| *event->AsPointerEvent(), |
| target_window ? target_window->GetWindow() : nullptr); |
| } |
| |
| void WindowTreeClient::OnWindowFocused(ui::Id focused_window_id) { |
| WindowMus* focused_window = GetWindowByServerId(focused_window_id); |
| InFlightFocusChange new_change(this, focus_synchronizer_.get(), |
| focused_window); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| focus_synchronizer_->SetFocusFromServer(focused_window); |
| } |
| |
| void WindowTreeClient::OnWindowCursorChanged(ui::Id window_id, |
| ui::CursorData cursor) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightCursorChange new_change(window, cursor); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| window->SetCursorFromServer(cursor); |
| } |
| |
| void WindowTreeClient::OnWindowSurfaceChanged( |
| ui::Id window_id, |
| const viz::SurfaceInfo& surface_info) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| // If the parent is informed of a child's surface then that surface ID is |
| // guaranteed to be available in the display compositor so we set it as the |
| // fallback. If surface synchronization is enabled, the primary SurfaceInfo |
| // is created by the embedder, and the LocalSurfaceId is allocated by the |
| // embedder. |
| window->SetFallbackSurfaceInfo(surface_info); |
| } |
| |
| void WindowTreeClient::OnDragDropStart( |
| const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data) { |
| drag_drop_controller_->OnDragDropStart(mojo::UnorderedMapToMap(mime_data)); |
| } |
| |
| void WindowTreeClient::OnDragEnter(ui::Id window_id, |
| uint32_t key_state, |
| const gfx::Point& position, |
| uint32_t effect_bitmask, |
| const OnDragEnterCallback& callback) { |
| callback.Run(drag_drop_controller_->OnDragEnter( |
| GetWindowByServerId(window_id), key_state, position, effect_bitmask)); |
| } |
| |
| void WindowTreeClient::OnDragOver(ui::Id window_id, |
| uint32_t key_state, |
| const gfx::Point& position, |
| uint32_t effect_bitmask, |
| const OnDragOverCallback& callback) { |
| callback.Run(drag_drop_controller_->OnDragOver( |
| GetWindowByServerId(window_id), key_state, position, effect_bitmask)); |
| } |
| |
| void WindowTreeClient::OnDragLeave(ui::Id window_id) { |
| drag_drop_controller_->OnDragLeave(GetWindowByServerId(window_id)); |
| } |
| |
| void WindowTreeClient::OnDragDropDone() { |
| drag_drop_controller_->OnDragDropDone(); |
| } |
| |
| void WindowTreeClient::OnCompleteDrop(ui::Id window_id, |
| uint32_t key_state, |
| const gfx::Point& position, |
| uint32_t effect_bitmask, |
| const OnCompleteDropCallback& callback) { |
| callback.Run(drag_drop_controller_->OnCompleteDrop( |
| GetWindowByServerId(window_id), key_state, position, effect_bitmask)); |
| } |
| |
| void WindowTreeClient::OnPerformDragDropCompleted(uint32_t change_id, |
| bool success, |
| uint32_t action_taken) { |
| OnChangeCompleted(change_id, success); |
| if (drag_drop_controller_->DoesChangeIdMatchDragChangeId(change_id)) |
| drag_drop_controller_->OnPerformDragDropCompleted(action_taken); |
| } |
| |
| void WindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) { |
| std::unique_ptr<InFlightChange> change(std::move(in_flight_map_[change_id])); |
| in_flight_map_.erase(change_id); |
| if (!change) |
| return; |
| |
| for (auto& observer : test_observers_) |
| observer.OnChangeCompleted(change_id, change->change_type(), success); |
| |
| if (!success) |
| change->ChangeFailed(); |
| |
| InFlightChange* next_change = GetOldestInFlightChangeMatching(*change); |
| if (next_change) { |
| if (!success) |
| next_change->SetRevertValueFrom(*change); |
| } else if (!success) { |
| change->Revert(); |
| } |
| |
| if (change_id == current_move_loop_change_) { |
| current_move_loop_change_ = 0; |
| on_current_move_finished_.Run(success); |
| on_current_move_finished_.Reset(); |
| } |
| } |
| |
| void WindowTreeClient::SetBlockingContainers( |
| const std::vector<BlockingContainers>& all_blocking_containers) { |
| std::vector<ui::mojom::BlockingContainersPtr> |
| transport_all_blocking_containers; |
| for (const BlockingContainers& blocking_containers : |
| all_blocking_containers) { |
| ui::mojom::BlockingContainersPtr transport_blocking_containers = |
| ui::mojom::BlockingContainers::New(); |
| // The |system_modal_container| must be specified, |min_container| may be |
| // null. |
| DCHECK(blocking_containers.system_modal_container); |
| transport_blocking_containers->system_modal_container_id = |
| GetServerIdForWindow(blocking_containers.system_modal_container); |
| transport_blocking_containers->min_container_id = |
| GetServerIdForWindow(blocking_containers.min_container); |
| transport_all_blocking_containers.push_back( |
| std::move(transport_blocking_containers)); |
| } |
| window_manager_client_->SetBlockingContainers( |
| std::move(transport_all_blocking_containers), |
| base::Bind(&OnAckMustSucceed, FROM_HERE)); |
| } |
| |
| void WindowTreeClient::GetWindowManager( |
| mojo::AssociatedInterfaceRequest<WindowManager> internal) { |
| window_manager_internal_.reset( |
| new mojo::AssociatedBinding<ui::mojom::WindowManager>( |
| this, std::move(internal))); |
| } |
| |
| void WindowTreeClient::RequestClose(ui::Id window_id) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window || !IsRoot(window)) |
| return; |
| |
| // Since the window is the root window, we send close request to the entire |
| // WindowTreeHost. |
| GetWindowTreeHostMus(window->GetWindow())->OnCloseRequest(); |
| } |
| |
| bool WindowTreeClient::WaitForInitialDisplays() { |
| if (got_initial_displays_) |
| return true; |
| |
| bool valid_wait = true; |
| // TODO(sky): having to block here is not ideal. http://crbug.com/594852. |
| while (!got_initial_displays_ && valid_wait) |
| valid_wait = binding_.WaitForIncomingMethodCall(); |
| return valid_wait; |
| } |
| |
| WindowTreeHostMusInitParams WindowTreeClient::CreateInitParamsForNewDisplay() { |
| WindowTreeHostMusInitParams init_params; |
| init_params.window_port = std::make_unique<WindowPortMus>( |
| this, WindowMusType::DISPLAY_MANUALLY_CREATED); |
| roots_.insert(init_params.window_port.get()); |
| init_params.window_tree_client = this; |
| return init_params; |
| } |
| |
| void WindowTreeClient::OnConnect() { |
| got_initial_displays_ = true; |
| if (window_manager_delegate_) |
| window_manager_delegate_->OnWmConnected(); |
| } |
| |
| void WindowTreeClient::WmOnAcceleratedWidgetForDisplay( |
| int64_t display, |
| gpu::SurfaceHandle surface_handle) { |
| if (window_manager_delegate_) { |
| window_manager_delegate_->OnWmAcceleratedWidgetAvailableForDisplay( |
| display, surface_handle); |
| } |
| } |
| |
| void WindowTreeClient::WmNewDisplayAdded( |
| const display::Display& display, |
| ui::mojom::WindowDataPtr root_data, |
| bool parent_drawn, |
| const base::Optional<viz::LocalSurfaceId>& local_surface_id) { |
| WmNewDisplayAddedImpl(display, std::move(root_data), parent_drawn, |
| local_surface_id); |
| } |
| |
| void WindowTreeClient::WmDisplayRemoved(int64_t display_id) { |
| DCHECK(window_manager_delegate_); |
| for (WindowMus* root : roots_) { |
| DCHECK(root->GetWindow()->GetHost()); |
| WindowTreeHostMus* window_tree_host = |
| static_cast<WindowTreeHostMus*>(root->GetWindow()->GetHost()); |
| if (window_tree_host->display_id() == display_id) { |
| window_manager_delegate_->OnWmDisplayRemoved(window_tree_host); |
| return; |
| } |
| } |
| } |
| |
| void WindowTreeClient::WmDisplayModified(const display::Display& display) { |
| DCHECK(window_manager_delegate_); |
| // TODO(sky): this should likely route to WindowTreeHost. |
| window_manager_delegate_->OnWmDisplayModified(display); |
| } |
| |
| void WindowTreeClient::WmSetBounds(uint32_t change_id, |
| ui::Id window_id, |
| const gfx::Rect& transit_bounds_in_pixels) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) { |
| float device_scale_factor = window->GetDeviceScaleFactor(); |
| DCHECK(window_manager_delegate_); |
| gfx::Rect transit_bounds_in_dip = |
| gfx::ConvertRectToDIP(device_scale_factor, transit_bounds_in_pixels); |
| window_manager_delegate_->OnWmSetBounds(window->GetWindow(), |
| transit_bounds_in_dip); |
| } else { |
| DVLOG(1) << "Unknown window passed to WmSetBounds()."; |
| } |
| if (window_manager_client_) |
| window_manager_client_->WmSetBoundsResponse(change_id); |
| } |
| |
| void WindowTreeClient::WmSetProperty( |
| uint32_t change_id, |
| ui::Id window_id, |
| const std::string& name, |
| const base::Optional<std::vector<uint8_t>>& transit_data) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| bool result = false; |
| if (window) { |
| DCHECK(window_manager_delegate_); |
| std::unique_ptr<std::vector<uint8_t>> data; |
| if (transit_data.has_value()) |
| data.reset(new std::vector<uint8_t>(transit_data.value())); |
| |
| result = window_manager_delegate_->OnWmSetProperty(window->GetWindow(), |
| name, &data); |
| if (result) { |
| delegate_->GetPropertyConverter()->SetPropertyFromTransportValue( |
| window->GetWindow(), name, data.get()); |
| } |
| } |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(change_id, result); |
| } |
| |
| void WindowTreeClient::WmSetModalType(ui::Id window_id, ui::ModalType type) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) |
| window_manager_delegate_->OnWmSetModalType(window->GetWindow(), type); |
| } |
| |
| void WindowTreeClient::WmSetCanFocus(ui::Id window_id, bool can_focus) { |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) |
| window_manager_delegate_->OnWmSetCanFocus(window->GetWindow(), can_focus); |
| } |
| |
| void WindowTreeClient::WmCreateTopLevelWindow( |
| uint32_t change_id, |
| const viz::FrameSinkId& frame_sink_id, |
| const std::unordered_map<std::string, std::vector<uint8_t>>& |
| transport_properties) { |
| DCHECK(frame_sink_id.is_valid()); |
| std::map<std::string, std::vector<uint8_t>> properties = |
| mojo::UnorderedMapToMap(transport_properties); |
| ui::mojom::WindowType window_type = ui::mojom::WindowType::UNKNOWN; |
| auto type_iter = |
| properties.find(ui::mojom::WindowManager::kWindowType_InitProperty); |
| if (type_iter != properties.end()) { |
| // TODO: validation! http://crbug.com/654924. |
| window_type = static_cast<ui::mojom::WindowType>( |
| mojo::ConvertTo<int32_t>(type_iter->second)); |
| } |
| Window* window = window_manager_delegate_->OnWmCreateTopLevelWindow( |
| window_type, &properties); |
| if (!window) { |
| window_manager_client_->OnWmCreatedTopLevelWindow(change_id, |
| kInvalidServerId); |
| return; |
| } |
| embedded_windows_[base::checked_cast<ui::ClientSpecificId>( |
| frame_sink_id.client_id())] |
| .insert(window); |
| if (window_manager_client_) { |
| window_manager_client_->OnWmCreatedTopLevelWindow( |
| change_id, WindowMus::Get(window)->server_id()); |
| OnFrameSinkIdAllocated(WindowMus::Get(window)->server_id(), frame_sink_id); |
| } |
| } |
| |
| void WindowTreeClient::WmClientJankinessChanged(ui::ClientSpecificId client_id, |
| bool janky) { |
| if (window_manager_delegate_) { |
| auto it = embedded_windows_.find(client_id); |
| // TODO(sky): early return necessitated because of http://crbug.com/766890. |
| if (it == embedded_windows_.end()) |
| return; |
| window_manager_delegate_->OnWmClientJankinessChanged( |
| embedded_windows_[client_id], janky); |
| } |
| } |
| |
| void WindowTreeClient::WmBuildDragImage(const gfx::Point& screen_location, |
| const SkBitmap& drag_image, |
| const gfx::Vector2d& drag_image_offset, |
| ui::mojom::PointerKind source) { |
| if (!window_manager_delegate_) |
| return; |
| |
| window_manager_delegate_->OnWmBuildDragImage(screen_location, drag_image, |
| drag_image_offset, source); |
| } |
| |
| void WindowTreeClient::WmMoveDragImage(const gfx::Point& screen_location, |
| WmMoveDragImageCallback callback) { |
| if (window_manager_delegate_) |
| window_manager_delegate_->OnWmMoveDragImage(screen_location); |
| std::move(callback).Run(); |
| } |
| |
| void WindowTreeClient::WmDestroyDragImage() { |
| if (!window_manager_delegate_) |
| return; |
| |
| window_manager_delegate_->OnWmDestroyDragImage(); |
| } |
| |
| void WindowTreeClient::WmPerformMoveLoop(uint32_t change_id, |
| ui::Id window_id, |
| ui::mojom::MoveLoopSource source, |
| const gfx::Point& cursor_location) { |
| if (!window_manager_delegate_ || current_wm_move_loop_change_ != 0) { |
| OnWmMoveLoopCompleted(change_id, false); |
| return; |
| } |
| |
| current_wm_move_loop_change_ = change_id; |
| current_wm_move_loop_window_id_ = window_id; |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) { |
| window_manager_delegate_->OnWmPerformMoveLoop( |
| window->GetWindow(), source, cursor_location, |
| base::Bind(&WindowTreeClient::OnWmMoveLoopCompleted, |
| weak_factory_.GetWeakPtr(), change_id)); |
| } else { |
| OnWmMoveLoopCompleted(change_id, false); |
| } |
| } |
| |
| void WindowTreeClient::WmCancelMoveLoop(uint32_t change_id) { |
| if (!window_manager_delegate_ || change_id != current_wm_move_loop_change_) |
| return; |
| |
| WindowMus* window = GetWindowByServerId(current_wm_move_loop_window_id_); |
| if (window) |
| window_manager_delegate_->OnWmCancelMoveLoop(window->GetWindow()); |
| } |
| |
| void WindowTreeClient::WmDeactivateWindow(ui::Id window_id) { |
| if (!window_manager_delegate_) |
| return; |
| |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) { |
| DVLOG(1) << "Attempt to deactivate invalid window " << window_id; |
| return; |
| } |
| |
| if (!window_manager_delegate_->IsWindowActive(window->GetWindow())) { |
| DVLOG(1) << "Non-active window requested deactivation."; |
| return; |
| } |
| |
| window_manager_delegate_->OnWmDeactivateWindow(window->GetWindow()); |
| } |
| |
| void WindowTreeClient::WmStackAbove(uint32_t wm_change_id, |
| ui::Id above_id, |
| ui::Id below_id) { |
| if (!window_manager_delegate_) |
| return; |
| |
| WindowMus* below_mus = GetWindowByServerId(below_id); |
| if (!below_mus) { |
| DVLOG(1) << "Attempt to stack at top invalid window " << below_id; |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(wm_change_id, false); |
| return; |
| } |
| |
| WindowMus* above_mus = GetWindowByServerId(above_id); |
| if (!above_mus) { |
| DVLOG(1) << "Attempt to stack at top invalid window " << above_id; |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(wm_change_id, false); |
| return; |
| } |
| |
| Window* above = above_mus->GetWindow(); |
| Window* below = below_mus->GetWindow(); |
| |
| if (above->parent() != below->parent()) { |
| DVLOG(1) << "Windows do not share the same parent"; |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(wm_change_id, false); |
| return; |
| } |
| |
| above->parent()->StackChildAbove(above, below); |
| |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(wm_change_id, true); |
| } |
| |
| void WindowTreeClient::WmStackAtTop(uint32_t wm_change_id, ui::Id window_id) { |
| if (!window_manager_delegate_) |
| return; |
| |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (!window) { |
| DVLOG(1) << "Attempt to stack at top invalid window " << window_id; |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(wm_change_id, false); |
| return; |
| } |
| |
| Window* parent = window->GetWindow()->parent(); |
| parent->StackChildAtTop(window->GetWindow()); |
| |
| if (window_manager_client_) |
| window_manager_client_->WmResponse(wm_change_id, true); |
| } |
| |
| void WindowTreeClient::WmPerformWmAction(ui::Id window_id, |
| const std::string& action) { |
| if (!window_manager_delegate_) |
| return; |
| |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) |
| window_manager_delegate_->OnWmPerformAction(window->GetWindow(), action); |
| } |
| |
| void WindowTreeClient::OnAccelerator(uint32_t ack_id, |
| uint32_t accelerator_id, |
| std::unique_ptr<ui::Event> event) { |
| DCHECK(event); |
| std::unordered_map<std::string, std::vector<uint8_t>> properties; |
| const ui::mojom::EventResult result = window_manager_delegate_->OnAccelerator( |
| accelerator_id, *event.get(), &properties); |
| if (ack_id && window_manager_client_) |
| window_manager_client_->OnAcceleratorAck(ack_id, result, properties); |
| } |
| |
| void WindowTreeClient::OnCursorTouchVisibleChanged(bool enabled) { |
| if (window_manager_client_) |
| window_manager_delegate_->OnCursorTouchVisibleChanged(enabled); |
| } |
| |
| void WindowTreeClient::OnEventBlockedByModalWindow(ui::Id window_id) { |
| if (!window_manager_delegate_) |
| return; |
| |
| WindowMus* window = GetWindowByServerId(window_id); |
| if (window) |
| window_manager_delegate_->OnEventBlockedByModalWindow(window->GetWindow()); |
| } |
| |
| void WindowTreeClient::SetFrameDecorationValues( |
| ui::mojom::FrameDecorationValuesPtr values) { |
| if (window_manager_client_) { |
| normal_client_area_insets_ = values->normal_client_area_insets; |
| window_manager_client_->WmSetFrameDecorationValues(std::move(values)); |
| } |
| } |
| |
| void WindowTreeClient::SetNonClientCursor(Window* window, |
| const ui::CursorData& cursor) { |
| if (window_manager_client_) { |
| window_manager_client_->WmSetNonClientCursor( |
| WindowMus::Get(window)->server_id(), cursor); |
| } |
| } |
| |
| void WindowTreeClient::AddAccelerators( |
| std::vector<ui::mojom::WmAcceleratorPtr> accelerators, |
| const base::Callback<void(bool)>& callback) { |
| if (window_manager_client_) { |
| window_manager_client_->AddAccelerators(std::move(accelerators), callback); |
| } |
| } |
| |
| void WindowTreeClient::RemoveAccelerator(uint32_t id) { |
| if (window_manager_client_) { |
| window_manager_client_->RemoveAccelerator(id); |
| } |
| } |
| |
| void WindowTreeClient::AddActivationParent(Window* window) { |
| if (window_manager_client_) { |
| window_manager_client_->AddActivationParent( |
| WindowMus::Get(window)->server_id()); |
| } |
| } |
| |
| void WindowTreeClient::RemoveActivationParent(Window* window) { |
| if (window_manager_client_) { |
| window_manager_client_->RemoveActivationParent( |
| WindowMus::Get(window)->server_id()); |
| } |
| } |
| |
| void WindowTreeClient::SetExtendedHitRegionForChildren( |
| Window* window, |
| const gfx::Insets& mouse_insets, |
| const gfx::Insets& touch_insets) { |
| if (!window_manager_client_) |
| return; |
| |
| WindowMus* window_mus = WindowMus::Get(window); |
| const float device_scale_factor = window_mus->GetDeviceScaleFactor(); |
| window_manager_client_->SetExtendedHitRegionForChildren( |
| window_mus->server_id(), |
| gfx::ConvertInsetsToPixel(device_scale_factor, mouse_insets), |
| gfx::ConvertInsetsToPixel(device_scale_factor, touch_insets)); |
| } |
| |
| void WindowTreeClient::LockCursor() { |
| if (window_manager_client_) |
| window_manager_client_->WmLockCursor(); |
| } |
| |
| void WindowTreeClient::UnlockCursor() { |
| if (window_manager_client_) |
| window_manager_client_->WmUnlockCursor(); |
| } |
| |
| void WindowTreeClient::SetCursorVisible(bool visible) { |
| if (window_manager_client_) |
| window_manager_client_->WmSetCursorVisible(visible); |
| } |
| |
| void WindowTreeClient::SetCursorSize(ui::CursorSize cursor_size) { |
| if (window_manager_client_) |
| window_manager_client_->WmSetCursorSize(cursor_size); |
| } |
| |
| void WindowTreeClient::SetGlobalOverrideCursor( |
| base::Optional<ui::CursorData> cursor) { |
| if (window_manager_client_) |
| window_manager_client_->WmSetGlobalOverrideCursor(std::move(cursor)); |
| } |
| |
| void WindowTreeClient::SetCursorTouchVisible(bool enabled) { |
| if (window_manager_client_) |
| window_manager_client_->WmSetCursorTouchVisible(enabled); |
| } |
| |
| void WindowTreeClient::InjectEvent(const ui::Event& event, int64_t display_id) { |
| if (!event_injector_) |
| connector()->BindInterface(ui::mojom::kServiceName, &event_injector_); |
| // Check event_injector_ so we don't crash if access to the interface was |
| // refused. |
| if (event_injector_) { |
| event_injector_->DispatchEvent(display_id, ui::Event::Clone(event), |
| base::DoNothing()); |
| } |
| } |
| |
| void WindowTreeClient::SetKeyEventsThatDontHideCursor( |
| std::vector<ui::mojom::EventMatcherPtr> cursor_key_list) { |
| if (window_manager_client_) { |
| window_manager_client_->SetKeyEventsThatDontHideCursor( |
| std::move(cursor_key_list)); |
| } |
| } |
| |
| void WindowTreeClient::RequestClose(Window* window) { |
| DCHECK(window); |
| if (window_manager_client_) |
| window_manager_client_->WmRequestClose(WindowMus::Get(window)->server_id()); |
| } |
| |
| void WindowTreeClient::SetDisplayConfiguration( |
| const std::vector<display::Display>& displays, |
| std::vector<ui::mojom::WmViewportMetricsPtr> viewport_metrics, |
| int64_t primary_display_id, |
| const std::vector<display::Display>& mirrors) { |
| DCHECK_EQ(displays.size() + mirrors.size(), viewport_metrics.size()); |
| if (window_manager_client_) { |
| const int64_t internal_display_id = |
| display::Display::HasInternalDisplay() |
| ? display::Display::InternalDisplayId() |
| : display::kInvalidDisplayId; |
| window_manager_client_->SetDisplayConfiguration( |
| displays, std::move(viewport_metrics), primary_display_id, |
| internal_display_id, mirrors, base::Bind(&OnAckMustSucceed, FROM_HERE)); |
| } |
| } |
| |
| void WindowTreeClient::AddDisplayReusingWindowTreeHost( |
| WindowTreeHostMus* window_tree_host, |
| const display::Display& display, |
| ui::mojom::WmViewportMetricsPtr viewport_metrics) { |
| DCHECK_NE(display.id(), window_tree_host->display_id()); |
| window_tree_host->set_display_id(display.id()); |
| if (window_manager_client_) { |
| // NOTE: The values of |is_primary_display| and |mirrors| do not matter, |
| // because SetDisplayConfiguration() is called shortly after this completes. |
| const bool is_primary_display = true; |
| std::vector<display::Display> mirrors; |
| WindowMus* display_root_window = WindowMus::Get(window_tree_host->window()); |
| window_manager_client_->SetDisplayRoot( |
| display, std::move(viewport_metrics), is_primary_display, |
| display_root_window->server_id(), mirrors, |
| base::Bind(&OnAckMustSucceed, FROM_HERE)); |
| window_tree_host->compositor()->SetLocalSurfaceId( |
| display_root_window->GetOrAllocateLocalSurfaceId( |
| window_tree_host->GetBoundsInPixels().size())); |
| } |
| } |
| |
| void WindowTreeClient::SwapDisplayRoots(WindowTreeHostMus* window_tree_host1, |
| WindowTreeHostMus* window_tree_host2) { |
| DCHECK_NE(window_tree_host1, window_tree_host2); |
| const int64_t display_id1 = window_tree_host1->display_id(); |
| const int64_t display_id2 = window_tree_host2->display_id(); |
| DCHECK_NE(display_id1, display_id2); |
| window_tree_host1->set_display_id(display_id2); |
| window_tree_host2->set_display_id(display_id1); |
| |
| // Swap the accelerated widgets so each host paints to the correct display. |
| gfx::AcceleratedWidget widget1 = window_tree_host1->GetAcceleratedWidget(); |
| gfx::AcceleratedWidget widget2 = window_tree_host2->GetAcceleratedWidget(); |
| window_tree_host1->OverrideAcceleratedWidget(widget2); |
| window_tree_host2->OverrideAcceleratedWidget(widget1); |
| |
| if (window_manager_client_) { |
| window_manager_client_->SwapDisplayRoots( |
| display_id1, display_id2, base::Bind(&OnAckMustSucceed, FROM_HERE)); |
| } |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostBoundsWillChange( |
| WindowTreeHostMus* window_tree_host, |
| const gfx::Rect& bounds) { |
| gfx::Rect old_bounds = window_tree_host->GetBoundsInPixels(); |
| gfx::Rect new_bounds = bounds; |
| if (window_manager_delegate_) { |
| // The window manager origins should always be 0x0. The real origin is |
| // communicated by way of SetDisplayConfiguration(). |
| old_bounds.set_origin(gfx::Point()); |
| new_bounds.set_origin(gfx::Point()); |
| } |
| ScheduleInFlightBoundsChange(WindowMus::Get(window_tree_host->window()), |
| old_bounds, new_bounds); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostClientAreaWillChange( |
| WindowTreeHostMus* window_tree_host, |
| const gfx::Insets& client_area, |
| const std::vector<gfx::Rect>& additional_client_areas) { |
| DCHECK(tree_); |
| WindowMus* window = WindowMus::Get(window_tree_host->window()); |
| float device_scale_factor = window->GetDeviceScaleFactor(); |
| std::vector<gfx::Rect> additional_client_areas_in_pixel; |
| for (const gfx::Rect& area : additional_client_areas) { |
| additional_client_areas_in_pixel.push_back( |
| gfx::ConvertRectToPixel(device_scale_factor, area)); |
| } |
| tree_->SetClientArea( |
| window->server_id(), |
| gfx::ConvertInsetsToPixel(device_scale_factor, client_area), |
| additional_client_areas_in_pixel); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostSetOpacity( |
| WindowTreeHostMus* window_tree_host, |
| float opacity) { |
| WindowMus* window = WindowMus::Get(window_tree_host->window()); |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(window, ChangeType::OPACITY)); |
| tree_->SetWindowOpacity(change_id, window->server_id(), opacity); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostDeactivateWindow( |
| WindowTreeHostMus* window_tree_host) { |
| tree_->DeactivateWindow( |
| WindowMus::Get(window_tree_host->window())->server_id()); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostStackAbove( |
| WindowTreeHostMus* window_tree_host, |
| Window* window) { |
| WindowMus* above = WindowMus::Get(window_tree_host->window()); |
| WindowMus* below = WindowMus::Get(window); |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(above, ChangeType::REORDER)); |
| tree_->StackAbove(change_id, above->server_id(), below->server_id()); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostStackAtTop( |
| WindowTreeHostMus* window_tree_host) { |
| WindowMus* window = WindowMus::Get(window_tree_host->window()); |
| const uint32_t change_id = ScheduleInFlightChange( |
| std::make_unique<CrashInFlightChange>(window, ChangeType::REORDER)); |
| tree_->StackAtTop(change_id, window->server_id()); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostPerformWmAction( |
| WindowTreeHostMus* window_tree_host, |
| const std::string& action) { |
| WindowMus* window = WindowMus::Get(window_tree_host->window()); |
| tree_->PerformWmAction(window->server_id(), action); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostPerformWindowMove( |
| WindowTreeHostMus* window_tree_host, |
| ui::mojom::MoveLoopSource source, |
| const gfx::Point& cursor_location, |
| const base::Callback<void(bool)>& callback) { |
| DCHECK(on_current_move_finished_.is_null()); |
| on_current_move_finished_ = callback; |
| |
| WindowMus* window_mus = WindowMus::Get(window_tree_host->window()); |
| current_move_loop_change_ = ScheduleInFlightChange( |
| std::make_unique<InFlightDragChange>(window_mus, ChangeType::MOVE_LOOP)); |
| // Tell the window manager to take over moving us. |
| tree_->PerformWindowMove(current_move_loop_change_, window_mus->server_id(), |
| source, cursor_location); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostCancelWindowMove( |
| WindowTreeHostMus* window_tree_host) { |
| tree_->CancelWindowMove( |
| WindowMus::Get(window_tree_host->window())->server_id()); |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostMoveCursorToDisplayLocation( |
| const gfx::Point& location_in_pixels, |
| int64_t display_id) { |
| DCHECK(window_manager_client_); |
| if (window_manager_client_) { |
| window_manager_client_->WmMoveCursorToDisplayLocation(location_in_pixels, |
| display_id); |
| } |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostConfineCursorToBounds( |
| const gfx::Rect& bounds_in_pixels, |
| int64_t display_id) { |
| DCHECK(window_manager_client_); |
| if (window_manager_client_) { |
| window_manager_client_->WmConfineCursorToBounds(bounds_in_pixels, |
| display_id); |
| } |
| } |
| |
| std::unique_ptr<WindowPortMus> WindowTreeClient::CreateWindowPortForTopLevel( |
| const std::map<std::string, std::vector<uint8_t>>* properties) { |
| std::unique_ptr<WindowPortMus> window_port = |
| std::make_unique<WindowPortMus>(this, WindowMusType::TOP_LEVEL); |
| roots_.insert(window_port.get()); |
| |
| window_port->set_server_id(next_window_id_++); |
| RegisterWindowMus(window_port.get()); |
| |
| std::unordered_map<std::string, std::vector<uint8_t>> transport_properties; |
| if (properties) { |
| for (const auto& property_pair : *properties) |
| transport_properties[property_pair.first] = property_pair.second; |
| } |
| |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<CrashInFlightChange>( |
| window_port.get(), ChangeType::NEW_TOP_LEVEL_WINDOW)); |
| tree_->NewTopLevelWindow(change_id, window_port->server_id(), |
| transport_properties); |
| return window_port; |
| } |
| |
| void WindowTreeClient::OnWindowTreeHostCreated( |
| WindowTreeHostMus* window_tree_host) { |
| // All WindowTreeHosts are destroyed before this, so we don't need to unset |
| // the DragDropClient. |
| if (install_drag_drop_client_) { |
| client::SetDragDropClient(window_tree_host->window(), |
| drag_drop_controller_.get()); |
| } |
| } |
| |
| void WindowTreeClient::OnTransientChildWindowAdded(Window* parent, |
| Window* transient_child) { |
| // TransientWindowClient is a singleton and we allow multiple |
| // WindowTreeClients. Ignore changes to windows we don't know about (assume |
| // they came from another connection). |
| if (!IsWindowKnown(parent) || !IsWindowKnown(transient_child)) |
| return; |
| |
| if (WindowMus::Get(parent)->OnTransientChildAdded( |
| WindowMus::Get(transient_child)) == WindowMus::ChangeSource::SERVER) { |
| return; |
| } |
| |
| // The change originated from client code and needs to be sent to the server. |
| DCHECK(tree_); |
| WindowMus* parent_mus = WindowMus::Get(parent); |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<CrashInFlightChange>( |
| parent_mus, ChangeType::ADD_TRANSIENT_WINDOW)); |
| tree_->AddTransientWindow(change_id, parent_mus->server_id(), |
| WindowMus::Get(transient_child)->server_id()); |
| } |
| |
| void WindowTreeClient::OnTransientChildWindowRemoved(Window* parent, |
| Window* transient_child) { |
| // See comments in OnTransientChildWindowAdded() for details on early return. |
| if (!IsWindowKnown(parent) || !IsWindowKnown(transient_child)) |
| return; |
| |
| if (WindowMus::Get(parent)->OnTransientChildRemoved( |
| WindowMus::Get(transient_child)) == WindowMus::ChangeSource::SERVER) { |
| return; |
| } |
| // The change originated from client code and needs to be sent to the server. |
| DCHECK(tree_); |
| WindowMus* child_mus = WindowMus::Get(transient_child); |
| const uint32_t change_id = |
| ScheduleInFlightChange(std::make_unique<CrashInFlightChange>( |
| child_mus, ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)); |
| tree_->RemoveTransientWindowFromParent(change_id, child_mus->server_id()); |
| } |
| |
| uint32_t WindowTreeClient::CreateChangeIdForDrag(WindowMus* window) { |
| return ScheduleInFlightChange( |
| std::make_unique<InFlightDragChange>(window, ChangeType::DRAG_LOOP)); |
| } |
| |
| uint32_t WindowTreeClient::CreateChangeIdForCapture(WindowMus* window) { |
| return ScheduleInFlightChange(std::make_unique<InFlightCaptureChange>( |
| this, capture_synchronizer_.get(), window)); |
| } |
| |
| uint32_t WindowTreeClient::CreateChangeIdForFocus(WindowMus* window) { |
| return ScheduleInFlightChange(std::make_unique<InFlightFocusChange>( |
| this, focus_synchronizer_.get(), window)); |
| } |
| |
| } // namespace aura |