summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-13 19:43:09 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-13 19:43:09 +0000
commitf76571ef290da3526c28f10223b083fde8476310 (patch)
tree4272a7311b907466d8f86218ab4a9d64990d22df /mojo
parentc0ccd2c2745aca1b75c8dbefe14adba6a581c990 (diff)
downloadchromium_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')
-rw-r--r--mojo/mojo_services.gypi3
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view.cc82
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager.cc13
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_private.cc12
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_private.h3
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc217
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h13
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_private.cc25
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_private.h46
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_tree_node.cc102
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h6
-rw-r--r--mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc223
-rw-r--r--mojo/services/public/cpp/view_manager/view.h31
-rw-r--r--mojo/services/public/cpp/view_manager/view_manager.h4
-rw-r--r--mojo/services/public/cpp/view_manager/view_observer.h35
-rw-r--r--mojo/services/public/cpp/view_manager/view_tree_node.h8
-rw-r--r--mojo/services/public/cpp/view_manager/view_tree_node_observer.h6
-rw-r--r--mojo/services/public/interfaces/view_manager/view_manager.mojom7
-rw-r--r--mojo/services/view_manager/node.cc2
-rw-r--r--mojo/services/view_manager/node.h8
-rw-r--r--mojo/services/view_manager/root_node_manager.cc11
-rw-r--r--mojo/services/view_manager/root_node_manager.h3
-rw-r--r--mojo/services/view_manager/view.cc2
-rw-r--r--mojo/services/view_manager/view.h5
-rw-r--r--mojo/services/view_manager/view_manager_connection.cc19
-rw-r--r--mojo/services/view_manager/view_manager_connection.h9
-rw-r--r--mojo/services/view_manager/view_manager_connection_unittest.cc13
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]);
}
}