| Index: mojo/services/view_manager/cpp/lib/view_manager_client_impl.cc
|
| diff --git a/mojo/services/view_manager/cpp/lib/view_manager_client_impl.cc b/mojo/services/view_manager/cpp/lib/view_manager_client_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6852f660dcd1bb6cbff39c935f7905061b4053d1
|
| --- /dev/null
|
| +++ b/mojo/services/view_manager/cpp/lib/view_manager_client_impl.cc
|
| @@ -0,0 +1,494 @@
|
| +// 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 "view_manager/cpp/lib/view_manager_client_impl.h"
|
| +
|
| +#include "mojo/public/cpp/application/application_impl.h"
|
| +#include "mojo/public/cpp/application/connect.h"
|
| +#include "mojo/public/cpp/application/service_provider_impl.h"
|
| +#include "mojo/public/interfaces/application/service_provider.mojom.h"
|
| +#include "mojo/public/interfaces/application/shell.mojom.h"
|
| +#include "view_manager/cpp/lib/view_private.h"
|
| +#include "view_manager/cpp/util.h"
|
| +#include "view_manager/cpp/view_manager_delegate.h"
|
| +#include "view_manager/cpp/view_observer.h"
|
| +
|
| +namespace mojo {
|
| +
|
| +Id MakeTransportId(ConnectionSpecificId connection_id,
|
| + ConnectionSpecificId local_id) {
|
| + return (connection_id << 16) | local_id;
|
| +}
|
| +
|
| +// Helper called to construct a local view object from transport data.
|
| +View* AddViewToViewManager(ViewManagerClientImpl* client,
|
| + View* parent,
|
| + const ViewDataPtr& view_data) {
|
| + // We don't use the ctor that takes a ViewManager here, since it will call
|
| + // back to the service and attempt to create a new view.
|
| + View* view = ViewPrivate::LocalCreate();
|
| + ViewPrivate private_view(view);
|
| + private_view.set_view_manager(client);
|
| + private_view.set_id(view_data->view_id);
|
| + private_view.set_visible(view_data->visible);
|
| + private_view.set_drawn(view_data->drawn);
|
| + private_view.LocalSetViewportMetrics(ViewportMetrics(),
|
| + *view_data->viewport_metrics);
|
| + private_view.set_properties(
|
| + view_data->properties.To<std::map<std::string, std::vector<uint8_t>>>());
|
| + client->AddView(view);
|
| + private_view.LocalSetBounds(Rect(), *view_data->bounds);
|
| + if (parent)
|
| + ViewPrivate(parent).LocalAddChild(view);
|
| + return view;
|
| +}
|
| +
|
| +View* BuildViewTree(ViewManagerClientImpl* client,
|
| + const Array<ViewDataPtr>& views,
|
| + View* initial_parent) {
|
| + std::vector<View*> parents;
|
| + View* root = NULL;
|
| + View* last_view = NULL;
|
| + if (initial_parent)
|
| + parents.push_back(initial_parent);
|
| + for (size_t i = 0; i < views.size(); ++i) {
|
| + if (last_view && views[i]->parent_id == last_view->id()) {
|
| + parents.push_back(last_view);
|
| + } else if (!parents.empty()) {
|
| + while (parents.back()->id() != views[i]->parent_id)
|
| + parents.pop_back();
|
| + }
|
| + View* view = AddViewToViewManager(
|
| + client, !parents.empty() ? parents.back() : NULL, views[i]);
|
| + if (!last_view)
|
| + root = view;
|
| + last_view = view;
|
| + }
|
| + return root;
|
| +}
|
| +
|
| +// Responsible for removing a root from the ViewManager when that view is
|
| +// destroyed.
|
| +class RootObserver : public ViewObserver {
|
| + public:
|
| + explicit RootObserver(View* root) : root_(root) {}
|
| + ~RootObserver() override {}
|
| +
|
| + private:
|
| + // Overridden from ViewObserver:
|
| + void OnViewDestroyed(View* view) override {
|
| + DCHECK_EQ(view, root_);
|
| + static_cast<ViewManagerClientImpl*>(root_->view_manager())
|
| + ->RootDestroyed(root_);
|
| + view->RemoveObserver(this);
|
| + delete this;
|
| + }
|
| +
|
| + View* root_;
|
| +
|
| + MOJO_DISALLOW_COPY_AND_ASSIGN(RootObserver);
|
| +};
|
| +
|
| +ViewManagerClientImpl::ViewManagerClientImpl(
|
| + ViewManagerDelegate* delegate,
|
| + Shell* shell,
|
| + InterfaceRequest<ViewManagerClient> request,
|
| + bool delete_on_error)
|
| + : connection_id_(0),
|
| + next_id_(1),
|
| + delegate_(delegate),
|
| + root_(nullptr),
|
| + capture_view_(nullptr),
|
| + focused_view_(nullptr),
|
| + activated_view_(nullptr),
|
| + wm_observer_binding_(this),
|
| + binding_(this, request.Pass()) {
|
| + if (delete_on_error)
|
| + binding_.set_connection_error_handler([this]() { delete this; });
|
| +}
|
| +
|
| +ViewManagerClientImpl::~ViewManagerClientImpl() {
|
| + std::vector<View*> non_owned;
|
| + while (!views_.empty()) {
|
| + IdToViewMap::iterator it = views_.begin();
|
| + if (OwnsView(it->second->id())) {
|
| + it->second->Destroy();
|
| + } else {
|
| + non_owned.push_back(it->second);
|
| + views_.erase(it);
|
| + }
|
| + }
|
| + // Delete the non-owned views last. In the typical case these are roots. The
|
| + // exception is the window manager, which may know aboutother random views
|
| + // 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_->OnViewManagerDisconnected(this);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::DestroyView(Id view_id) {
|
| + DCHECK(service_);
|
| + service_->DeleteView(view_id, ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::AddChild(Id child_id, Id parent_id) {
|
| + DCHECK(service_);
|
| + service_->AddView(parent_id, child_id, ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::RemoveChild(Id child_id, Id parent_id) {
|
| + DCHECK(service_);
|
| + service_->RemoveViewFromParent(child_id, ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::Reorder(Id view_id,
|
| + Id relative_view_id,
|
| + OrderDirection direction) {
|
| + DCHECK(service_);
|
| + service_->ReorderView(view_id, relative_view_id, direction,
|
| + ActionCompletedCallback());
|
| +}
|
| +
|
| +bool ViewManagerClientImpl::OwnsView(Id id) const {
|
| + return HiWord(id) == connection_id_;
|
| +}
|
| +
|
| +void ViewManagerClientImpl::SetBounds(Id view_id, const Rect& bounds) {
|
| + DCHECK(service_);
|
| + service_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::SetSurfaceId(Id view_id, SurfaceIdPtr surface_id) {
|
| + DCHECK(service_);
|
| + if (surface_id.is_null())
|
| + return;
|
| + service_->SetViewSurfaceId(view_id, surface_id.Pass(),
|
| + ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::SetFocus(Id view_id) {
|
| + // In order for us to get here we had to have exposed a view, which implies we
|
| + // got a connection.
|
| + DCHECK(service_);
|
| + service_->PerformAction(view_id, "focus", ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::SetVisible(Id view_id, bool visible) {
|
| + DCHECK(service_);
|
| + service_->SetViewVisibility(view_id, visible, ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::SetProperty(Id view_id,
|
| + const std::string& name,
|
| + const std::vector<uint8_t>& data) {
|
| + DCHECK(service_);
|
| + service_->SetViewProperty(view_id, String(name), Array<uint8_t>::From(data),
|
| + ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::Embed(const String& url, Id view_id) {
|
| + Embed(url, view_id, nullptr, nullptr);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::Embed(const String& url,
|
| + Id view_id,
|
| + InterfaceRequest<ServiceProvider> services,
|
| + ServiceProviderPtr exposed_services) {
|
| + DCHECK(service_);
|
| + service_->EmbedUrl(url, view_id, services.Pass(), exposed_services.Pass(),
|
| + ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::Embed(Id view_id, ViewManagerClientPtr client) {
|
| + DCHECK(service_);
|
| + service_->Embed(view_id, client.Pass(), ActionCompletedCallback());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::AddView(View* view) {
|
| + DCHECK(views_.find(view->id()) == views_.end());
|
| + views_[view->id()] = view;
|
| +}
|
| +
|
| +void ViewManagerClientImpl::RemoveView(Id view_id) {
|
| + if (focused_view_ && focused_view_->id() == view_id)
|
| + OnFocusChanged(0);
|
| + if (capture_view_ && capture_view_->id() == view_id)
|
| + OnCaptureChanged(0);
|
| + if (activated_view_ && activated_view_->id() == view_id)
|
| + OnActiveWindowChanged(0);
|
| +
|
| + IdToViewMap::iterator it = views_.find(view_id);
|
| + if (it != views_.end())
|
| + views_.erase(it);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::SetViewManagerService(
|
| + ViewManagerServicePtr service) {
|
| + DCHECK(!service_);
|
| + DCHECK(service);
|
| + service_ = service.Pass();
|
| +}
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ViewManagerClientImpl, ViewManager implementation:
|
| +
|
| +Id ViewManagerClientImpl::CreateViewOnServer() {
|
| + DCHECK(service_);
|
| + const Id view_id = MakeTransportId(connection_id_, ++next_id_);
|
| + service_->CreateView(view_id, [this](ErrorCode code) {
|
| + OnActionCompleted(code == ErrorCode::NONE);
|
| + });
|
| + return view_id;
|
| +}
|
| +
|
| +const std::string& ViewManagerClientImpl::GetEmbedderURL() const {
|
| + return creator_url_;
|
| +}
|
| +
|
| +View* ViewManagerClientImpl::GetRoot() {
|
| + return root_;
|
| +}
|
| +
|
| +View* ViewManagerClientImpl::GetViewById(Id id) {
|
| + IdToViewMap::const_iterator it = views_.find(id);
|
| + return it != views_.end() ? it->second : NULL;
|
| +}
|
| +
|
| +View* ViewManagerClientImpl::GetFocusedView() {
|
| + return focused_view_;
|
| +}
|
| +
|
| +View* ViewManagerClientImpl::CreateView() {
|
| + View* view = new View(this, CreateViewOnServer());
|
| + AddView(view);
|
| + return view;
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ViewManagerClientImpl, ViewManagerClient implementation:
|
| +
|
| +void ViewManagerClientImpl::OnEmbed(
|
| + ConnectionSpecificId connection_id,
|
| + const String& creator_url,
|
| + ViewDataPtr root_data,
|
| + ViewManagerServicePtr view_manager_service,
|
| + InterfaceRequest<ServiceProvider> services,
|
| + ServiceProviderPtr exposed_services,
|
| + ScopedMessagePipeHandle window_manager_pipe) {
|
| + if (view_manager_service) {
|
| + DCHECK(!service_);
|
| + service_ = view_manager_service.Pass();
|
| + }
|
| + connection_id_ = connection_id;
|
| + creator_url_ = String::From(creator_url);
|
| +
|
| + DCHECK(!root_);
|
| + root_ = AddViewToViewManager(this, nullptr, root_data);
|
| + root_->AddObserver(new RootObserver(root_));
|
| +
|
| + window_manager_.Bind(
|
| + InterfacePtrInfo<WindowManager>(window_manager_pipe.Pass(), 0u));
|
| + WindowManagerObserverPtr observer;
|
| + wm_observer_binding_.Bind(GetProxy(&observer));
|
| + // binding to |this| is safe here as |window_manager_| is bound to our
|
| + // lifetime.
|
| + window_manager_->GetFocusedAndActiveViews(
|
| + observer.Pass(),
|
| + [this](uint32_t capture_view_id, uint32_t focused_view_id,
|
| + uint32_t active_view_id) {
|
| + if (GetViewById(capture_view_id) != capture_view_)
|
| + OnCaptureChanged(capture_view_id);
|
| + if (GetViewById(focused_view_id) != focused_view_)
|
| + OnFocusChanged(focused_view_id);
|
| + if (GetViewById(active_view_id) != activated_view_)
|
| + OnActiveWindowChanged(active_view_id);
|
| + });
|
| +
|
| + delegate_->OnEmbed(root_, services.Pass(), exposed_services.Pass());
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnEmbeddedAppDisconnected(Id view_id) {
|
| + View* view = GetViewById(view_id);
|
| + if (view) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(),
|
| + OnViewEmbeddedAppDisconnected(view));
|
| + }
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewBoundsChanged(Id view_id,
|
| + RectPtr old_bounds,
|
| + RectPtr new_bounds) {
|
| + View* view = GetViewById(view_id);
|
| + ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds);
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +void SetViewportMetricsOnDecendants(View* root,
|
| + const ViewportMetrics& old_metrics,
|
| + const ViewportMetrics& new_metrics) {
|
| + ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics);
|
| + const View::Children& children = root->children();
|
| + for (size_t i = 0; i < children.size(); ++i)
|
| + SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics);
|
| +}
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewViewportMetricsChanged(
|
| + ViewportMetricsPtr old_metrics,
|
| + ViewportMetricsPtr new_metrics) {
|
| + View* view = GetRoot();
|
| + if (view)
|
| + SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewHierarchyChanged(
|
| + Id view_id,
|
| + Id new_parent_id,
|
| + Id old_parent_id,
|
| + mojo::Array<ViewDataPtr> views) {
|
| + View* initial_parent = views.size() ? GetViewById(views[0]->parent_id) : NULL;
|
| +
|
| + BuildViewTree(this, views, initial_parent);
|
| +
|
| + View* new_parent = GetViewById(new_parent_id);
|
| + View* old_parent = GetViewById(old_parent_id);
|
| + View* view = GetViewById(view_id);
|
| + if (new_parent)
|
| + ViewPrivate(new_parent).LocalAddChild(view);
|
| + else
|
| + ViewPrivate(old_parent).LocalRemoveChild(view);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewReordered(Id view_id,
|
| + Id relative_view_id,
|
| + OrderDirection direction) {
|
| + View* view = GetViewById(view_id);
|
| + View* relative_view = GetViewById(relative_view_id);
|
| + if (view && relative_view)
|
| + ViewPrivate(view).LocalReorder(relative_view, direction);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewDeleted(Id view_id) {
|
| + View* view = GetViewById(view_id);
|
| + if (view)
|
| + ViewPrivate(view).LocalDestroy();
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) {
|
| + // TODO(sky): there is a race condition here. If this client and another
|
| + // client change the visibility at the same time the wrong value may be set.
|
| + // Deal with this some how.
|
| + View* view = GetViewById(view_id);
|
| + if (view)
|
| + ViewPrivate(view).LocalSetVisible(visible);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) {
|
| + View* view = GetViewById(view_id);
|
| + if (view)
|
| + ViewPrivate(view).LocalSetDrawn(drawn);
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewSharedPropertyChanged(
|
| + Id view_id,
|
| + const String& name,
|
| + Array<uint8_t> new_data) {
|
| + View* view = GetViewById(view_id);
|
| + if (view) {
|
| + std::vector<uint8_t> data;
|
| + std::vector<uint8_t>* data_ptr = NULL;
|
| + if (!new_data.is_null()) {
|
| + data = new_data.To<std::vector<uint8_t>>();
|
| + data_ptr = &data;
|
| + }
|
| +
|
| + view->SetSharedProperty(name, data_ptr);
|
| + }
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnViewInputEvent(
|
| + Id view_id,
|
| + EventPtr event,
|
| + const Callback<void()>& ack_callback) {
|
| + View* view = GetViewById(view_id);
|
| + if (view) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(),
|
| + OnViewInputEvent(view, event));
|
| + }
|
| + ack_callback.Run();
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnPerformAction(
|
| + Id view_id,
|
| + const String& name,
|
| + const Callback<void(bool)>& callback) {
|
| + View* view = GetViewById(view_id);
|
| + callback.Run(delegate_->OnPerformAction(view, name));
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ViewManagerClientImpl, WindowManagerObserver implementation:
|
| +
|
| +void ViewManagerClientImpl::OnCaptureChanged(Id capture_view_id) {
|
| + View* gained_capture = GetViewById(capture_view_id);
|
| + View* lost_capture = capture_view_;
|
| + if (lost_capture) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(lost_capture).observers(),
|
| + OnViewFocusChanged(gained_capture, lost_capture));
|
| + }
|
| + capture_view_ = gained_capture;
|
| + if (gained_capture) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(gained_capture).observers(),
|
| + OnViewFocusChanged(gained_capture, lost_capture));
|
| + }
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnFocusChanged(Id focused_view_id) {
|
| + View* focused = GetViewById(focused_view_id);
|
| + View* blurred = focused_view_;
|
| + if (blurred) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(blurred).observers(),
|
| + OnViewFocusChanged(focused, blurred));
|
| + }
|
| + focused_view_ = focused;
|
| + if (focused) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(focused).observers(),
|
| + OnViewFocusChanged(focused, blurred));
|
| + }
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnActiveWindowChanged(Id active_view_id) {
|
| + View* activated = GetViewById(active_view_id);
|
| + View* deactivated = activated_view_;
|
| + if (deactivated) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(deactivated).observers(),
|
| + OnViewActivationChanged(activated, deactivated));
|
| + }
|
| + activated_view_ = activated;
|
| + if (activated) {
|
| + FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(activated).observers(),
|
| + OnViewActivationChanged(activated, deactivated));
|
| + }
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ViewManagerClientImpl, private:
|
| +
|
| +void ViewManagerClientImpl::RootDestroyed(View* root) {
|
| + DCHECK_EQ(root, root_);
|
| + root_ = nullptr;
|
| +}
|
| +
|
| +void ViewManagerClientImpl::OnActionCompleted(bool success) {
|
| + if (!change_acked_callback_.is_null())
|
| + change_acked_callback_.Run();
|
| +}
|
| +
|
| +Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() {
|
| + return [this](bool success) { OnActionCompleted(success); };
|
| +}
|
| +
|
| +} // namespace mojo
|
|
|