| // 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 "services/ui/public/cpp/window_tree_client.h" |
| |
| #include <stddef.h> |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "services/ui/common/util.h" |
| #include "services/ui/public/cpp/in_flight_change.h" |
| #include "services/ui/public/cpp/input_event_handler.h" |
| #include "services/ui/public/cpp/surface_id_handler.h" |
| #include "services/ui/public/cpp/window_drop_target.h" |
| #include "services/ui/public/cpp/window_manager_delegate.h" |
| #include "services/ui/public/cpp/window_observer.h" |
| #include "services/ui/public/cpp/window_private.h" |
| #include "services/ui/public/cpp/window_tracker.h" |
| #include "services/ui/public/cpp/window_tree_client_delegate.h" |
| #include "services/ui/public/cpp/window_tree_client_observer.h" |
| #include "services/ui/public/interfaces/constants.mojom.h" |
| #include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h" |
| #include "ui/display/screen.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 ui { |
| |
| Id MakeTransportId(ClientSpecificId client_id, ClientSpecificId local_id) { |
| return (client_id << 16) | local_id; |
| } |
| |
| // Helper function to get the device_scale_factor() of the display::Display |
| // with |display_id|. |
| float ScaleFactorForDisplay(int64_t display_id) { |
| // TODO(jonross): Remove this once aura-mus is complete. Currently the screen |
| // is not being set properly for mus-in-renderer. (http://crbug.com/659155) |
| if (!display::Screen::GetScreen()) |
| return 1.f; |
| |
| // TODO(riajiang): Change to use display::GetDisplayWithDisplayId() after |
| // https://codereview.chromium.org/2361283002/ is landed. |
| std::vector<display::Display> displays = |
| display::Screen::GetScreen()->GetAllDisplays(); |
| auto iter = std::find_if(displays.begin(), displays.end(), |
| [display_id](const display::Display& display) { |
| return display.id() == display_id; |
| }); |
| if (iter != displays.end()) |
| return iter->device_scale_factor(); |
| return 1.f; |
| } |
| |
| // Helper called to construct a local window object from transport data. |
| Window* AddWindowToClient(WindowTreeClient* client, |
| Window* parent, |
| const mojom::WindowDataPtr& window_data) { |
| // We don't use the ctor that takes a WindowTreeClient here, since it will |
| // call back to the service and attempt to create a new window. |
| Window* window = WindowPrivate::LocalCreate(); |
| WindowPrivate private_window(window); |
| private_window.set_client(client); |
| private_window.set_server_id(window_data->window_id); |
| private_window.set_visible(window_data->visible); |
| private_window.set_properties( |
| mojo::UnorderedMapToMap(window_data->properties)); |
| client->AddWindow(window); |
| private_window.LocalSetBounds( |
| gfx::Rect(), |
| gfx::ConvertRectToDIP(ScaleFactorForDisplay(window->display_id()), |
| window_data->bounds)); |
| if (parent) |
| WindowPrivate(parent).LocalAddChild(window); |
| return window; |
| } |
| |
| struct WindowTreeClient::CurrentDragState { |
| // The current change id of the current drag an drop ipc. |
| uint32_t change_id; |
| |
| // The effect to return when we send our finish signal. |
| uint32_t completed_action; |
| |
| // Callback executed when a drag initiated by PerformDragDrop() is completed. |
| base::Callback<void(bool, uint32_t)> on_finished; |
| }; |
| |
| WindowTreeClient::WindowTreeClient( |
| WindowTreeClientDelegate* delegate, |
| WindowManagerDelegate* window_manager_delegate, |
| mojo::InterfaceRequest<mojom::WindowTreeClient> request) |
| : client_id_(0), |
| next_window_id_(1), |
| next_change_id_(1), |
| delegate_(delegate), |
| window_manager_delegate_(window_manager_delegate), |
| capture_window_(nullptr), |
| focused_window_(nullptr), |
| binding_(this), |
| tree_(nullptr), |
| in_destructor_(false), |
| weak_factory_(this) { |
| // Allow for a null request in tests. |
| if (request.is_pending()) |
| binding_.Bind(std::move(request)); |
| if (window_manager_delegate) |
| window_manager_delegate->SetWindowManagerClient(this); |
| } |
| |
| WindowTreeClient::~WindowTreeClient() { |
| in_destructor_ = true; |
| |
| for (auto& observer : observers_) |
| observer.OnWillDestroyClient(this); |
| |
| std::vector<Window*> non_owned; |
| WindowTracker tracker; |
| while (!windows_.empty()) { |
| IdToWindowMap::iterator it = windows_.begin(); |
| if (it->second->WasCreatedByThisClient()) { |
| it->second->Destroy(); |
| } else { |
| tracker.Add(it->second); |
| windows_.erase(it); |
| } |
| } |
| |
| // Delete the non-owned windows last. In the typical case these are roots. The |
| // exception is the window manager and embed roots, which may know about |
| // other random windows that it doesn't own. |
| // NOTE: we manually delete as we're a friend. |
| while (!tracker.windows().empty()) |
| delete tracker.windows().front(); |
| |
| for (auto& observer : observers_) |
| observer.OnDidDestroyClient(this); |
| } |
| |
| void WindowTreeClient::ConnectViaWindowTreeFactory( |
| service_manager::Connector* connector) { |
| // The client id doesn't really matter, we use 101 purely for debugging. |
| client_id_ = 101; |
| |
| mojom::WindowTreeFactoryPtr factory; |
| connector->ConnectToInterface(ui::mojom::kServiceName, &factory); |
| mojom::WindowTreePtr window_tree; |
| factory->CreateWindowTree(GetProxy(&window_tree), |
| binding_.CreateInterfacePtrAndBind()); |
| SetWindowTree(std::move(window_tree)); |
| } |
| |
| void WindowTreeClient::ConnectAsWindowManager( |
| service_manager::Connector* connector) { |
| DCHECK(window_manager_delegate_); |
| |
| mojom::WindowManagerWindowTreeFactoryPtr factory; |
| connector->ConnectToInterface(ui::mojom::kServiceName, &factory); |
| mojom::WindowTreePtr window_tree; |
| factory->CreateWindowTree(GetProxy(&window_tree), |
| binding_.CreateInterfacePtrAndBind()); |
| SetWindowTree(std::move(window_tree)); |
| } |
| |
| void WindowTreeClient::WaitForEmbed() { |
| DCHECK(roots_.empty()); |
| // OnEmbed() is the first function called. |
| binding_.WaitForIncomingMethodCall(); |
| // TODO(sky): deal with pipe being closed before we get OnEmbed(). |
| } |
| |
| void WindowTreeClient::DestroyWindow(Window* window) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<CrashInFlightChange>(window, ChangeType::DELETE_WINDOW)); |
| tree_->DeleteWindow(change_id, server_id(window)); |
| } |
| |
| void WindowTreeClient::AddChild(Window* parent, Id child_id) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<CrashInFlightChange>(parent, ChangeType::ADD_CHILD)); |
| tree_->AddWindow(change_id, parent->server_id(), child_id); |
| } |
| |
| void WindowTreeClient::RemoveChild(Window* parent, Id child_id) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<CrashInFlightChange>(parent, ChangeType::REMOVE_CHILD)); |
| tree_->RemoveWindowFromParent(change_id, child_id); |
| } |
| |
| void WindowTreeClient::AddTransientWindow(Window* window, |
| Id transient_window_id) { |
| DCHECK(tree_); |
| const uint32_t change_id = |
| ScheduleInFlightChange(base::MakeUnique<CrashInFlightChange>( |
| window, ChangeType::ADD_TRANSIENT_WINDOW)); |
| tree_->AddTransientWindow(change_id, server_id(window), transient_window_id); |
| } |
| |
| void WindowTreeClient::RemoveTransientWindowFromParent(Window* window) { |
| DCHECK(tree_); |
| const uint32_t change_id = |
| ScheduleInFlightChange(base::MakeUnique<CrashInFlightChange>( |
| window, ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)); |
| tree_->RemoveTransientWindowFromParent(change_id, server_id(window)); |
| } |
| |
| void WindowTreeClient::SetModal(Window* window) { |
| DCHECK(tree_); |
| const uint32_t change_id = |
| ScheduleInFlightChange(base::MakeUnique<InFlightSetModalChange>(window)); |
| tree_->SetModal(change_id, server_id(window)); |
| } |
| |
| void WindowTreeClient::Reorder(Window* window, |
| Id relative_window_id, |
| mojom::OrderDirection direction) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<CrashInFlightChange>(window, ChangeType::REORDER)); |
| tree_->ReorderWindow(change_id, server_id(window), relative_window_id, |
| direction); |
| } |
| |
| bool WindowTreeClient::WasCreatedByThisClient(const Window* window) const { |
| // Windows created via CreateTopLevelWindow() are not owned by us, but have |
| // our client id. const_cast is required by set. |
| return HiWord(server_id(window)) == client_id_ && |
| roots_.count(const_cast<Window*>(window)) == 0; |
| } |
| |
| void WindowTreeClient::SetBounds(Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& bounds) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<InFlightBoundsChange>(window, old_bounds)); |
| tree_->SetWindowBounds( |
| change_id, server_id(window), |
| gfx::ConvertRectToPixel(ScaleFactorForDisplay(window->display_id()), |
| bounds)); |
| } |
| |
| void WindowTreeClient::SetCapture(Window* window) { |
| // In order for us to get here we had to have exposed a window, which implies |
| // we got a client. |
| DCHECK(tree_); |
| if (capture_window_ == window) |
| return; |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<InFlightCaptureChange>(this, capture_window_)); |
| tree_->SetCapture(change_id, server_id(window)); |
| LocalSetCapture(window); |
| } |
| |
| void WindowTreeClient::ReleaseCapture(Window* window) { |
| // In order for us to get here we had to have exposed a window, which implies |
| // we got a client. |
| DCHECK(tree_); |
| if (capture_window_ != window) |
| return; |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<InFlightCaptureChange>(this, window)); |
| tree_->ReleaseCapture(change_id, server_id(window)); |
| LocalSetCapture(nullptr); |
| } |
| |
| void WindowTreeClient::SetClientArea( |
| Id window_id, |
| const gfx::Insets& client_area, |
| const std::vector<gfx::Rect>& additional_client_areas) { |
| DCHECK(tree_); |
| float device_scale_factor = |
| ScaleFactorForDisplay(GetWindowByServerId(window_id)->display_id()); |
| 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_id, gfx::ConvertInsetsToPixel(device_scale_factor, client_area), |
| additional_client_areas_in_pixel); |
| } |
| |
| void WindowTreeClient::SetHitTestMask(Id window_id, const gfx::Rect& mask) { |
| DCHECK(tree_); |
| tree_->SetHitTestMask( |
| window_id, |
| gfx::ConvertRectToPixel( |
| ScaleFactorForDisplay(GetWindowByServerId(window_id)->display_id()), |
| mask)); |
| } |
| |
| void WindowTreeClient::ClearHitTestMask(Id window_id) { |
| DCHECK(tree_); |
| tree_->SetHitTestMask(window_id, base::nullopt); |
| } |
| |
| void WindowTreeClient::SetFocus(Window* window) { |
| // In order for us to get here we had to have exposed a window, which implies |
| // we got a client. |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<InFlightFocusChange>(this, focused_window_)); |
| tree_->SetFocus(change_id, window ? server_id(window) : 0); |
| LocalSetFocus(window); |
| } |
| |
| void WindowTreeClient::SetCanFocus(Id window_id, bool can_focus) { |
| DCHECK(tree_); |
| tree_->SetCanFocus(window_id, can_focus); |
| } |
| |
| void WindowTreeClient::SetPredefinedCursor(Id window_id, |
| ui::mojom::Cursor cursor_id) { |
| DCHECK(tree_); |
| |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| // We make an inflight change thing here. |
| const uint32_t change_id = |
| ScheduleInFlightChange(base::MakeUnique<InFlightPredefinedCursorChange>( |
| window, window->predefined_cursor())); |
| tree_->SetPredefinedCursor(change_id, window_id, cursor_id); |
| } |
| |
| void WindowTreeClient::SetVisible(Window* window, bool visible) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<InFlightVisibleChange>(window, !visible)); |
| tree_->SetWindowVisibility(change_id, server_id(window), visible); |
| } |
| |
| void WindowTreeClient::SetOpacity(Window* window, float opacity) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| base::MakeUnique<InFlightOpacityChange>(window, window->opacity())); |
| tree_->SetWindowOpacity(change_id, server_id(window), opacity); |
| } |
| |
| void WindowTreeClient::SetProperty( |
| Window* window, |
| const std::string& name, |
| const base::Optional<std::vector<uint8_t>>& data) { |
| DCHECK(tree_); |
| |
| base::Optional<std::vector<uint8_t>> old_value; |
| if (window->HasSharedProperty(name)) |
| old_value.emplace(window->properties_[name]); |
| |
| const uint32_t change_id = |
| ScheduleInFlightChange(base::MakeUnique<InFlightPropertyChange>( |
| window, name, std::move(old_value))); |
| tree_->SetWindowProperty(change_id, server_id(window), name, data); |
| } |
| |
| void WindowTreeClient::SetWindowTextInputState( |
| Id window_id, |
| mojo::TextInputStatePtr state) { |
| DCHECK(tree_); |
| tree_->SetWindowTextInputState(window_id, std::move(state)); |
| } |
| |
| void WindowTreeClient::SetImeVisibility(Id window_id, |
| bool visible, |
| mojo::TextInputStatePtr state) { |
| DCHECK(tree_); |
| tree_->SetImeVisibility(window_id, visible, std::move(state)); |
| } |
| |
| void WindowTreeClient::Embed(Id window_id, |
| mojom::WindowTreeClientPtr client, |
| uint32_t flags, |
| const mojom::WindowTree::EmbedCallback& callback) { |
| DCHECK(tree_); |
| tree_->Embed(window_id, std::move(client), flags, callback); |
| } |
| |
| void WindowTreeClient::RequestClose(Window* window) { |
| if (window_manager_internal_client_) |
| window_manager_internal_client_->WmRequestClose(server_id(window)); |
| } |
| |
| void WindowTreeClient::AttachCompositorFrameSink( |
| Id window_id, |
| mojom::CompositorFrameSinkType type, |
| cc::mojom::MojoCompositorFrameSinkRequest compositor_frame_sink, |
| cc::mojom::MojoCompositorFrameSinkClientPtr client) { |
| DCHECK(tree_); |
| tree_->AttachCompositorFrameSink( |
| window_id, type, std::move(compositor_frame_sink), std::move(client)); |
| } |
| |
| void WindowTreeClient::LocalSetCapture(Window* window) { |
| if (capture_window_ == window) |
| return; |
| Window* lost_capture = capture_window_; |
| capture_window_ = window; |
| if (lost_capture) { |
| for (auto& observer : *WindowPrivate(lost_capture).observers()) |
| observer.OnWindowLostCapture(lost_capture); |
| } |
| for (auto& observer : observers_) |
| observer.OnWindowTreeCaptureChanged(window, lost_capture); |
| } |
| |
| void WindowTreeClient::LocalSetFocus(Window* focused) { |
| Window* blurred = focused_window_; |
| // Update |focused_window_| before calling any of the observers, so that the |
| // observers get the correct result from calling |Window::HasFocus()|, |
| // |WindowTreeClient::GetFocusedWindow()| etc. |
| focused_window_ = focused; |
| if (blurred) { |
| for (auto& observer : *WindowPrivate(blurred).observers()) |
| observer.OnWindowFocusChanged(focused, blurred); |
| } |
| if (focused) { |
| for (auto& observer : *WindowPrivate(focused).observers()) |
| observer.OnWindowFocusChanged(focused, blurred); |
| } |
| for (auto& observer : observers_) |
| observer.OnWindowTreeFocusChanged(focused, blurred); |
| } |
| |
| void WindowTreeClient::AddWindow(Window* window) { |
| DCHECK(windows_.find(server_id(window)) == windows_.end()); |
| windows_[server_id(window)] = window; |
| } |
| |
| void WindowTreeClient::OnWindowDestroying(Window* window) { |
| if (window == capture_window_) { |
| // Normally the queue updates itself upon window destruction. However since |
| // |window| is being destroyed, it will not be possible to notify its |
| // observers of the lost capture. Update local state now. |
| LocalSetCapture(nullptr); |
| } |
| // For |focused_window_| window destruction clears the entire focus state. |
| } |
| |
| void WindowTreeClient::OnWindowDestroyed(Window* window) { |
| windows_.erase(server_id(window)); |
| |
| for (auto& entry : embedded_windows_) { |
| auto it = entry.second.find(window); |
| 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); |
| |
| const bool was_root = roots_.erase(window) > 0; |
| if (!in_destructor_ && was_root && roots_.empty() && is_from_embed_) |
| delegate_->OnEmbedRootDestroyed(window); |
| } |
| |
| Window* WindowTreeClient::GetWindowByServerId(Id id) { |
| IdToWindowMap::const_iterator it = windows_.find(id); |
| return it != windows_.end() ? it->second : NULL; |
| } |
| |
| 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); |
| const uint32_t change_id = next_change_id_++; |
| in_flight_map_[change_id] = std::move(change); |
| 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<mojom::WindowDataPtr>& windows, |
| Window* initial_parent) { |
| for (const auto& window_data : windows) { |
| Window* parent = window_data->parent_id == 0 |
| ? nullptr |
| : GetWindowByServerId(window_data->parent_id); |
| Window* existing_window = GetWindowByServerId(window_data->window_id); |
| if (!existing_window) |
| AddWindowToClient(this, parent, window_data); |
| else if (parent) |
| WindowPrivate(parent).LocalAddChild(existing_window); |
| } |
| } |
| |
| Window* WindowTreeClient::NewWindowImpl( |
| NewWindowType type, |
| const Window::SharedProperties* properties) { |
| DCHECK(tree_); |
| Window* window = |
| new Window(this, MakeTransportId(client_id_, next_window_id_++)); |
| if (properties) |
| window->properties_ = *properties; |
| AddWindow(window); |
| |
| const uint32_t change_id = |
| ScheduleInFlightChange(base::MakeUnique<CrashInFlightChange>( |
| window, type == NewWindowType::CHILD |
| ? ChangeType::NEW_WINDOW |
| : ChangeType::NEW_TOP_LEVEL_WINDOW)); |
| std::unordered_map<std::string, std::vector<uint8_t>> transport_properties; |
| if (properties) |
| transport_properties = mojo::MapToUnorderedMap(*properties); |
| |
| if (type == NewWindowType::CHILD) { |
| tree_->NewWindow(change_id, server_id(window), |
| std::move(transport_properties)); |
| } else { |
| roots_.insert(window); |
| tree_->NewTopLevelWindow(change_id, server_id(window), |
| transport_properties); |
| } |
| return window; |
| } |
| |
| void WindowTreeClient::SetWindowTree(mojom::WindowTreePtr window_tree_ptr) { |
| tree_ptr_ = std::move(window_tree_ptr); |
| tree_ = 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(GetProxy(&window_manager_internal_client_, |
| tree_ptr_.associated_group())); |
| } |
| } |
| |
| void WindowTreeClient::OnConnectionLost() { |
| delegate_->OnLostConnection(this); |
| } |
| |
| void WindowTreeClient::OnEmbedImpl(mojom::WindowTree* window_tree, |
| ClientSpecificId client_id, |
| mojom::WindowDataPtr root_data, |
| int64_t display_id, |
| Id focused_window_id, |
| bool drawn) { |
| // WARNING: this is only called if WindowTreeClient was created as the |
| // result of an embedding. |
| tree_ = window_tree; |
| client_id_ = client_id; |
| |
| DCHECK(roots_.empty()); |
| Window* root = AddWindowToClient(this, nullptr, root_data); |
| WindowPrivate(root).LocalSetDisplay(display_id); |
| roots_.insert(root); |
| |
| focused_window_ = GetWindowByServerId(focused_window_id); |
| |
| WindowPrivate(root).LocalSetParentDrawn(drawn); |
| |
| delegate_->OnEmbed(root); |
| |
| if (focused_window_) { |
| for (auto& observer : observers_) |
| observer.OnWindowTreeFocusChanged(focused_window_, nullptr); |
| } |
| } |
| |
| void WindowTreeClient::WmNewDisplayAddedImpl(const display::Display& display, |
| mojom::WindowDataPtr root_data, |
| bool parent_drawn) { |
| DCHECK(window_manager_delegate_); |
| |
| Window* root = AddWindowToClient(this, nullptr, root_data); |
| WindowPrivate(root).LocalSetDisplay(display.id()); |
| WindowPrivate(root).LocalSetParentDrawn(parent_drawn); |
| roots_.insert(root); |
| |
| window_manager_delegate_->OnWmNewDisplay(root, display); |
| } |
| |
| void WindowTreeClient::OnReceivedCursorLocationMemory( |
| mojo::ScopedSharedBufferHandle handle) { |
| cursor_location_mapping_ = handle->Map(sizeof(base::subtle::Atomic32)); |
| DCHECK(cursor_location_mapping_); |
| } |
| |
| void WindowTreeClient::OnWmMoveLoopCompleted(uint32_t change_id, |
| bool completed) { |
| if (window_manager_internal_client_) |
| window_manager_internal_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; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WindowTreeClient, WindowTreeClient implementation: |
| |
| const std::set<Window*>& WindowTreeClient::GetRoots() { |
| return roots_; |
| } |
| |
| Window* WindowTreeClient::GetFocusedWindow() { |
| return focused_window_; |
| } |
| |
| void WindowTreeClient::ClearFocus() { |
| if (!focused_window_) |
| return; |
| |
| SetFocus(nullptr); |
| } |
| |
| 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::PerformDragDrop( |
| Window* window, |
| const std::map<std::string, std::vector<uint8_t>>& drag_data, |
| int drag_operation, |
| const gfx::Point& cursor_location, |
| const SkBitmap& bitmap, |
| const base::Callback<void(bool, uint32_t)>& callback) { |
| DCHECK(!current_drag_state_); |
| |
| // TODO(erg): Pass |cursor_location| and |bitmap| in PerformDragDrop() when |
| // we start showing an image representation of the drag under the cursor. |
| |
| auto unordered_drag_data = mojo::MapToUnorderedMap(drag_data); |
| |
| if (window->drop_target()) { |
| // To minimize the number of round trips, copy the drag drop data to our |
| // handler here, instead of forcing mus to send this same data back. |
| OnDragDropStart(unordered_drag_data); |
| } |
| |
| uint32_t current_drag_change = ScheduleInFlightChange( |
| base::MakeUnique<InFlightDragChange>(window, ChangeType::DRAG_LOOP)); |
| current_drag_state_.reset(new CurrentDragState{ |
| current_drag_change, ui::mojom::kDropEffectNone, callback}); |
| |
| tree_->PerformDragDrop(current_drag_change, window->server_id(), |
| unordered_drag_data, drag_operation); |
| } |
| |
| void WindowTreeClient::CancelDragDrop(Window* window) { |
| // Server will clean up drag and fail the in-flight change. |
| tree_->CancelDragDrop(window->server_id()); |
| } |
| |
| void WindowTreeClient::PerformWindowMove( |
| Window* window, |
| 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; |
| |
| current_move_loop_change_ = ScheduleInFlightChange( |
| base::MakeUnique<InFlightDragChange>(window, ChangeType::MOVE_LOOP)); |
| // Tell the window manager to take over moving us. |
| tree_->PerformWindowMove(current_move_loop_change_, window->server_id(), |
| source, cursor_location); |
| } |
| |
| void WindowTreeClient::CancelWindowMove(Window* window) { |
| tree_->CancelWindowMove(window->server_id()); |
| } |
| |
| Window* WindowTreeClient::NewWindow( |
| const Window::SharedProperties* properties) { |
| return NewWindowImpl(NewWindowType::CHILD, properties); |
| } |
| |
| Window* WindowTreeClient::NewTopLevelWindow( |
| const Window::SharedProperties* properties) { |
| Window* window = NewWindowImpl(NewWindowType::TOP_LEVEL, properties); |
| // Assume newly created top level windows are drawn by default, otherwise |
| // requests to focus will fail. We will get the real value in |
| // OnTopLevelCreated(). |
| window->LocalSetParentDrawn(true); |
| return window; |
| } |
| |
| #if !defined(NDEBUG) |
| std::string WindowTreeClient::GetDebugWindowHierarchy() const { |
| std::string result; |
| for (Window* root : roots_) |
| BuildDebugInfo(std::string(), root, &result); |
| return result; |
| } |
| |
| void WindowTreeClient::BuildDebugInfo(const std::string& depth, |
| Window* window, |
| std::string* result) const { |
| std::string name = window->GetName(); |
| *result += base::StringPrintf( |
| "%sid=%d visible=%s bounds=%d,%d %dx%d %s\n", depth.c_str(), |
| window->server_id(), window->visible() ? "true" : "false", |
| window->bounds().x(), window->bounds().y(), window->bounds().width(), |
| window->bounds().height(), !name.empty() ? name.c_str() : "(no name)"); |
| for (Window* child : window->children()) |
| BuildDebugInfo(depth + " ", child, result); |
| } |
| #endif // !defined(NDEBUG) |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WindowTreeClient, WindowTreeClient implementation: |
| |
| void WindowTreeClient::AddObserver(WindowTreeClientObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void WindowTreeClient::RemoveObserver(WindowTreeClientObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void WindowTreeClient::SetCanAcceptDrops(Id window_id, bool can_accept_drops) { |
| DCHECK(tree_); |
| tree_->SetCanAcceptDrops(window_id, can_accept_drops); |
| } |
| |
| void WindowTreeClient::SetCanAcceptEvents(Id window_id, |
| bool can_accept_events) { |
| DCHECK(tree_); |
| tree_->SetCanAcceptEvents(window_id, can_accept_events); |
| } |
| |
| void WindowTreeClient::OnEmbed(ClientSpecificId client_id, |
| mojom::WindowDataPtr root_data, |
| mojom::WindowTreePtr tree, |
| int64_t display_id, |
| Id focused_window_id, |
| bool drawn) { |
| DCHECK(!tree_ptr_); |
| tree_ptr_ = std::move(tree); |
| |
| is_from_embed_ = true; |
| |
| if (window_manager_delegate_) { |
| tree_ptr_->GetWindowManagerClient(GetProxy(&window_manager_internal_client_, |
| tree_ptr_.associated_group())); |
| } |
| |
| OnEmbedImpl(tree_ptr_.get(), client_id, std::move(root_data), display_id, |
| focused_window_id, drawn); |
| } |
| |
| void WindowTreeClient::OnEmbeddedAppDisconnected(Id window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| if (window) { |
| for (auto& observer : *WindowPrivate(window).observers()) |
| observer.OnWindowEmbeddedAppDisconnected(window); |
| } |
| } |
| |
| void WindowTreeClient::OnUnembed(Id window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| delegate_->OnUnembed(window); |
| WindowPrivate(window).LocalDestroy(); |
| } |
| |
| void WindowTreeClient::OnCaptureChanged(Id new_capture_window_id, |
| Id old_capture_window_id) { |
| Window* new_capture_window = GetWindowByServerId(new_capture_window_id); |
| Window* lost_capture_window = GetWindowByServerId(old_capture_window_id); |
| if (!new_capture_window && !lost_capture_window) |
| return; |
| |
| InFlightCaptureChange change(this, new_capture_window); |
| if (ApplyServerChangeToExistingInFlightChange(change)) |
| return; |
| |
| LocalSetCapture(new_capture_window); |
| } |
| |
| void WindowTreeClient::OnTopLevelCreated(uint32_t change_id, |
| mojom::WindowDataPtr data, |
| int64_t display_id, |
| bool drawn) { |
| // 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); |
| |
| Window* window = change->window(); |
| WindowPrivate window_private(window); |
| |
| // Drawn state and display-id always come from the server (they can't be |
| // modified locally). |
| window_private.LocalSetParentDrawn(drawn); |
| window_private.LocalSetDisplay(display_id); |
| |
| // The default visibilty is false, we only need update visibility if it |
| // differs from that. |
| if (data->visible) { |
| InFlightVisibleChange visible_change(window, data->visible); |
| InFlightChange* current_change = |
| GetOldestInFlightChangeMatching(visible_change); |
| if (current_change) |
| current_change->SetRevertValueFrom(visible_change); |
| else |
| window_private.LocalSetVisible(true); |
| } |
| |
| const gfx::Rect bounds(data->bounds); |
| { |
| InFlightBoundsChange bounds_change(window, bounds); |
| InFlightChange* current_change = |
| GetOldestInFlightChangeMatching(bounds_change); |
| if (current_change) |
| current_change->SetRevertValueFrom(bounds_change); |
| else if (window->bounds() != bounds) |
| window_private.LocalSetBounds(window->bounds(), bounds); |
| } |
| |
| // There is currently no API to bulk set properties, so we iterate over each |
| // property individually. |
| Window::SharedProperties properties = |
| mojo::UnorderedMapToMap(data->properties); |
| for (const auto& pair : properties) { |
| InFlightPropertyChange property_change(window, pair.first, pair.second); |
| InFlightChange* current_change = |
| GetOldestInFlightChangeMatching(property_change); |
| if (current_change) |
| current_change->SetRevertValueFrom(property_change); |
| else |
| window_private.LocalSetSharedProperty(pair.first, &(pair.second)); |
| } |
| |
| // Top level windows should not have a parent. |
| DCHECK_EQ(0u, data->parent_id); |
| } |
| |
| void WindowTreeClient::OnWindowBoundsChanged(Id window_id, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| float device_scale_factor = ScaleFactorForDisplay(window->display_id()); |
| gfx::Rect old_bounds_in_dip = |
| gfx::ConvertRectToDIP(device_scale_factor, old_bounds); |
| gfx::Rect new_bounds_in_dip = |
| gfx::ConvertRectToDIP(device_scale_factor, new_bounds); |
| |
| InFlightBoundsChange new_change(window, new_bounds_in_dip); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| WindowPrivate(window).LocalSetBounds(old_bounds_in_dip, new_bounds_in_dip); |
| } |
| |
| void WindowTreeClient::OnClientAreaChanged( |
| uint32_t window_id, |
| const gfx::Insets& new_client_area, |
| const std::vector<gfx::Rect>& new_additional_client_areas) { |
| Window* window = GetWindowByServerId(window_id); |
| if (window) { |
| float device_scale_factor = ScaleFactorForDisplay(window->display_id()); |
| 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)); |
| } |
| WindowPrivate(window).LocalSetClientArea( |
| gfx::ConvertInsetsToDIP(device_scale_factor, new_client_area), |
| new_additional_client_areas_in_dip); |
| } |
| } |
| |
| void WindowTreeClient::OnTransientWindowAdded( |
| uint32_t window_id, |
| uint32_t transient_window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| Window* 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) |
| WindowPrivate(window).LocalAddTransientWindow(transient_window); |
| } |
| |
| void WindowTreeClient::OnTransientWindowRemoved( |
| uint32_t window_id, |
| uint32_t transient_window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| Window* 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) |
| WindowPrivate(window).LocalRemoveTransientWindow(transient_window); |
| } |
| |
| void WindowTreeClient::OnWindowHierarchyChanged( |
| Id window_id, |
| Id old_parent_id, |
| Id new_parent_id, |
| std::vector<mojom::WindowDataPtr> windows) { |
| Window* initial_parent = |
| windows.size() ? GetWindowByServerId(windows[0]->parent_id) : NULL; |
| |
| const bool was_window_known = GetWindowByServerId(window_id) != nullptr; |
| |
| BuildWindowTree(windows, initial_parent); |
| |
| // If the window was not known, then BuildWindowTree() will have created it |
| // and parented the window. |
| if (!was_window_known) |
| return; |
| |
| Window* new_parent = GetWindowByServerId(new_parent_id); |
| Window* old_parent = GetWindowByServerId(old_parent_id); |
| Window* window = GetWindowByServerId(window_id); |
| if (new_parent) |
| WindowPrivate(new_parent).LocalAddChild(window); |
| else |
| WindowPrivate(old_parent).LocalRemoveChild(window); |
| } |
| |
| void WindowTreeClient::OnWindowReordered(Id window_id, |
| Id relative_window_id, |
| mojom::OrderDirection direction) { |
| Window* window = GetWindowByServerId(window_id); |
| Window* relative_window = GetWindowByServerId(relative_window_id); |
| if (window && relative_window) |
| WindowPrivate(window).LocalReorder(relative_window, direction); |
| } |
| |
| void WindowTreeClient::OnWindowDeleted(Id window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| if (window) |
| WindowPrivate(window).LocalDestroy(); |
| } |
| |
| Window* WindowTreeClient::GetCaptureWindow() { |
| return capture_window_; |
| } |
| |
| void WindowTreeClient::OnWindowVisibilityChanged(Id window_id, |
| bool visible) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightVisibleChange new_change(window, visible); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetVisible(visible); |
| } |
| |
| void WindowTreeClient::OnWindowOpacityChanged(Id window_id, |
| float old_opacity, |
| float new_opacity) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightOpacityChange new_change(window, new_opacity); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetOpacity(new_opacity); |
| } |
| |
| void WindowTreeClient::OnWindowParentDrawnStateChanged(Id window_id, |
| bool drawn) { |
| Window* window = GetWindowByServerId(window_id); |
| if (window) |
| WindowPrivate(window).LocalSetParentDrawn(drawn); |
| } |
| |
| void WindowTreeClient::OnWindowSharedPropertyChanged( |
| Id window_id, |
| const std::string& name, |
| const base::Optional<std::vector<uint8_t>>& new_data) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightPropertyChange new_change(window, name, new_data); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetSharedProperty(name, new_data); |
| } |
| |
| void WindowTreeClient::OnWindowInputEvent(uint32_t event_id, |
| Id window_id, |
| std::unique_ptr<ui::Event> event, |
| bool matches_pointer_watcher) { |
| DCHECK(event); |
| Window* window = GetWindowByServerId(window_id); // May be null. |
| |
| if (matches_pointer_watcher && has_pointer_watcher_) { |
| DCHECK(event->IsPointerEvent()); |
| delegate_->OnPointerEventObserved(*event->AsPointerEvent(), window); |
| } |
| |
| if (!window || !window->input_event_handler_) { |
| tree_->OnWindowInputEventAck(event_id, mojom::EventResult::UNHANDLED); |
| return; |
| } |
| |
| std::unique_ptr<base::Callback<void(mojom::EventResult)>> ack_callback( |
| new base::Callback<void(mojom::EventResult)>( |
| base::Bind(&mojom::WindowTree::OnWindowInputEventAck, |
| base::Unretained(tree_), 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. |
| if (event->IsMousePointerEvent()) { |
| if (event->type() == ui::ET_POINTER_WHEEL_CHANGED) { |
| window->input_event_handler_->OnWindowInputEvent( |
| window, ui::MouseWheelEvent(*event->AsPointerEvent()), &ack_callback); |
| } else { |
| window->input_event_handler_->OnWindowInputEvent( |
| window, ui::MouseEvent(*event->AsPointerEvent()), &ack_callback); |
| } |
| } else if (event->IsTouchPointerEvent()) { |
| window->input_event_handler_->OnWindowInputEvent( |
| window, ui::TouchEvent(*event->AsPointerEvent()), &ack_callback); |
| } else { |
| window->input_event_handler_->OnWindowInputEvent(window, *event.get(), |
| &ack_callback); |
| } |
| |
| // The handler did not take ownership of the callback, so we send the ack, |
| // marking the event as not consumed. |
| if (ack_callback) |
| ack_callback->Run(mojom::EventResult::UNHANDLED); |
| } |
| |
| void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event, |
| uint32_t window_id) { |
| DCHECK(event); |
| DCHECK(event->IsPointerEvent()); |
| if (has_pointer_watcher_) { |
| Window* target_window = GetWindowByServerId(window_id); |
| delegate_->OnPointerEventObserved(*event->AsPointerEvent(), target_window); |
| } |
| } |
| |
| void WindowTreeClient::OnWindowFocused(Id focused_window_id) { |
| Window* focused_window = GetWindowByServerId(focused_window_id); |
| InFlightFocusChange new_change(this, focused_window); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| LocalSetFocus(focused_window); |
| } |
| |
| void WindowTreeClient::OnWindowPredefinedCursorChanged( |
| Id window_id, |
| mojom::Cursor cursor) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| |
| InFlightPredefinedCursorChange new_change(window, cursor); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetPredefinedCursor(cursor); |
| } |
| |
| void WindowTreeClient::OnWindowSurfaceChanged( |
| Id window_id, |
| const cc::SurfaceId& surface_id, |
| const gfx::Size& frame_size, |
| float device_scale_factor) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window) |
| return; |
| std::unique_ptr<SurfaceInfo> surface_info(base::MakeUnique<SurfaceInfo>()); |
| surface_info->surface_id = surface_id; |
| surface_info->frame_size = frame_size; |
| surface_info->device_scale_factor = device_scale_factor; |
| WindowPrivate(window).LocalSetSurfaceId(std::move(surface_info)); |
| } |
| |
| void WindowTreeClient::OnDragDropStart( |
| const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data) { |
| mime_drag_data_ = mojo::UnorderedMapToMap(mime_data); |
| } |
| |
| void WindowTreeClient::OnDragEnter(Id window_id, |
| uint32_t key_state, |
| const gfx::Point& position, |
| uint32_t effect_bitmask, |
| const OnDragEnterCallback& callback) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window || !window->drop_target()) { |
| callback.Run(mojom::kDropEffectNone); |
| return; |
| } |
| |
| if (!base::ContainsKey(drag_entered_windows_, window_id)) { |
| window->drop_target()->OnDragDropStart(mime_drag_data_); |
| drag_entered_windows_.insert(window_id); |
| } |
| |
| uint32_t ret = |
| window->drop_target()->OnDragEnter(key_state, position, effect_bitmask); |
| callback.Run(ret); |
| } |
| |
| void WindowTreeClient::OnDragOver(Id window_id, |
| uint32_t key_state, |
| const gfx::Point& position, |
| uint32_t effect_bitmask, |
| const OnDragOverCallback& callback) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window || !window->drop_target()) { |
| callback.Run(mojom::kDropEffectNone); |
| return; |
| } |
| |
| uint32_t ret = |
| window->drop_target()->OnDragOver(key_state, position, effect_bitmask); |
| callback.Run(ret); |
| } |
| |
| void WindowTreeClient::OnDragLeave(Id window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window || !window->drop_target()) |
| return; |
| |
| window->drop_target()->OnDragLeave(); |
| } |
| |
| void WindowTreeClient::OnDragDropDone() { |
| for (Id id : drag_entered_windows_) { |
| Window* window = GetWindowByServerId(id); |
| if (!window || !window->drop_target()) |
| continue; |
| window->drop_target()->OnDragDropDone(); |
| } |
| drag_entered_windows_.clear(); |
| } |
| |
| void WindowTreeClient::OnCompleteDrop(Id window_id, |
| uint32_t key_state, |
| const gfx::Point& position, |
| uint32_t effect_bitmask, |
| const OnCompleteDropCallback& callback) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window || !window->drop_target()) { |
| callback.Run(mojom::kDropEffectNone); |
| return; |
| } |
| |
| uint32_t ret = window->drop_target()->OnCompleteDrop(key_state, position, |
| effect_bitmask); |
| callback.Run(ret); |
| } |
| |
| void WindowTreeClient::OnPerformDragDropCompleted(uint32_t change_id, |
| bool success, |
| uint32_t action_taken) { |
| if (current_drag_state_ && change_id == current_drag_state_->change_id) { |
| current_drag_state_->completed_action = action_taken; |
| OnChangeCompleted(change_id, success); |
| } |
| } |
| |
| 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; |
| |
| 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(); |
| } |
| |
| if (current_drag_state_ && change_id == current_drag_state_->change_id) { |
| OnDragDropDone(); |
| |
| current_drag_state_->on_finished.Run(success, |
| current_drag_state_->completed_action); |
| current_drag_state_.reset(); |
| } |
| } |
| |
| void WindowTreeClient::GetWindowManager( |
| mojo::AssociatedInterfaceRequest<WindowManager> internal) { |
| window_manager_internal_.reset( |
| new mojo::AssociatedBinding<mojom::WindowManager>(this, |
| std::move(internal))); |
| } |
| |
| void WindowTreeClient::RequestClose(uint32_t window_id) { |
| Window* window = GetWindowByServerId(window_id); |
| if (!window || !IsRoot(window)) |
| return; |
| |
| for (auto& observer : *WindowPrivate(window).observers()) |
| observer.OnRequestClose(window); |
| } |
| |
| void WindowTreeClient::OnConnect(ClientSpecificId client_id) { |
| client_id_ = client_id; |
| } |
| |
| void WindowTreeClient::WmNewDisplayAdded(const display::Display& display, |
| mojom::WindowDataPtr root_data, |
| bool parent_drawn) { |
| WmNewDisplayAddedImpl(display, std::move(root_data), parent_drawn); |
| } |
| |
| void WindowTreeClient::WmDisplayRemoved(int64_t display_id) { |
| DCHECK(window_manager_delegate_); |
| |
| for (Window* root : roots_) { |
| if (root->display_id() == display_id) { |
| window_manager_delegate_->OnWmDisplayRemoved(root); |
| return; |
| } |
| } |
| } |
| |
| void WindowTreeClient::WmDisplayModified(const display::Display& display) { |
| DCHECK(window_manager_delegate_); |
| window_manager_delegate_->OnWmDisplayModified(display); |
| } |
| |
| void WindowTreeClient::WmSetBounds(uint32_t change_id, |
| Id window_id, |
| const gfx::Rect& transit_bounds) { |
| Window* window = GetWindowByServerId(window_id); |
| bool result = false; |
| if (window) { |
| DCHECK(window_manager_delegate_); |
| gfx::Rect transit_bounds_in_dip = gfx::ConvertRectToDIP( |
| ScaleFactorForDisplay(window->display_id()), transit_bounds); |
| gfx::Rect bounds = transit_bounds_in_dip; |
| result = window_manager_delegate_->OnWmSetBounds(window, &bounds); |
| if (result) { |
| // If the resulting bounds differ return false. Returning false ensures |
| // the client applies the bounds we set below. |
| result = bounds == transit_bounds_in_dip; |
| window->SetBounds(bounds); |
| } |
| } |
| if (window_manager_internal_client_) |
| window_manager_internal_client_->WmResponse(change_id, result); |
| } |
| |
| void WindowTreeClient::WmSetProperty( |
| uint32_t change_id, |
| Id window_id, |
| const std::string& name, |
| const base::Optional<std::vector<uint8_t>>& transit_data) { |
| Window* 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, name, &data); |
| if (result) { |
| // If the resulting bounds differ return false. Returning false ensures |
| // the client applies the bounds we set below. |
| window->SetSharedPropertyInternal(name, data.get()); |
| } |
| } |
| if (window_manager_internal_client_) |
| window_manager_internal_client_->WmResponse(change_id, result); |
| } |
| |
| void WindowTreeClient::WmCreateTopLevelWindow( |
| uint32_t change_id, |
| ClientSpecificId requesting_client_id, |
| const std::unordered_map<std::string, std::vector<uint8_t>>& |
| transport_properties) { |
| std::map<std::string, std::vector<uint8_t>> properties = |
| mojo::UnorderedMapToMap(transport_properties); |
| Window* window = |
| window_manager_delegate_->OnWmCreateTopLevelWindow(&properties); |
| embedded_windows_[requesting_client_id].insert(window); |
| if (window_manager_internal_client_) { |
| window_manager_internal_client_->OnWmCreatedTopLevelWindow( |
| change_id, server_id(window)); |
| } |
| } |
| |
| void WindowTreeClient::WmClientJankinessChanged(ClientSpecificId client_id, |
| bool janky) { |
| if (window_manager_delegate_) { |
| auto it = embedded_windows_.find(client_id); |
| CHECK(it != embedded_windows_.end()); |
| window_manager_delegate_->OnWmClientJankinessChanged( |
| embedded_windows_[client_id], janky); |
| } |
| } |
| |
| void WindowTreeClient::WmPerformMoveLoop(uint32_t change_id, |
| Id window_id, |
| 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; |
| Window* window = GetWindowByServerId(window_id); |
| if (window) { |
| window_manager_delegate_->OnWmPerformMoveLoop( |
| window, 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; |
| |
| Window* window = GetWindowByServerId(current_wm_move_loop_window_id_); |
| if (window) |
| window_manager_delegate_->OnWmCancelMoveLoop(window); |
| } |
| |
| void WindowTreeClient::OnAccelerator(uint32_t ack_id, |
| uint32_t accelerator_id, |
| std::unique_ptr<ui::Event> event) { |
| DCHECK(event); |
| const mojom::EventResult result = |
| window_manager_delegate_->OnAccelerator(accelerator_id, *event.get()); |
| if (ack_id && window_manager_internal_client_) |
| window_manager_internal_client_->OnAcceleratorAck(ack_id, result); |
| } |
| |
| void WindowTreeClient::SetFrameDecorationValues( |
| mojom::FrameDecorationValuesPtr values) { |
| if (window_manager_internal_client_) { |
| window_manager_internal_client_->WmSetFrameDecorationValues( |
| std::move(values)); |
| } |
| } |
| |
| void WindowTreeClient::SetNonClientCursor(Window* window, |
| ui::mojom::Cursor cursor_id) { |
| window_manager_internal_client_->WmSetNonClientCursor(server_id(window), |
| cursor_id); |
| } |
| |
| void WindowTreeClient::AddAccelerator( |
| uint32_t id, |
| mojom::EventMatcherPtr event_matcher, |
| const base::Callback<void(bool)>& callback) { |
| if (window_manager_internal_client_) { |
| window_manager_internal_client_->AddAccelerator( |
| id, std::move(event_matcher), callback); |
| } |
| } |
| |
| void WindowTreeClient::RemoveAccelerator(uint32_t id) { |
| if (window_manager_internal_client_) { |
| window_manager_internal_client_->RemoveAccelerator(id); |
| } |
| } |
| |
| void WindowTreeClient::AddActivationParent(Window* window) { |
| if (window_manager_internal_client_) |
| window_manager_internal_client_->AddActivationParent(server_id(window)); |
| } |
| |
| void WindowTreeClient::RemoveActivationParent(Window* window) { |
| if (window_manager_internal_client_) |
| window_manager_internal_client_->RemoveActivationParent(server_id(window)); |
| } |
| |
| void WindowTreeClient::ActivateNextWindow() { |
| if (window_manager_internal_client_) |
| window_manager_internal_client_->ActivateNextWindow(); |
| } |
| |
| void WindowTreeClient::SetUnderlaySurfaceOffsetAndExtendedHitArea( |
| Window* window, |
| const gfx::Vector2d& offset, |
| const gfx::Insets& hit_area) { |
| if (window_manager_internal_client_) { |
| // TODO(riajiang): Figure out if |offset| needs to be converted. |
| // (http://crbugs.com/646932) |
| window_manager_internal_client_->SetUnderlaySurfaceOffsetAndExtendedHitArea( |
| server_id(window), offset.x(), offset.y(), |
| gfx::ConvertInsetsToDIP(ScaleFactorForDisplay(window->display_id()), |
| hit_area)); |
| } |
| } |
| |
| } // namespace ui |