| // 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 "components/mus/public/cpp/lib/window_tree_client_impl.h" |
| |
| #include "base/bind.h" |
| #include "components/mus/common/util.h" |
| #include "components/mus/public/cpp/input_event_handler.h" |
| #include "components/mus/public/cpp/lib/in_flight_change.h" |
| #include "components/mus/public/cpp/lib/window_private.h" |
| #include "components/mus/public/cpp/window_manager_delegate.h" |
| #include "components/mus/public/cpp/window_observer.h" |
| #include "components/mus/public/cpp/window_tree_connection.h" |
| #include "components/mus/public/cpp/window_tree_connection_observer.h" |
| #include "components/mus/public/cpp/window_tree_delegate.h" |
| #include "mojo/application/public/cpp/application_impl.h" |
| #include "mojo/application/public/cpp/connect.h" |
| #include "mojo/application/public/cpp/service_provider_impl.h" |
| #include "mojo/application/public/interfaces/service_provider.mojom.h" |
| #include "mojo/converters/geometry/geometry_type_converters.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace mus { |
| |
| Id MakeTransportId(ConnectionSpecificId connection_id, |
| ConnectionSpecificId local_id) { |
| return (connection_id << 16) | local_id; |
| } |
| |
| // Helper called to construct a local window object from transport data. |
| Window* AddWindowToConnection(WindowTreeClientImpl* client, |
| Window* parent, |
| const mojom::WindowDataPtr& window_data) { |
| // We don't use the cto that takes a WindowTreeConnection 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_connection(client); |
| private_window.set_id(window_data->window_id); |
| private_window.set_visible(window_data->visible); |
| private_window.set_drawn(window_data->drawn); |
| private_window.LocalSetViewportMetrics(mojom::ViewportMetrics(), |
| *window_data->viewport_metrics); |
| private_window.set_properties( |
| window_data->properties |
| .To<std::map<std::string, std::vector<uint8_t>>>()); |
| client->AddWindow(window); |
| private_window.LocalSetBounds(gfx::Rect(), |
| window_data->bounds.To<gfx::Rect>()); |
| if (parent) |
| WindowPrivate(parent).LocalAddChild(window); |
| return window; |
| } |
| |
| Window* BuildWindowTree(WindowTreeClientImpl* client, |
| const mojo::Array<mojom::WindowDataPtr>& windows, |
| Window* initial_parent) { |
| std::vector<Window*> parents; |
| Window* root = NULL; |
| Window* last_window = NULL; |
| if (initial_parent) |
| parents.push_back(initial_parent); |
| for (size_t i = 0; i < windows.size(); ++i) { |
| if (last_window && windows[i]->parent_id == last_window->id()) { |
| parents.push_back(last_window); |
| } else if (!parents.empty()) { |
| while (parents.back()->id() != windows[i]->parent_id) |
| parents.pop_back(); |
| } |
| Window* window = AddWindowToConnection( |
| client, !parents.empty() ? parents.back() : NULL, windows[i]); |
| if (!last_window) |
| root = window; |
| last_window = window; |
| } |
| return root; |
| } |
| |
| WindowTreeConnection* WindowTreeConnection::Create( |
| WindowTreeDelegate* delegate, |
| mojo::InterfaceRequest<mojom::WindowTreeClient> request, |
| CreateType create_type) { |
| WindowTreeClientImpl* client = |
| new WindowTreeClientImpl(delegate, nullptr, std::move(request)); |
| if (create_type == CreateType::WAIT_FOR_EMBED) |
| client->WaitForEmbed(); |
| return client; |
| } |
| |
| WindowTreeConnection* WindowTreeConnection::CreateForWindowManager( |
| WindowTreeDelegate* delegate, |
| mojo::InterfaceRequest<mojom::WindowTreeClient> request, |
| CreateType create_type, |
| WindowManagerDelegate* window_manager_delegate) { |
| WindowTreeClientImpl* client = new WindowTreeClientImpl( |
| delegate, window_manager_delegate, std::move(request)); |
| if (create_type == CreateType::WAIT_FOR_EMBED) |
| client->WaitForEmbed(); |
| return client; |
| } |
| |
| WindowTreeClientImpl::WindowTreeClientImpl( |
| WindowTreeDelegate* delegate, |
| WindowManagerDelegate* window_manager_delegate, |
| mojo::InterfaceRequest<mojom::WindowTreeClient> request) |
| : connection_id_(0), |
| next_window_id_(1), |
| next_change_id_(1), |
| delegate_(delegate), |
| window_manager_delegate_(window_manager_delegate), |
| root_(nullptr), |
| focused_window_(nullptr), |
| binding_(this), |
| tree_(nullptr), |
| is_embed_root_(false), |
| in_destructor_(false) { |
| // Allow for a null request in tests. |
| if (request.is_pending()) |
| binding_.Bind(std::move(request)); |
| } |
| |
| WindowTreeClientImpl::~WindowTreeClientImpl() { |
| in_destructor_ = true; |
| |
| std::vector<Window*> non_owned; |
| while (!windows_.empty()) { |
| IdToWindowMap::iterator it = windows_.begin(); |
| if (OwnsWindow(it->second->id())) { |
| it->second->Destroy(); |
| } else { |
| non_owned.push_back(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. |
| for (size_t i = 0; i < non_owned.size(); ++i) |
| delete non_owned[i]; |
| |
| delegate_->OnConnectionLost(this); |
| } |
| |
| void WindowTreeClientImpl::WaitForEmbed() { |
| DCHECK(!root_); |
| // OnEmbed() is the first function called. |
| binding_.WaitForIncomingMethodCall(); |
| // TODO(sky): deal with pipe being closed before we get OnEmbed(). |
| } |
| |
| void WindowTreeClientImpl::DestroyWindow(Window* window) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr( |
| new CrashInFlightChange(window, ChangeType::DELETE_WINDOW))); |
| tree_->DeleteWindow(change_id, window->id()); |
| } |
| |
| void WindowTreeClientImpl::AddChild(Window* parent, Id child_id) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new CrashInFlightChange(parent, ChangeType::ADD_CHILD))); |
| tree_->AddWindow(change_id, parent->id(), child_id); |
| } |
| |
| void WindowTreeClientImpl::RemoveChild(Window* parent, Id child_id) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr( |
| new CrashInFlightChange(parent, ChangeType::REMOVE_CHILD))); |
| tree_->RemoveWindowFromParent(change_id, child_id); |
| } |
| |
| void WindowTreeClientImpl::AddTransientWindow(Window* window, |
| Id transient_window_id) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr( |
| new CrashInFlightChange(window, ChangeType::ADD_TRANSIENT_WINDOW))); |
| tree_->AddTransientWindow(change_id, window->id(), transient_window_id); |
| } |
| |
| void WindowTreeClientImpl::RemoveTransientWindowFromParent(Window* window) { |
| DCHECK(tree_); |
| const uint32_t change_id = |
| ScheduleInFlightChange(make_scoped_ptr(new CrashInFlightChange( |
| window, ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT))); |
| tree_->RemoveTransientWindowFromParent(change_id, window->id()); |
| } |
| |
| void WindowTreeClientImpl::Reorder(Window* window, |
| Id relative_window_id, |
| mojom::OrderDirection direction) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new CrashInFlightChange(window, ChangeType::REORDER))); |
| tree_->ReorderWindow(change_id, window->id(), relative_window_id, direction); |
| } |
| |
| bool WindowTreeClientImpl::OwnsWindow(Id id) const { |
| return HiWord(id) == connection_id_; |
| } |
| |
| void WindowTreeClientImpl::SetBounds(Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& bounds) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new InFlightBoundsChange(window, old_bounds))); |
| tree_->SetWindowBounds(change_id, window->id(), mojo::Rect::From(bounds)); |
| } |
| |
| void WindowTreeClientImpl::SetClientArea( |
| Id window_id, |
| const gfx::Insets& client_area, |
| const std::vector<gfx::Rect>& additional_client_areas) { |
| DCHECK(tree_); |
| tree_->SetClientArea( |
| window_id, mojo::Insets::From(client_area), |
| mojo::Array<mojo::RectPtr>::From(additional_client_areas)); |
| } |
| |
| void WindowTreeClientImpl::SetFocus(Window* window) { |
| // In order for us to get here we had to have exposed a window, which implies |
| // we got a connection. |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new InFlightFocusChange(this, focused_window_))); |
| tree_->SetFocus(change_id, window ? window->id() : 0); |
| LocalSetFocus(window); |
| } |
| |
| void WindowTreeClientImpl::SetCanFocus(Id window_id, bool can_focus) { |
| DCHECK(tree_); |
| tree_->SetCanFocus(window_id, can_focus); |
| } |
| |
| void WindowTreeClientImpl::SetPredefinedCursor(Id window_id, |
| mus::mojom::Cursor cursor_id) { |
| DCHECK(tree_); |
| |
| Window* window = GetWindowById(window_id); |
| if (!window) |
| return; |
| |
| // We make an inflight change thing here. |
| const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr( |
| new InFlightPredefinedCursorChange(window, window->predefined_cursor()))); |
| tree_->SetPredefinedCursor(change_id, window_id, cursor_id); |
| } |
| |
| void WindowTreeClientImpl::SetVisible(Window* window, bool visible) { |
| DCHECK(tree_); |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new InFlightVisibleChange(window, !visible))); |
| tree_->SetWindowVisibility(change_id, window->id(), visible); |
| } |
| |
| void WindowTreeClientImpl::SetProperty(Window* window, |
| const std::string& name, |
| mojo::Array<uint8_t> data) { |
| DCHECK(tree_); |
| |
| mojo::Array<uint8_t> old_value; |
| if (window->HasSharedProperty(name)) |
| old_value = mojo::Array<uint8_t>::From(window->properties_[name]); |
| |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new InFlightPropertyChange(window, name, old_value))); |
| tree_->SetWindowProperty(change_id, window->id(), mojo::String(name), |
| std::move(data)); |
| } |
| |
| void WindowTreeClientImpl::SetWindowTextInputState( |
| Id window_id, |
| mojo::TextInputStatePtr state) { |
| DCHECK(tree_); |
| tree_->SetWindowTextInputState(window_id, std::move(state)); |
| } |
| |
| void WindowTreeClientImpl::SetImeVisibility(Id window_id, |
| bool visible, |
| mojo::TextInputStatePtr state) { |
| DCHECK(tree_); |
| tree_->SetImeVisibility(window_id, visible, std::move(state)); |
| } |
| |
| void WindowTreeClientImpl::Embed( |
| Id window_id, |
| mojom::WindowTreeClientPtr client, |
| uint32_t policy_bitmask, |
| const mojom::WindowTree::EmbedCallback& callback) { |
| DCHECK(tree_); |
| tree_->Embed(window_id, std::move(client), policy_bitmask, callback); |
| } |
| |
| void WindowTreeClientImpl::AttachSurface( |
| Id window_id, |
| mojom::SurfaceType type, |
| mojo::InterfaceRequest<mojom::Surface> surface, |
| mojom::SurfaceClientPtr client) { |
| DCHECK(tree_); |
| tree_->AttachSurface(window_id, type, std::move(surface), std::move(client)); |
| } |
| |
| void WindowTreeClientImpl::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()|, |
| // |WindowTreeConnection::GetFocusedWindow()| etc. |
| focused_window_ = focused; |
| if (blurred) { |
| FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(blurred).observers(), |
| OnWindowFocusChanged(focused, blurred)); |
| } |
| if (focused) { |
| FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(focused).observers(), |
| OnWindowFocusChanged(focused, blurred)); |
| } |
| FOR_EACH_OBSERVER(WindowTreeConnectionObserver, observers_, |
| OnWindowTreeFocusChanged(focused, blurred)); |
| } |
| |
| void WindowTreeClientImpl::AddWindow(Window* window) { |
| DCHECK(windows_.find(window->id()) == windows_.end()); |
| windows_[window->id()] = window; |
| } |
| |
| void WindowTreeClientImpl::OnWindowDestroyed(Window* window) { |
| windows_.erase(window->id()); |
| |
| // 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); |
| |
| if (window == root_) { |
| root_ = nullptr; |
| |
| // When the root is gone we can't do anything useful. |
| if (!in_destructor_) |
| delete this; |
| } |
| } |
| |
| InFlightChange* WindowTreeClientImpl::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 WindowTreeClientImpl::ScheduleInFlightChange( |
| scoped_ptr<InFlightChange> change) { |
| DCHECK(!change->window() || windows_.count(change->window()->id()) > 0); |
| const uint32_t change_id = next_change_id_++; |
| in_flight_map_[change_id] = std::move(change); |
| return change_id; |
| } |
| |
| bool WindowTreeClientImpl::ApplyServerChangeToExistingInFlightChange( |
| const InFlightChange& change) { |
| InFlightChange* existing_change = GetOldestInFlightChangeMatching(change); |
| if (!existing_change) |
| return false; |
| |
| existing_change->SetRevertValueFrom(change); |
| return true; |
| } |
| |
| void WindowTreeClientImpl::OnEmbedImpl(mojom::WindowTree* window_tree, |
| ConnectionSpecificId connection_id, |
| mojom::WindowDataPtr root_data, |
| Id focused_window_id, |
| uint32 access_policy) { |
| tree_ = window_tree; |
| connection_id_ = connection_id; |
| is_embed_root_ = |
| (access_policy & mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT) != 0; |
| |
| DCHECK(!root_); |
| root_ = AddWindowToConnection(this, nullptr, root_data); |
| |
| focused_window_ = GetWindowById(focused_window_id); |
| |
| delegate_->OnEmbed(root_); |
| |
| if (focused_window_) { |
| FOR_EACH_OBSERVER(WindowTreeConnectionObserver, observers_, |
| OnWindowTreeFocusChanged(focused_window_, nullptr)); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WindowTreeClientImpl, WindowTreeConnection implementation: |
| |
| Window* WindowTreeClientImpl::GetRoot() { |
| return root_; |
| } |
| |
| Window* WindowTreeClientImpl::GetWindowById(Id id) { |
| IdToWindowMap::const_iterator it = windows_.find(id); |
| return it != windows_.end() ? it->second : NULL; |
| } |
| |
| Window* WindowTreeClientImpl::GetFocusedWindow() { |
| return focused_window_; |
| } |
| |
| Window* WindowTreeClientImpl::NewWindow( |
| const Window::SharedProperties* properties) { |
| DCHECK(tree_); |
| Window* window = |
| new Window(this, MakeTransportId(connection_id_, next_window_id_++)); |
| if (properties) |
| window->properties_ = *properties; |
| AddWindow(window); |
| |
| const uint32_t change_id = ScheduleInFlightChange( |
| make_scoped_ptr(new CrashInFlightChange(window, ChangeType::NEW_WINDOW))); |
| mojo::Map<mojo::String, mojo::Array<uint8_t>> transport_properties; |
| if (properties) { |
| transport_properties = |
| mojo::Map<mojo::String, mojo::Array<uint8_t>>::From(*properties); |
| } |
| tree_->NewWindow(change_id, window->id(), std::move(transport_properties)); |
| return window; |
| } |
| |
| bool WindowTreeClientImpl::IsEmbedRoot() { |
| return is_embed_root_; |
| } |
| |
| ConnectionSpecificId WindowTreeClientImpl::GetConnectionId() { |
| return connection_id_; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WindowTreeClientImpl, WindowTreeClient implementation: |
| |
| void WindowTreeClientImpl::AddObserver(WindowTreeConnectionObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void WindowTreeClientImpl::RemoveObserver( |
| WindowTreeConnectionObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void WindowTreeClientImpl::OnEmbed(ConnectionSpecificId connection_id, |
| mojom::WindowDataPtr root_data, |
| mojom::WindowTreePtr tree, |
| Id focused_window_id, |
| uint32 access_policy) { |
| DCHECK(!tree_ptr_); |
| tree_ptr_ = std::move(tree); |
| tree_ptr_.set_connection_error_handler([this]() { delete this; }); |
| OnEmbedImpl(tree_ptr_.get(), connection_id, std::move(root_data), |
| focused_window_id, access_policy); |
| } |
| |
| void WindowTreeClientImpl::OnEmbeddedAppDisconnected(Id window_id) { |
| Window* window = GetWindowById(window_id); |
| if (window) { |
| FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(), |
| OnWindowEmbeddedAppDisconnected(window)); |
| } |
| } |
| |
| void WindowTreeClientImpl::OnUnembed() { |
| delegate_->OnUnembed(); |
| // This will send out the various notifications. |
| delete this; |
| } |
| |
| void WindowTreeClientImpl::OnWindowBoundsChanged(Id window_id, |
| mojo::RectPtr old_bounds, |
| mojo::RectPtr new_bounds) { |
| Window* window = GetWindowById(window_id); |
| if (!window) |
| return; |
| |
| InFlightBoundsChange new_change(window, new_bounds.To<gfx::Rect>()); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window) |
| .LocalSetBounds(old_bounds.To<gfx::Rect>(), new_bounds.To<gfx::Rect>()); |
| } |
| |
| void WindowTreeClientImpl::OnClientAreaChanged( |
| uint32_t window_id, |
| mojo::InsetsPtr new_client_area, |
| mojo::Array<mojo::RectPtr> new_additional_client_areas) { |
| Window* window = GetWindowById(window_id); |
| if (window) { |
| WindowPrivate(window).LocalSetClientArea( |
| new_client_area.To<gfx::Insets>(), |
| new_additional_client_areas.To<std::vector<gfx::Rect>>()); |
| } |
| } |
| |
| void WindowTreeClientImpl::OnTransientWindowAdded( |
| uint32_t window_id, |
| uint32_t transient_window_id) { |
| Window* window = GetWindowById(window_id); |
| Window* transient_window = GetWindowById(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 WindowTreeClientImpl::OnTransientWindowRemoved( |
| uint32_t window_id, |
| uint32_t transient_window_id) { |
| Window* window = GetWindowById(window_id); |
| Window* transient_window = GetWindowById(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); |
| } |
| |
| namespace { |
| |
| void SetViewportMetricsOnDecendants(Window* root, |
| const mojom::ViewportMetrics& old_metrics, |
| const mojom::ViewportMetrics& new_metrics) { |
| WindowPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics); |
| const Window::Children& children = root->children(); |
| for (size_t i = 0; i < children.size(); ++i) |
| SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics); |
| } |
| } |
| |
| void WindowTreeClientImpl::OnWindowViewportMetricsChanged( |
| mojom::ViewportMetricsPtr old_metrics, |
| mojom::ViewportMetricsPtr new_metrics) { |
| Window* window = GetRoot(); |
| if (window) |
| SetViewportMetricsOnDecendants(window, *old_metrics, *new_metrics); |
| } |
| |
| void WindowTreeClientImpl::OnWindowHierarchyChanged( |
| Id window_id, |
| Id new_parent_id, |
| Id old_parent_id, |
| mojo::Array<mojom::WindowDataPtr> windows) { |
| Window* initial_parent = |
| windows.size() ? GetWindowById(windows[0]->parent_id) : NULL; |
| |
| const bool was_window_known = GetWindowById(window_id) != nullptr; |
| |
| BuildWindowTree(this, 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 = GetWindowById(new_parent_id); |
| Window* old_parent = GetWindowById(old_parent_id); |
| Window* window = GetWindowById(window_id); |
| if (new_parent) |
| WindowPrivate(new_parent).LocalAddChild(window); |
| else |
| WindowPrivate(old_parent).LocalRemoveChild(window); |
| } |
| |
| void WindowTreeClientImpl::OnWindowReordered(Id window_id, |
| Id relative_window_id, |
| mojom::OrderDirection direction) { |
| Window* window = GetWindowById(window_id); |
| Window* relative_window = GetWindowById(relative_window_id); |
| if (window && relative_window) |
| WindowPrivate(window).LocalReorder(relative_window, direction); |
| } |
| |
| void WindowTreeClientImpl::OnWindowDeleted(Id window_id) { |
| Window* window = GetWindowById(window_id); |
| if (window) |
| WindowPrivate(window).LocalDestroy(); |
| } |
| |
| void WindowTreeClientImpl::OnWindowVisibilityChanged(Id window_id, |
| bool visible) { |
| Window* window = GetWindowById(window_id); |
| if (!window) |
| return; |
| |
| InFlightVisibleChange new_change(window, visible); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetVisible(visible); |
| } |
| |
| void WindowTreeClientImpl::OnWindowDrawnStateChanged(Id window_id, bool drawn) { |
| Window* window = GetWindowById(window_id); |
| if (window) |
| WindowPrivate(window).LocalSetDrawn(drawn); |
| } |
| |
| void WindowTreeClientImpl::OnWindowSharedPropertyChanged( |
| Id window_id, |
| const mojo::String& name, |
| mojo::Array<uint8_t> new_data) { |
| Window* window = GetWindowById(window_id); |
| if (!window) |
| return; |
| |
| InFlightPropertyChange new_change(window, name, new_data); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetSharedProperty(name, std::move(new_data)); |
| } |
| |
| void WindowTreeClientImpl::OnWindowInputEvent(uint32_t event_id, |
| Id window_id, |
| mojom::EventPtr event) { |
| Window* window = GetWindowById(window_id); |
| if (!window || !window->input_event_handler_) { |
| tree_->OnWindowInputEventAck(event_id); |
| return; |
| } |
| |
| scoped_ptr<base::Closure> ack_callback( |
| new base::Closure(base::Bind(&mojom::WindowTree::OnWindowInputEventAck, |
| base::Unretained(tree_), event_id))); |
| window->input_event_handler_->OnWindowInputEvent(window, std::move(event), |
| &ack_callback); |
| if (ack_callback) |
| ack_callback->Run(); |
| } |
| |
| void WindowTreeClientImpl::OnWindowFocused(Id focused_window_id) { |
| Window* focused_window = GetWindowById(focused_window_id); |
| InFlightFocusChange new_change(this, focused_window); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| LocalSetFocus(focused_window); |
| } |
| |
| void WindowTreeClientImpl::OnWindowPredefinedCursorChanged( |
| Id window_id, |
| mojom::Cursor cursor) { |
| Window* window = GetWindowById(window_id); |
| if (!window) |
| return; |
| |
| InFlightPredefinedCursorChange new_change(window, cursor); |
| if (ApplyServerChangeToExistingInFlightChange(new_change)) |
| return; |
| |
| WindowPrivate(window).LocalSetPredefinedCursor(cursor); |
| } |
| |
| void WindowTreeClientImpl::OnChangeCompleted(uint32 change_id, bool success) { |
| scoped_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(); |
| } |
| } |
| |
| void WindowTreeClientImpl::WmSetBounds(uint32_t change_id, |
| Id window_id, |
| mojo::RectPtr transit_bounds) { |
| Window* window = GetWindowById(window_id); |
| bool result = false; |
| if (window) { |
| DCHECK(window_manager_delegate_); |
| gfx::Rect bounds = transit_bounds.To<gfx::Rect>(); |
| 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.To<gfx::Rect>(); |
| window->SetBounds(bounds); |
| } |
| } |
| tree_->WmResponse(change_id, result); |
| } |
| |
| void WindowTreeClientImpl::WmSetProperty(uint32_t change_id, |
| Id window_id, |
| const mojo::String& name, |
| mojo::Array<uint8_t> transit_data) { |
| Window* window = GetWindowById(window_id); |
| bool result = false; |
| if (window) { |
| DCHECK(window_manager_delegate_); |
| scoped_ptr<std::vector<uint8_t>> data; |
| if (!transit_data.is_null()) { |
| data.reset( |
| new std::vector<uint8_t>(transit_data.To<std::vector<uint8_t>>())); |
| } |
| 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()); |
| } |
| } |
| tree_->WmResponse(change_id, result); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // WindowTreeClientImpl, private: |
| |
| mojo::Callback<void(bool)> WindowTreeClientImpl::ActionCompletedCallback() { |
| return [this](bool success) {}; |
| } |
| |
| } // namespace mus |