diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-13 19:43:09 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-13 19:43:09 +0000 |
commit | f76571ef290da3526c28f10223b083fde8476310 (patch) | |
tree | 4272a7311b907466d8f86218ab4a9d64990d22df /mojo | |
parent | c0ccd2c2745aca1b75c8dbefe14adba6a581c990 (diff) | |
download | chromium_src-f76571ef290da3526c28f10223b083fde8476310.zip chromium_src-f76571ef290da3526c28f10223b083fde8476310.tar.gz chromium_src-f76571ef290da3526c28f10223b083fde8476310.tar.bz2 |
Synchronizes View instances across clients.
Create/DestroyView
SetActiveView
also adds some tests for creating views & nodes across connections, and some preliminary validation that client side objects from different connections can't be used together.
R=sky@chromium.org
http://crbug.com/365012
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=270122
Review URL: https://codereview.chromium.org/272833002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270174 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
27 files changed, 832 insertions, 76 deletions
diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi index 217a0a1..f3433ab 100644 --- a/mojo/mojo_services.gypi +++ b/mojo/mojo_services.gypi @@ -153,6 +153,8 @@ ], 'sources': [ 'services/public/cpp/view_manager/lib/view.cc', + 'services/public/cpp/view_manager/lib/view_private.cc', + 'services/public/cpp/view_manager/lib/view_private.h', 'services/public/cpp/view_manager/lib/view_manager.cc', 'services/public/cpp/view_manager/lib/view_manager_private.cc', 'services/public/cpp/view_manager/lib/view_manager_private.h', @@ -166,6 +168,7 @@ 'services/public/cpp/view_manager/view.h', 'services/public/cpp/view_manager/view_manager.h', 'services/public/cpp/view_manager/view_manager_types.h', + 'services/public/cpp/view_manager/view_observer.h', 'services/public/cpp/view_manager/view_tree_host.h', 'services/public/cpp/view_manager/view_tree_node.h', 'services/public/cpp/view_manager/view_tree_node_observer.h', diff --git a/mojo/services/public/cpp/view_manager/lib/view.cc b/mojo/services/public/cpp/view_manager/lib/view.cc index e69de29..577aca8 100644 --- a/mojo/services/public/cpp/view_manager/lib/view.cc +++ b/mojo/services/public/cpp/view_manager/lib/view.cc @@ -0,0 +1,82 @@ +// 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 "mojo/services/public/cpp/view_manager/view.h" + +#include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h" +#include "mojo/services/public/cpp/view_manager/lib/view_private.h" +#include "mojo/services/public/cpp/view_manager/view_observer.h" + +namespace mojo { +namespace services { +namespace view_manager { + +namespace { +class ScopedDestructionNotifier { + public: + explicit ScopedDestructionNotifier(View* view) + : view_(view) { + FOR_EACH_OBSERVER( + ViewObserver, + *ViewPrivate(view_).observers(), + OnViewDestroy(view_, ViewObserver::DISPOSITION_CHANGING)); + } + ~ScopedDestructionNotifier() { + FOR_EACH_OBSERVER( + ViewObserver, + *ViewPrivate(view_).observers(), + OnViewDestroy(view_, ViewObserver::DISPOSITION_CHANGED)); + } + + private: + View* view_; + + DISALLOW_COPY_AND_ASSIGN(ScopedDestructionNotifier); +}; +} // namespace + +// static +View* View::Create(ViewManager* manager) { + View* view = new View(manager); + ViewManagerPrivate(manager).AddView(view->id(), view); + return view; +} + +void View::Destroy() { + if (manager_) + ViewManagerPrivate(manager_).synchronizer()->DestroyView(id_); + LocalDestroy(); +} + +void View::AddObserver(ViewObserver* observer) { + observers_.AddObserver(observer); +} + +void View::RemoveObserver(ViewObserver* observer) { + observers_.RemoveObserver(observer); +} + +View::View(ViewManager* manager) + : id_(ViewManagerPrivate(manager).synchronizer()->CreateView()), + node_(NULL), + manager_(manager) {} + +View::View() + : id_(-1), + node_(NULL), + manager_(NULL) {} + +View::~View() { + ScopedDestructionNotifier notifier(this); + if (manager_) + ViewManagerPrivate(manager_).RemoveView(id_); +} + +void View::LocalDestroy() { + delete this; +} + +} // namespace view_manager +} // namespace services +} // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager.cc b/mojo/services/public/cpp/view_manager/lib/view_manager.cc index 9325a99..f3f02e87 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager.cc +++ b/mojo/services/public/cpp/view_manager/lib/view_manager.cc @@ -6,6 +6,7 @@ #include "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h" #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" +#include "mojo/services/public/cpp/view_manager/view.h" namespace mojo { namespace services { @@ -22,6 +23,13 @@ ViewManager::~ViewManager() { else nodes_.erase(it); } + while (!views_.empty()) { + IdToViewMap::iterator it = views_.begin(); + if (synchronizer_->OwnsView(it->second->id())) + it->second->Destroy(); + else + views_.erase(it); + } } void ViewManager::Init() { @@ -33,6 +41,11 @@ ViewTreeNode* ViewManager::GetNodeById(TransportNodeId id) { return it != nodes_.end() ? it->second : NULL; } +View* ViewManager::GetViewById(TransportViewId id) { + IdToViewMap::const_iterator it = views_.find(id); + return it != views_.end() ? it->second : NULL; +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_private.cc b/mojo/services/public/cpp/view_manager/lib/view_manager_private.cc index bf08b39..d69a383 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager_private.cc +++ b/mojo/services/public/cpp/view_manager/lib/view_manager_private.cc @@ -13,6 +13,7 @@ ViewManagerPrivate::ViewManagerPrivate(ViewManager* manager) ViewManagerPrivate::~ViewManagerPrivate() {} void ViewManagerPrivate::AddNode(TransportNodeId node_id, ViewTreeNode* node) { + DCHECK(!manager_->nodes_[node_id]); manager_->nodes_[node_id] = node; } @@ -22,6 +23,17 @@ void ViewManagerPrivate::RemoveNode(TransportNodeId node_id) { manager_->nodes_.erase(it); } +void ViewManagerPrivate::AddView(TransportViewId view_id, View* view) { + DCHECK(!manager_->views_[view_id]); + manager_->views_[view_id] = view; +} + +void ViewManagerPrivate::RemoveView(TransportViewId view_id) { + ViewManager::IdToViewMap::iterator it = manager_->views_.find(view_id); + if (it != manager_->views_.end()) + manager_->views_.erase(it); +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_private.h b/mojo/services/public/cpp/view_manager/lib/view_manager_private.h index f12fc64..8df1231 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager_private.h +++ b/mojo/services/public/cpp/view_manager/lib/view_manager_private.h @@ -30,6 +30,9 @@ class ViewManagerPrivate { void AddNode(TransportNodeId node_id, ViewTreeNode* node); void RemoveNode(TransportNodeId node_id); + void AddView(TransportViewId view_id, View* view); + void RemoveView(TransportViewId view_id); + // Returns true if the ViewManager's synchronizer is connected to the service. bool connected() { return manager_->synchronizer_->connected(); } diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc b/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc index 617f8ff..0335082 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc +++ b/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc @@ -9,6 +9,7 @@ #include "mojo/public/cpp/shell/service.h" #include "mojo/public/interfaces/shell/shell.mojom.h" #include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h" +#include "mojo/services/public/cpp/view_manager/lib/view_private.h" #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" #include "mojo/services/public/cpp/view_manager/util.h" @@ -16,9 +17,39 @@ namespace mojo { namespace services { namespace view_manager { -TransportNodeId MakeTransportNodeId(uint16_t connection_id, - uint16_t local_node_id) { - return (connection_id << 16) | local_node_id; +uint32_t MakeTransportId(uint16_t connection_id, uint16_t local_id) { + return (connection_id << 16) | local_id; +} + +// Helper called to construct a local node/view object from transport data. +ViewTreeNode* AddNodeToViewManager(ViewManager* manager, + ViewTreeNode* parent, + TransportNodeId node_id, + TransportViewId view_id) { + // 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 node. + ViewTreeNode* node = ViewTreeNodePrivate::LocalCreate(); + ViewTreeNodePrivate private_node(node); + private_node.set_view_manager(manager); + private_node.set_id(node_id); + if (parent) + ViewTreeNodePrivate(parent).LocalAddChild(node); + ViewManagerPrivate private_manager(manager); + private_manager.AddNode(node->id(), node); + + // View. + if (view_id != 0) { + View* view = ViewPrivate::LocalCreate(); + ViewPrivate private_view(view); + private_view.set_view_manager(manager); + private_view.set_id(view_id); + private_view.set_node(node); + // TODO(beng): this broadcasts notifications locally... do we want this? I + // don't think so. same story for LocalAddChild above! + private_node.LocalSetActiveView(view); + private_manager.AddView(view->id(), view); + } + return node; } class ViewManagerTransaction { @@ -43,12 +74,17 @@ class ViewManagerTransaction { protected: enum TransactionType { + // View creation and destruction. + TYPE_CREATE_VIEW, + TYPE_DESTROY_VIEW, // Node creation and destruction. TYPE_CREATE_VIEW_TREE_NODE, TYPE_DESTROY_VIEW_TREE_NODE, // Modifications to the hierarchy (addition of or removal of nodes from a // parent.) - TYPE_HIERARCHY + TYPE_HIERARCHY, + // View replacement. + TYPE_SET_ACTIVE_VIEW }; ViewManagerTransaction(TransactionType transaction_type, @@ -81,6 +117,57 @@ class ViewManagerTransaction { DISALLOW_COPY_AND_ASSIGN(ViewManagerTransaction); }; +class CreateViewTransaction : public ViewManagerTransaction { + public: + CreateViewTransaction(uint16_t view_id, + ViewManagerSynchronizer* synchronizer) + : ViewManagerTransaction(TYPE_CREATE_VIEW, synchronizer), + view_id_(view_id) {} + virtual ~CreateViewTransaction() {} + + private: + // Overridden from ViewManagerTransaction: + virtual void DoCommit() OVERRIDE { + service()->CreateView( + view_id_, + base::Bind(&ViewManagerTransaction::OnActionCompleted, + base::Unretained(this))); + } + virtual void DoActionCompleted(bool success) OVERRIDE { + // TODO(beng): failure. + } + + const uint16_t view_id_; + + DISALLOW_COPY_AND_ASSIGN(CreateViewTransaction); +}; + +class DestroyViewTransaction : public ViewManagerTransaction { + public: + DestroyViewTransaction(TransportViewId view_id, + ViewManagerSynchronizer* synchronizer) + : ViewManagerTransaction(TYPE_DESTROY_VIEW, synchronizer), + view_id_(view_id) {} + virtual ~DestroyViewTransaction() {} + + private: + // Overridden from ViewManagerTransaction: + virtual void DoCommit() OVERRIDE { + service()->DeleteView( + view_id_, + client_change_id(), + base::Bind(&ViewManagerTransaction::OnActionCompleted, + base::Unretained(this))); + } + virtual void DoActionCompleted(bool success) OVERRIDE { + // TODO(beng): recovery? + } + + const TransportViewId view_id_; + + DISALLOW_COPY_AND_ASSIGN(DestroyViewTransaction); +}; + class CreateViewTreeNodeTransaction : public ViewManagerTransaction { public: CreateViewTreeNodeTransaction(uint16_t node_id, @@ -130,7 +217,7 @@ class DestroyViewTreeNodeTransaction : public ViewManagerTransaction { // TODO(beng): recovery? } - TransportNodeId node_id_; + const TransportNodeId node_id_; DISALLOW_COPY_AND_ASSIGN(DestroyViewTreeNodeTransaction); }; @@ -186,6 +273,36 @@ class HierarchyTransaction : public ViewManagerTransaction { DISALLOW_COPY_AND_ASSIGN(HierarchyTransaction); }; +class SetActiveViewTransaction : public ViewManagerTransaction { + public: + SetActiveViewTransaction(TransportNodeId node_id, + TransportViewId view_id, + ViewManagerSynchronizer* synchronizer) + : ViewManagerTransaction(TYPE_SET_ACTIVE_VIEW, synchronizer), + node_id_(node_id), + view_id_(view_id) {} + virtual ~SetActiveViewTransaction() {} + + private: + // Overridden from ViewManagerTransaction: + virtual void DoCommit() OVERRIDE { + service()->SetView( + node_id_, + view_id_, + client_change_id(), + base::Bind(&ViewManagerTransaction::OnActionCompleted, + base::Unretained(this))); + } + virtual void DoActionCompleted(bool success) OVERRIDE { + // TODO(beng): recovery? + } + + const TransportNodeId node_id_; + const TransportViewId view_id_; + + DISALLOW_COPY_AND_ASSIGN(SetActiveViewTransaction); +}; + ViewManagerSynchronizer::ViewManagerSynchronizer(ViewManager* view_manager) : view_manager_(view_manager), connected_(false), @@ -220,7 +337,7 @@ TransportNodeId ViewManagerSynchronizer::CreateViewTreeNode() { uint16_t id = ++next_id_; pending_transactions_.push_back(new CreateViewTreeNodeTransaction(id, this)); Sync(); - return MakeTransportNodeId(connection_id_, id); + return MakeTransportId(connection_id_, id); } void ViewManagerSynchronizer::DestroyViewTreeNode(TransportNodeId node_id) { @@ -230,6 +347,20 @@ void ViewManagerSynchronizer::DestroyViewTreeNode(TransportNodeId node_id) { Sync(); } +TransportViewId ViewManagerSynchronizer::CreateView() { + DCHECK(connected_); + uint16_t id = ++next_id_; + pending_transactions_.push_back(new CreateViewTransaction(id, this)); + Sync(); + return MakeTransportId(connection_id_, id); +} + +void ViewManagerSynchronizer::DestroyView(TransportViewId view_id) { + DCHECK(connected_); + pending_transactions_.push_back(new DestroyViewTransaction(view_id, this)); + Sync(); +} + void ViewManagerSynchronizer::AddChild(TransportNodeId child_id, TransportNodeId parent_id) { DCHECK(connected_); @@ -256,6 +387,18 @@ bool ViewManagerSynchronizer::OwnsNode(TransportNodeId id) const { return HiWord(id) == connection_id_; } +bool ViewManagerSynchronizer::OwnsView(TransportViewId id) const { + return HiWord(id) == connection_id_; +} + +void ViewManagerSynchronizer::SetActiveView(TransportNodeId node_id, + TransportViewId view_id) { + DCHECK(connected_); + pending_transactions_.push_back( + new SetActiveViewTransaction(node_id, view_id, this)); + Sync(); +} + //////////////////////////////////////////////////////////////////////////////// // ViewManagerSynchronizer, IViewManagerClient implementation: @@ -293,6 +436,8 @@ void ViewManagerSynchronizer::OnNodeHierarchyChanged( private_node.set_view_manager(view_manager_); private_node.set_id(node_id); ViewManagerPrivate(view_manager_).AddNode(node->id(), node); + + // TODO(beng): view changes. } if (new_parent) ViewTreeNodePrivate(new_parent).LocalAddChild(node); @@ -302,10 +447,31 @@ void ViewManagerSynchronizer::OnNodeHierarchyChanged( next_server_change_id_ = server_change_id + 1; } -void ViewManagerSynchronizer::OnNodeDeleted( - TransportNodeId node_id, - TransportChangeId server_change_id, - TransportChangeId client_change_id) { +void ViewManagerSynchronizer::OnNodeViewReplaced(uint32_t node_id, + uint32_t new_view_id, + uint32_t old_view_id, + uint32_t client_change_id) { + if (client_change_id == 0) { + ViewTreeNode* node = view_manager_->GetNodeById(node_id); + View* new_view = view_manager_->GetViewById(new_view_id); + if (!new_view && new_view_id != 0) { + // This client wasn't aware of this View until now. + new_view = ViewPrivate::LocalCreate(); + ViewPrivate private_view(new_view); + private_view.set_view_manager(view_manager_); + private_view.set_id(new_view_id); + private_view.set_node(node); + ViewManagerPrivate(view_manager_).AddView(new_view->id(), new_view); + } + View* old_view = view_manager_->GetViewById(old_view_id); + DCHECK_EQ(old_view, node->active_view()); + ViewTreeNodePrivate(node).LocalSetActiveView(new_view); + } +} + +void ViewManagerSynchronizer::OnNodeDeleted(uint32_t node_id, + uint32_t server_change_id, + uint32_t client_change_id) { next_server_change_id_ = server_change_id + 1; if (client_change_id == 0) { ViewTreeNode* node = view_manager_->GetNodeById(node_id); @@ -314,11 +480,15 @@ void ViewManagerSynchronizer::OnNodeDeleted( } } -void ViewManagerSynchronizer::OnNodeViewReplaced(uint32_t node, - uint32_t new_view_id, - uint32_t old_view_id, - uint32_t client_change_id) { - // .. +void ViewManagerSynchronizer::OnViewDeleted(uint32_t view_id, + uint32_t server_change_id, + uint32_t client_change_id) { + next_server_change_id_ = server_change_id + 1; + if (client_change_id == 0) { + View* view = view_manager_->GetViewById(view_id); + if (view) + ViewPrivate(view).LocalDestroy(); + } } //////////////////////////////////////////////////////////////////////////////// @@ -354,6 +524,7 @@ void ViewManagerSynchronizer::RemoveFromPendingQueue( void ViewManagerSynchronizer::OnRootTreeReceived( const Array<INode>& nodes) { + ViewManagerPrivate private_manager(view_manager_); std::vector<ViewTreeNode*> parents; ViewTreeNode* root = NULL; ViewTreeNode* last_node = NULL; @@ -364,20 +535,16 @@ void ViewManagerSynchronizer::OnRootTreeReceived( while (parents.back()->id() != nodes[i].parent_id()) parents.pop_back(); } - // 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 node. - ViewTreeNode* node = ViewTreeNodePrivate::LocalCreate(); - ViewTreeNodePrivate private_node(node); - private_node.set_view_manager(view_manager_); - private_node.set_id(nodes[i].node_id()); - if (!parents.empty()) - ViewTreeNodePrivate(parents.back()).LocalAddChild(node); + ViewTreeNode* node = + AddNodeToViewManager(view_manager_, + !parents.empty() ? parents.back() : NULL, + nodes[i].node_id(), + nodes[i].view_id()); if (!last_node) root = node; last_node = node; - ViewManagerPrivate(view_manager_).AddNode(node->id(), node); } - ViewManagerPrivate(view_manager_).set_root(root); + private_manager.set_root(root); if (init_loop_) init_loop_->Quit(); } diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h b/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h index 2bab3a1..8792975 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h +++ b/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h @@ -30,11 +30,14 @@ class ViewManagerSynchronizer : public IViewManagerClient { bool connected() const { return connected_; } - // API exposed to the node implementation that pushes local changes to the - // service. + // API exposed to the node/view implementations that pushes local changes to + // the service. TransportNodeId CreateViewTreeNode(); void DestroyViewTreeNode(TransportNodeId node_id); + TransportViewId CreateView(); + void DestroyView(TransportViewId view_id); + // These methods take TransportIds. For views owned by the current connection, // the connection id high word can be zero. In all cases, the TransportId 0x1 // refers to the root node. @@ -42,6 +45,9 @@ class ViewManagerSynchronizer : public IViewManagerClient { void RemoveChild(TransportNodeId child_id, TransportNodeId parent_id); bool OwnsNode(TransportNodeId id) const; + bool OwnsView(TransportViewId id) const; + + void SetActiveView(TransportNodeId node_id, TransportViewId view_id); private: friend class ViewManagerTransaction; @@ -64,6 +70,9 @@ class ViewManagerSynchronizer : public IViewManagerClient { uint32_t new_view_id, uint32_t old_view_id, TransportChangeId client_change_id) OVERRIDE; + virtual void OnViewDeleted(uint32_t node_id, + uint32_t server_change_id, + uint32_t client_change_id) OVERRIDE; // Sync the client model with the service by enumerating the pending // transaction queue and applying them in order. diff --git a/mojo/services/public/cpp/view_manager/lib/view_private.cc b/mojo/services/public/cpp/view_manager/lib/view_private.cc new file mode 100644 index 0000000..c674533 --- /dev/null +++ b/mojo/services/public/cpp/view_manager/lib/view_private.cc @@ -0,0 +1,25 @@ +// 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 "mojo/services/public/cpp/view_manager/lib/view_private.h" + +namespace mojo { +namespace services { +namespace view_manager { + +ViewPrivate::ViewPrivate(View* view) + : view_(view) { +} + +ViewPrivate::~ViewPrivate() { +} + +// static +View* ViewPrivate::LocalCreate() { + return new View; +} + +} // namespace view_manager +} // namespace services +} // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/lib/view_private.h b/mojo/services/public/cpp/view_manager/lib/view_private.h new file mode 100644 index 0000000..45cc11b --- /dev/null +++ b/mojo/services/public/cpp/view_manager/lib/view_private.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_LIB_VIEW_PRIVATE_H_ +#define MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_LIB_VIEW_PRIVATE_H_ + +#include "base/basictypes.h" + +#include "mojo/services/public/cpp/view_manager/view.h" + +namespace mojo { +namespace services { +namespace view_manager { + +class ViewPrivate { + public: + explicit ViewPrivate(View* view); + ~ViewPrivate(); + + static View* LocalCreate(); + void LocalDestroy() { + view_->LocalDestroy(); + } + + void set_id(TransportViewId id) { view_->id_ = id; } + void set_node(ViewTreeNode* node) { view_->node_ = node; } + + ViewManager* view_manager() { return view_->manager_; } + void set_view_manager(ViewManager* manager) { + view_->manager_ = manager; + } + + ObserverList<ViewObserver>* observers() { return &view_->observers_; } + + private: + View* view_; + + DISALLOW_COPY_AND_ASSIGN(ViewPrivate); +}; + +} // namespace view_manager +} // namespace services +} // namespace mojo + +#endif // MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_LIB_VIEW_PRIVATE_H_ diff --git a/mojo/services/public/cpp/view_manager/lib/view_tree_node.cc b/mojo/services/public/cpp/view_manager/lib/view_tree_node.cc index 74e88a9..a034176 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_tree_node.cc +++ b/mojo/services/public/cpp/view_manager/lib/view_tree_node.cc @@ -6,13 +6,17 @@ #include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h" #include "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h" +#include "mojo/services/public/cpp/view_manager/lib/view_private.h" #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" +#include "mojo/services/public/cpp/view_manager/view.h" #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" namespace mojo { namespace services { namespace view_manager { +namespace { + void NotifyViewTreeChangeAtReceiver( ViewTreeNode* receiver, const ViewTreeNodeObserver::TreeChangeParams& params) { @@ -87,6 +91,64 @@ void RemoveChildImpl(ViewTreeNode* child, ViewTreeNode::Children* children) { } } +class ScopedSetActiveViewNotifier { + public: + ScopedSetActiveViewNotifier(ViewTreeNode* node, + View* old_view, + View* new_view) + : node_(node), + old_view_(old_view), + new_view_(new_view) { + FOR_EACH_OBSERVER( + ViewTreeNodeObserver, + *ViewTreeNodePrivate(node).observers(), + OnNodeActiveViewChange(node_, + old_view_, + new_view_, + ViewTreeNodeObserver::DISPOSITION_CHANGING)); + } + ~ScopedSetActiveViewNotifier() { + FOR_EACH_OBSERVER( + ViewTreeNodeObserver, + *ViewTreeNodePrivate(node_).observers(), + OnNodeActiveViewChange(node_, + old_view_, + new_view_, + ViewTreeNodeObserver::DISPOSITION_CHANGED)); + } + + private: + ViewTreeNode* node_; + View* old_view_; + View* new_view_; + + DISALLOW_COPY_AND_ASSIGN(ScopedSetActiveViewNotifier); +}; + +class ScopedDestructionNotifier { + public: + explicit ScopedDestructionNotifier(ViewTreeNode* node) + : node_(node) { + FOR_EACH_OBSERVER( + ViewTreeNodeObserver, + *ViewTreeNodePrivate(node_).observers(), + OnNodeDestroy(node_, ViewTreeNodeObserver::DISPOSITION_CHANGING)); + } + ~ScopedDestructionNotifier() { + FOR_EACH_OBSERVER( + ViewTreeNodeObserver, + *ViewTreeNodePrivate(node_).observers(), + OnNodeDestroy(node_, ViewTreeNodeObserver::DISPOSITION_CHANGED)); + } + + private: + ViewTreeNode* node_; + + DISALLOW_COPY_AND_ASSIGN(ScopedDestructionNotifier); +}; + +} // namespace + //////////////////////////////////////////////////////////////////////////////// // ViewTreeNode, public: @@ -114,18 +176,24 @@ void ViewTreeNode::RemoveObserver(ViewTreeNodeObserver* observer) { } void ViewTreeNode::AddChild(ViewTreeNode* child) { + if (manager_) + CHECK_EQ(ViewTreeNodePrivate(child).view_manager(), manager_); LocalAddChild(child); if (manager_) ViewManagerPrivate(manager_).synchronizer()->AddChild(child->id(), id_); } void ViewTreeNode::RemoveChild(ViewTreeNode* child) { + if (manager_) + CHECK_EQ(ViewTreeNodePrivate(child).view_manager(), manager_); LocalRemoveChild(child); if (manager_) ViewManagerPrivate(manager_).synchronizer()->RemoveChild(child->id(), id_); } bool ViewTreeNode::Contains(ViewTreeNode* child) const { + if (manager_) + CHECK_EQ(ViewTreeNodePrivate(child).view_manager(), manager_); for (ViewTreeNode* p = child->parent(); p; p = p->parent()) { if (p == this) return true; @@ -146,25 +214,29 @@ ViewTreeNode* ViewTreeNode::GetChildById(TransportNodeId id) { return NULL; } +void ViewTreeNode::SetActiveView(View* view) { + if (manager_) + CHECK_EQ(ViewPrivate(view).view_manager(), manager_); + LocalSetActiveView(view); + if (manager_) { + ViewManagerPrivate(manager_).synchronizer()->SetActiveView( + id_, active_view_->id()); + } +} + //////////////////////////////////////////////////////////////////////////////// // ViewTreeNode, protected: ViewTreeNode::ViewTreeNode() : manager_(NULL), id_(-1), - parent_(NULL) {} + parent_(NULL), + active_view_(NULL) {} ViewTreeNode::~ViewTreeNode() { - FOR_EACH_OBSERVER( - ViewTreeNodeObserver, - observers_, - OnNodeDestroy(this, ViewTreeNodeObserver::DISPOSITION_CHANGING)); + ScopedDestructionNotifier notifier(this); if (parent_) parent_->LocalRemoveChild(this); - FOR_EACH_OBSERVER( - ViewTreeNodeObserver, - observers_, - OnNodeDestroy(this, ViewTreeNodeObserver::DISPOSITION_CHANGED)); if (manager_) ViewManagerPrivate(manager_).RemoveNode(id_); } @@ -175,7 +247,8 @@ ViewTreeNode::~ViewTreeNode() { ViewTreeNode::ViewTreeNode(ViewManager* manager) : manager_(manager), id_(ViewManagerPrivate(manager).synchronizer()->CreateViewTreeNode()), - parent_(NULL) {} + parent_(NULL), + active_view_(NULL) {} void ViewTreeNode::LocalDestroy() { delete this; @@ -195,6 +268,15 @@ void ViewTreeNode::LocalRemoveChild(ViewTreeNode* child) { RemoveChildImpl(child, &children_); } +void ViewTreeNode::LocalSetActiveView(View* view) { + ScopedSetActiveViewNotifier notifier(this, active_view_, view); + if (active_view_) + ViewPrivate(active_view_).set_node(NULL); + active_view_ = view; + if (active_view_) + ViewPrivate(active_view_).set_node(this); +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h b/mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h index 4837a97..ea7faf3 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h +++ b/mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h @@ -5,8 +5,6 @@ #ifndef MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_LIB_VIEW_TREE_NODE_PRIVATE_H_ #define MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_LIB_VIEW_TREE_NODE_PRIVATE_H_ -#include <vector> - #include "base/basictypes.h" #include "mojo/services/public/cpp/view_manager/view_tree_node.h" @@ -43,6 +41,10 @@ class ViewTreeNodePrivate { node_->LocalRemoveChild(child); } + void LocalSetActiveView(View* view) { + node_->LocalSetActiveView(view); + } + private: ViewTreeNode* node_; diff --git a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc index 6505028..6abcd4c 100644 --- a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc +++ b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc @@ -8,6 +8,8 @@ #include "base/logging.h" #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h" #include "mojo/services/public/cpp/view_manager/util.h" +#include "mojo/services/public/cpp/view_manager/view.h" +#include "mojo/services/public/cpp/view_manager/view_observer.h" #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" #include "mojo/shell/shell_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" @@ -245,31 +247,68 @@ TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) { EXPECT_TRUE(tree2->children().empty()); } -class NodeDestroyed_Waiter : public ViewTreeNodeObserver { +// Utility class that waits for the destruction of some number of nodes and +// views. +class DestructionWaiter : public ViewTreeNodeObserver, + public ViewObserver { public: - NodeDestroyed_Waiter(ViewManager* view_manager, TransportNodeId id) - : id_(id), - view_manager_(view_manager) { - view_manager_->GetNodeById(id)->AddObserver(this); + // |nodes| or |views| can be NULL. + DestructionWaiter(ViewManager* view_manager, + std::set<TransportNodeId>* nodes, + std::set<TransportViewId>* views) + : nodes_(nodes), + views_(views) { + DCHECK(nodes || views); + if (nodes) { + for (std::set<TransportNodeId>::const_iterator it = nodes->begin(); + it != nodes->end(); ++it) { + view_manager->GetNodeById(*it)->AddObserver(this); + } + } + if (views) { + for (std::set<TransportViewId>::const_iterator it = views->begin(); + it != views->end(); ++it) { + view_manager->GetViewById(*it)->AddObserver(this); + } + } DoRunLoop(); } - virtual ~NodeDestroyed_Waiter() { - } private: - // Overridden from TreeObserverBase: - virtual void OnNodeDestroy(ViewTreeNode* node, - DispositionChangePhase phase) OVERRIDE { - if (phase != DISPOSITION_CHANGED) + // Overridden from ViewTreeNodeObserver: + virtual void OnNodeDestroy( + ViewTreeNode* node, + ViewTreeNodeObserver::DispositionChangePhase phase) OVERRIDE { + if (phase != ViewTreeNodeObserver::DISPOSITION_CHANGED) return; - if (node->id() == id_) + std::set<TransportNodeId>::const_iterator it = nodes_->find(node->id()); + if (it != nodes_->end()) + nodes_->erase(it); + if (CanQuit()) QuitRunLoop(); } - TransportNodeId id_; - ViewManager* view_manager_; + // Overridden from ViewObserver: + virtual void OnViewDestroy( + View* view, + ViewObserver::DispositionChangePhase phase) OVERRIDE { + if (phase != ViewObserver::DISPOSITION_CHANGED) + return; + std::set<TransportViewId>::const_iterator it = views_->find(view->id()); + if (it != views_->end()) + views_->erase(it); + if (CanQuit()) + QuitRunLoop(); + } + + bool CanQuit() { + return (!nodes_ || nodes_->empty()) && (!views_ || views_->empty()); + } - DISALLOW_COPY_AND_ASSIGN(NodeDestroyed_Waiter); + std::set<TransportNodeId>* nodes_; + std::set<TransportViewId>* views_; + + DISALLOW_COPY_AND_ASSIGN(DestructionWaiter); }; TEST_F(ViewManagerTest, NodeDestroyed) { @@ -279,23 +318,171 @@ TEST_F(ViewManagerTest, NodeDestroyed) { // |node1| will be deleted after calling Destroy() below. TransportNodeId id = node1->id(); node1->Destroy(); - NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id); + + std::set<TransportNodeId> nodes; + nodes.insert(id); + DestructionWaiter destroyed_waiter(view_manager_2(), &nodes, NULL); EXPECT_TRUE(view_manager_2()->tree()->children().empty()); + EXPECT_EQ(NULL, view_manager_2()->GetNodeById(id)); } -TEST_F(ViewManagerTest, ViewManagerDestroyed) { +TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) { ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); TransportNodeId id = node1->id(); DestroyViewManager1(); - NodeDestroyed_Waiter destroyed_waiter(view_manager_2(), id); + std::set<TransportNodeId> nodes; + nodes.insert(id); + DestructionWaiter destroyed_waiter(view_manager_2(), &nodes, NULL); // tree() should still be valid, since it's owned by neither connection. EXPECT_TRUE(view_manager_2()->tree()->children().empty()); } +// Waits until the active view id of the supplied node changes. +class ActiveViewChangedWaiter : public ViewTreeNodeObserver { + public: + explicit ActiveViewChangedWaiter(ViewTreeNode* node) + : node_(node) { + node_->AddObserver(this); + DoRunLoop(); + } + virtual ~ActiveViewChangedWaiter() { + node_->RemoveObserver(this); + } + + private: + // Overridden from ViewTreeNodeObserver: + virtual void OnNodeActiveViewChange(ViewTreeNode* node, + View* old_view, + View* new_view, + DispositionChangePhase phase) OVERRIDE { + DCHECK_EQ(node, node_); + QuitRunLoop(); + } + + ViewTreeNode* node_; + + DISALLOW_COPY_AND_ASSIGN(ActiveViewChangedWaiter); +}; + +TEST_F(ViewManagerTest, SetActiveView) { + ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); + TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); + + View* view1 = View::Create(view_manager_1()); + node1->SetActiveView(view1); + + ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); + ActiveViewChangedWaiter waiter(node1_2); + + EXPECT_EQ(node1_2->active_view()->id(), view1->id()); +} + +TEST_F(ViewManagerTest, DestroyView) { + ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); + TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); + + View* view1 = View::Create(view_manager_1()); + node1->SetActiveView(view1); + + ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); + ActiveViewChangedWaiter active_view_waiter(node1_2); + + TransportViewId view1_id = view1->id(); + view1->Destroy(); + + std::set<TransportViewId> views; + views.insert(view1_id); + DestructionWaiter destruction_waiter(view_manager_2(), NULL, &views); + EXPECT_EQ(NULL, node1_2->active_view()); + EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); +} + +// Destroying the connection that created a node and view should result in that +// node and view disappearing from all connections that see them. +TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) { + ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); + TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); + + View* view1 = View::Create(view_manager_1()); + node1->SetActiveView(view1); + + ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); + { + ActiveViewChangedWaiter active_view_waiter(node1_2); + } + + TransportNodeId node1_id = node1->id(); + TransportViewId view1_id = view1->id(); + + DestroyViewManager1(); + std::set<TransportNodeId> observed_nodes; + observed_nodes.insert(node1_id); + std::set<TransportViewId> observed_views; + observed_views.insert(view1_id); + DestructionWaiter destruction_waiter(view_manager_2(), + &observed_nodes, + &observed_views); + + // tree() should still be valid, since it's owned by neither connection. + EXPECT_TRUE(view_manager_2()->tree()->children().empty()); + EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); + EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); +} + +// This test validates the following scenario: +// - a node originating from one connection +// - a view originating from a second connection +// + the connection originating the node is destroyed +// -> the view should still exist (since the second connection is live) but +// should be disconnected from any nodes. +TEST_F(ViewManagerTest, + ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) { + ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); + TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); + + View* view1_2 = View::Create(view_manager_2()); + ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); + node1_2->SetActiveView(view1_2); + + { + ActiveViewChangedWaiter active_view_waiter(node1); + } + + TransportNodeId node1_id = node1->id(); + TransportViewId view1_2_id = view1_2->id(); + + DestroyViewManager1(); + std::set<TransportNodeId> nodes; + nodes.insert(node1_id); + DestructionWaiter destruction_waiter(view_manager_2(), &nodes, NULL); + + // tree() should still be valid, since it's owned by neither connection. + EXPECT_TRUE(view_manager_2()->tree()->children().empty()); + // node1 was owned by the first connection, so it should be gone. + EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); + // view1_2 was owned by the second connection, so it should still exist, but + // disconnected from the node tree. + View* another_view1_2 = view_manager_2()->GetViewById(view1_2_id); + EXPECT_EQ(view1_2, another_view1_2); + EXPECT_EQ(NULL, view1_2->node()); +} + +// This test verifies that it is not possible to set the active view to a view +// defined in a different connection. +// TODO(beng): write these tests for ViewTreeNode::AddChild(), RemoveChild() and +// Contains(). +TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { + ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); + TreeSizeMatchesWaiter init_waiter(view_manager_2(), 2); + + View* view1_2 = View::Create(view_manager_2()); + EXPECT_DEATH(node1->SetActiveView(view1_2), ""); +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/view.h b/mojo/services/public/cpp/view_manager/view.h index a0bba82..12ba55c 100644 --- a/mojo/services/public/cpp/view_manager/view.h +++ b/mojo/services/public/cpp/view_manager/view.h @@ -6,14 +6,45 @@ #define MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_H_ #include "base/basictypes.h" +#include "base/observer_list.h" +#include "mojo/services/public/cpp/view_manager/view_manager_types.h" namespace mojo { namespace services { namespace view_manager { +class ViewManager; +class ViewObserver; +class ViewTreeNode; + +// Views are owned by the ViewManager. class View { public: + static View* Create(ViewManager* manager); + + void Destroy(); + + TransportViewId id() const { return id_; } + ViewTreeNode* node() { return node_; } + + void AddObserver(ViewObserver* observer); + void RemoveObserver(ViewObserver* observer); + private: + friend class ViewPrivate; + + explicit View(ViewManager* manager); + View(); + ~View(); + + void LocalDestroy(); + + TransportViewId id_; + ViewTreeNode* node_; + ViewManager* manager_; + + ObserverList<ViewObserver> observers_; + DISALLOW_COPY_AND_ASSIGN(View); }; diff --git a/mojo/services/public/cpp/view_manager/view_manager.h b/mojo/services/public/cpp/view_manager/view_manager.h index a06d566..380974c 100644 --- a/mojo/services/public/cpp/view_manager/view_manager.h +++ b/mojo/services/public/cpp/view_manager/view_manager.h @@ -17,6 +17,7 @@ class Shell; namespace services { namespace view_manager { +class View; class ViewManagerSynchronizer; class ViewTreeNode; @@ -44,16 +45,19 @@ class ViewManager { ViewTreeNode* tree() { return tree_; } ViewTreeNode* GetNodeById(TransportNodeId id); + View* GetViewById(TransportViewId id); private: friend class ViewManagerPrivate; typedef std::map<TransportNodeId, ViewTreeNode*> IdToNodeMap; + typedef std::map<TransportViewId, View*> IdToViewMap; Shell* shell_; scoped_ptr<ViewManagerSynchronizer> synchronizer_; ViewTreeNode* tree_; IdToNodeMap nodes_; + IdToViewMap views_; DISALLOW_COPY_AND_ASSIGN(ViewManager); }; diff --git a/mojo/services/public/cpp/view_manager/view_observer.h b/mojo/services/public/cpp/view_manager/view_observer.h new file mode 100644 index 0000000..e08bac2 --- /dev/null +++ b/mojo/services/public/cpp/view_manager/view_observer.h @@ -0,0 +1,35 @@ +// 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. + +#ifndef MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_OBSERVER_H_ +#define MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_OBSERVER_H_ + +#include <vector> + +#include "base/basictypes.h" + +namespace mojo { +namespace services { +namespace view_manager { + +class View; + +class ViewObserver { + public: + enum DispositionChangePhase { + DISPOSITION_CHANGING, + DISPOSITION_CHANGED + }; + + virtual void OnViewDestroy(View* view, DispositionChangePhase phase) {} + + protected: + virtual ~ViewObserver() {} +}; + +} // namespace view_manager +} // namespace services +} // namespace mojo + +#endif // MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_OBSERVER_H_ diff --git a/mojo/services/public/cpp/view_manager/view_tree_node.h b/mojo/services/public/cpp/view_manager/view_tree_node.h index b2af9cb..e1f9058 100644 --- a/mojo/services/public/cpp/view_manager/view_tree_node.h +++ b/mojo/services/public/cpp/view_manager/view_tree_node.h @@ -15,6 +15,7 @@ namespace mojo { namespace services { namespace view_manager { +class View; class ViewManager; class ViewTreeNodeObserver; @@ -50,6 +51,10 @@ class ViewTreeNode { ViewTreeNode* GetChildById(TransportNodeId id); + // View. + void SetActiveView(View* view); + View* active_view() { return active_view_; } + protected: // This class is subclassed only by test classes that provide a public ctor. ViewTreeNode(); @@ -63,6 +68,7 @@ class ViewTreeNode { void LocalDestroy(); void LocalAddChild(ViewTreeNode* child); void LocalRemoveChild(ViewTreeNode* child); + void LocalSetActiveView(View* view); ViewManager* manager_; TransportNodeId id_; @@ -71,6 +77,8 @@ class ViewTreeNode { ObserverList<ViewTreeNodeObserver> observers_; + View* active_view_; + DISALLOW_COPY_AND_ASSIGN(ViewTreeNode); }; diff --git a/mojo/services/public/cpp/view_manager/view_tree_node_observer.h b/mojo/services/public/cpp/view_manager/view_tree_node_observer.h index ac55ae6..cd5da9d 100644 --- a/mojo/services/public/cpp/view_manager/view_tree_node_observer.h +++ b/mojo/services/public/cpp/view_manager/view_tree_node_observer.h @@ -13,6 +13,7 @@ namespace mojo { namespace services { namespace view_manager { +class View; class ViewTreeNode; class ViewTreeNodeObserver { @@ -36,6 +37,11 @@ class ViewTreeNodeObserver { virtual void OnNodeDestroy(ViewTreeNode* node, DispositionChangePhase phase) {} + virtual void OnNodeActiveViewChange(ViewTreeNode* node, + View* old_view, + View* new_view, + DispositionChangePhase phase) {} + protected: virtual ~ViewTreeNodeObserver() {} }; diff --git a/mojo/services/public/interfaces/view_manager/view_manager.mojom b/mojo/services/public/interfaces/view_manager/view_manager.mojom index 4aa0fdb..afb2ab7 100644 --- a/mojo/services/public/interfaces/view_manager/view_manager.mojom +++ b/mojo/services/public/interfaces/view_manager/view_manager.mojom @@ -96,9 +96,7 @@ interface IViewManagerClient { uint32 client_change_id); // Invoked when a node is deleted. - OnNodeDeleted(uint32 node, - uint32 server_change_id, - uint32 client_change_id); + OnNodeDeleted(uint32 node, uint32 server_change_id, uint32 client_change_id); // Invoked when the view associated with a node is replaced by another view. @@ -107,6 +105,9 @@ interface IViewManagerClient { uint32 new_view_id, uint32 old_view_id, uint32 client_change_id); + + // Invoked when a view is deleted. + OnViewDeleted(uint32 view, uint32 server_change_id, uint32 client_change_id); }; } diff --git a/mojo/services/view_manager/node.cc b/mojo/services/view_manager/node.cc index 5f5af51..a69807d 100644 --- a/mojo/services/view_manager/node.cc +++ b/mojo/services/view_manager/node.cc @@ -62,7 +62,7 @@ std::vector<Node*> Node::GetChildren() { return children; } -void Node::SetView(View* view) { +void Node::SetView(service::View* view) { if (view == view_) return; diff --git a/mojo/services/view_manager/node.h b/mojo/services/view_manager/node.h index d1b65ae..7a9b130 100644 --- a/mojo/services/view_manager/node.h +++ b/mojo/services/view_manager/node.h @@ -19,7 +19,9 @@ namespace services { namespace view_manager { class NodeDelegate; +namespace service { class View; +} // Represents a node in the graph. Delegate is informed of interesting events. class MOJO_VIEW_MANAGER_EXPORT Node @@ -44,8 +46,8 @@ class MOJO_VIEW_MANAGER_EXPORT Node std::vector<Node*> GetChildren(); // Sets the view associated with this node. Node does not own its View. - void SetView(View* view); - View* view() { return view_; } + void SetView(service::View* view); + service::View* view() { return view_; } private: // WindowObserver overrides: @@ -76,7 +78,7 @@ class MOJO_VIEW_MANAGER_EXPORT Node const NodeId id_; // Weak pointer to view associated with this node. - View* view_; + service::View* view_; ViewId view_id_; diff --git a/mojo/services/view_manager/root_node_manager.cc b/mojo/services/view_manager/root_node_manager.cc index 77ebfcf..7bb7948 100644 --- a/mojo/services/view_manager/root_node_manager.cc +++ b/mojo/services/view_manager/root_node_manager.cc @@ -80,7 +80,7 @@ Node* RootNodeManager::GetNode(const NodeId& id) { return i == connection_map_.end() ? NULL : i->second->GetNode(id); } -View* RootNodeManager::GetView(const ViewId& id) { +service::View* RootNodeManager::GetView(const ViewId& id) { ConnectionMap::iterator i = connection_map_.find(id.connection_id); return i == connection_map_.end() ? NULL : i->second->GetView(id); } @@ -116,6 +116,15 @@ void RootNodeManager::NotifyNodeDeleted(const NodeId& node) { } } +void RootNodeManager::NotifyViewDeleted(const ViewId& view) { + // TODO(sky): make a macro for this. + for (ConnectionMap::iterator i = connection_map_.begin(); + i != connection_map_.end(); ++i) { + i->second->NotifyViewDeleted(view, next_server_change_id_, + GetClientChangeId(i->first)); + } +} + void RootNodeManager::PrepareForChange(ViewManagerConnection* connection, TransportChangeId change_id) { DCHECK(!change_.get()); // Should only ever have one change in flight. diff --git a/mojo/services/view_manager/root_node_manager.h b/mojo/services/view_manager/root_node_manager.h index e040416..c7ce7e3 100644 --- a/mojo/services/view_manager/root_node_manager.h +++ b/mojo/services/view_manager/root_node_manager.h @@ -72,7 +72,7 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager : public NodeDelegate { Node* GetNode(const NodeId& id); // Returns the View identified by |id|. - View* GetView(const ViewId& id); + service::View* GetView(const ViewId& id); Node* root() { return &root_; } @@ -85,6 +85,7 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager : public NodeDelegate { const ViewId& new_view_id, const ViewId& old_view_id); void NotifyNodeDeleted(const NodeId& node); + void NotifyViewDeleted(const ViewId& view); private: // Used to setup any static state needed by RootNodeManager. diff --git a/mojo/services/view_manager/view.cc b/mojo/services/view_manager/view.cc index 18c98d1..23246c0 100644 --- a/mojo/services/view_manager/view.cc +++ b/mojo/services/view_manager/view.cc @@ -9,6 +9,7 @@ namespace mojo { namespace services { namespace view_manager { +namespace service { View::View(const ViewId& id) : id_(id), node_(NULL) {} @@ -23,6 +24,7 @@ void View::SetBitmap(const SkBitmap& bitmap) { } } +} // namespace service } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/view_manager/view.h b/mojo/services/view_manager/view.h index 32b7e03..ba8c280 100644 --- a/mojo/services/view_manager/view.h +++ b/mojo/services/view_manager/view.h @@ -15,8 +15,8 @@ namespace mojo { namespace services { namespace view_manager { - class Node; +namespace service { // Represents a view. A view may be associated with a single Node. class MOJO_VIEW_MANAGER_EXPORT View { @@ -33,7 +33,7 @@ class MOJO_VIEW_MANAGER_EXPORT View { private: // Node is responsible for maintaining |node_|. - friend class Node; + friend class mojo::services::view_manager::Node; void set_node(Node* node) { node_ = node; } @@ -44,6 +44,7 @@ class MOJO_VIEW_MANAGER_EXPORT View { DISALLOW_COPY_AND_ASSIGN(View); }; +} // namespace service } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/view_manager/view_manager_connection.cc b/mojo/services/view_manager/view_manager_connection.cc index 176d8ee..d7a2919 100644 --- a/mojo/services/view_manager/view_manager_connection.cc +++ b/mojo/services/view_manager/view_manager_connection.cc @@ -96,7 +96,7 @@ Node* ViewManagerConnection::GetNode(const NodeId& id) { return context()->GetNode(id); } -View* ViewManagerConnection::GetView(const ViewId& id) { +service::View* ViewManagerConnection::GetView(const ViewId& id) { if (id_ == id.connection_id) { ViewMap::const_iterator i = view_map_.find(id.view_id); return i == view_map_.end() ? NULL : i->second; @@ -136,6 +136,14 @@ void ViewManagerConnection::NotifyNodeDeleted( client_change_id); } +void ViewManagerConnection::NotifyViewDeleted( + const ViewId& view, + TransportChangeId server_change_id, + TransportChangeId client_change_id) { + client()->OnViewDeleted(ViewIdToTransportId(view), server_change_id, + client_change_id); +} + bool ViewManagerConnection::DeleteNodeImpl(ViewManagerConnection* source, const NodeId& node_id, TransportChangeId change_id) { @@ -163,7 +171,7 @@ bool ViewManagerConnection::DeleteViewImpl(ViewManagerConnection* source, const ViewId& view_id, TransportChangeId change_id) { DCHECK_EQ(view_id.connection_id, id_); - View* view = GetView(view_id); + service::View* view = GetView(view_id); if (!view) return false; RootNodeManager::ScopedChange change( @@ -173,6 +181,7 @@ bool ViewManagerConnection::DeleteViewImpl(ViewManagerConnection* source, view->node()->SetView(NULL); view_map_.erase(view_id.view_id); delete view; + context()->NotifyViewDeleted(view_id); return true; } @@ -182,7 +191,7 @@ bool ViewManagerConnection::SetViewImpl(const NodeId& node_id, Node* node = GetNode(node_id); if (!node) return false; - View* view = GetView(view_id); + service::View* view = GetView(view_id); if (!view && view_id != ViewId()) return false; RootNodeManager::ScopedChange change( @@ -276,7 +285,7 @@ void ViewManagerConnection::CreateView( callback.Run(false); return; } - view_map_[view_id] = new View(ViewId(id_, view_id)); + view_map_[view_id] = new service::View(ViewId(id_, view_id)); callback.Run(true); } @@ -305,7 +314,7 @@ void ViewManagerConnection::SetViewContents( TransportViewId view_id, ScopedSharedBufferHandle buffer, uint32_t buffer_size) { - View* view = GetView(ViewIdFromTransportId(view_id)); + service::View* view = GetView(ViewIdFromTransportId(view_id)); if (!view) return; void* handle_data; diff --git a/mojo/services/view_manager/view_manager_connection.h b/mojo/services/view_manager/view_manager_connection.h index bebbee9..c095ad1 100644 --- a/mojo/services/view_manager/view_manager_connection.h +++ b/mojo/services/view_manager/view_manager_connection.h @@ -21,7 +21,9 @@ namespace view_manager { class Node; class RootNodeManager; +namespace service { class View; +} #if defined(OS_WIN) // Equivalent of NON_EXPORTED_BASE which does not work with the template snafu @@ -48,7 +50,7 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerConnection Node* GetNode(const NodeId& id); // Returns the View with the specified id. - View* GetView(const ViewId& id); + service::View* GetView(const ViewId& id); // Notifies the client of a hierarchy change. void NotifyNodeHierarchyChanged(const NodeId& node, @@ -63,10 +65,13 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerConnection void NotifyNodeDeleted(const NodeId& node, TransportChangeId server_change_id, TransportChangeId client_change_id); + void NotifyViewDeleted(const ViewId& view, + TransportChangeId server_change_id, + TransportChangeId client_change_id); private: typedef std::map<TransportConnectionSpecificNodeId, Node*> NodeMap; - typedef std::map<TransportConnectionSpecificViewId, View*> ViewMap; + typedef std::map<TransportConnectionSpecificViewId, service::View*> ViewMap; // Deletes a node owned by this connection. Returns true on success. |source| // is the connection that originated the change. diff --git a/mojo/services/view_manager/view_manager_connection_unittest.cc b/mojo/services/view_manager/view_manager_connection_unittest.cc index 221e804..8424dd0 100644 --- a/mojo/services/view_manager/view_manager_connection_unittest.cc +++ b/mojo/services/view_manager/view_manager_connection_unittest.cc @@ -239,6 +239,17 @@ class ViewManagerClientImpl : public IViewManagerClient { NodeIdToString(node).c_str())); QuitIfNecessary(); } + virtual void OnViewDeleted(TransportViewId view, + TransportChangeId server_change_id, + TransportChangeId client_change_id) OVERRIDE { + changes_.push_back( + base::StringPrintf( + "ViewDeleted change_id=%d,%d view=%s", + static_cast<int>(client_change_id), + static_cast<int>(client_change_id), + NodeIdToString(view).c_str())); + QuitIfNecessary(); + } virtual void OnNodeViewReplaced(TransportNodeId node, TransportViewId new_view_id, TransportViewId old_view_id, @@ -683,7 +694,7 @@ TEST_F(ViewManagerConnectionTest, SetViewFromSecondConnection) { client_.DoRunLoopUntilChangesCount(1); Changes changes(client_.GetAndClearChanges()); - ASSERT_EQ(1u, changes.size()); + ASSERT_EQ(2u, changes.size()); EXPECT_EQ("change_id=0 node=1,1 new_view=null old_view=2,51", changes[0]); } } |