Index: mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc |
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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5fe22b4cb9583454cb77dc23e3863b2632c26fcf |
--- /dev/null |
+++ b/mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.cc |
@@ -0,0 +1,261 @@ |
+// 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_manager_synchronizer.h" |
+ |
+#include "base/bind.h" |
+#include "base/message_loop/message_loop.h" |
+#include "mojo/public/cpp/bindings/allocation_scope.h" |
+#include "mojo/public/interfaces/shell/shell.mojom.h" |
+#include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h" |
+ |
+namespace mojo { |
+namespace services { |
+namespace view_manager { |
+ |
+class ViewManagerTransaction { |
+ public: |
+ virtual ~ViewManagerTransaction() {} |
+ |
+ void Commit() { |
+ DCHECK(!committed_); |
+ DoCommit(); |
+ committed_ = true; |
+ } |
+ |
+ bool committed() const { return committed_; } |
+ uint32_t change_id() const { return change_id_; } |
+ |
+ // General callback to be used for commits to the service. |
+ void OnActionCompleted(bool success) { |
+ DCHECK(success); |
+ DoActionCompleted(success); |
+ synchronizer_->RemoveFromPendingQueue(this); |
+ } |
+ |
+ protected: |
+ enum TransactionType { |
+ // Node creation. |
+ TYPE_CREATE_VIEW_TREE_NODE, |
+ // Modifications to the hierarchy (addition of or removal of nodes from a |
+ // parent.) |
+ TYPE_HIERARCHY |
+ }; |
+ |
+ ViewManagerTransaction(TransactionType transaction_type, |
+ ViewManagerSynchronizer* synchronizer) |
+ : transaction_type_(transaction_type), |
+ change_id_(synchronizer->GetNextChangeId()), |
+ committed_(false), |
+ synchronizer_(synchronizer) { |
+ } |
+ |
+ // Overridden to perform transaction-specific commit actions. |
+ virtual void DoCommit() = 0; |
+ |
+ // Overridden to perform transaction-specific cleanup on commit ack from the |
+ // service. |
+ virtual void DoActionCompleted(bool success) = 0; |
+ |
+ IViewManager* service() { return synchronizer_->service_.get(); } |
+ |
+ uint32_t MakeTransportId(uint16_t id) { |
+ return (synchronizer_->connection_id_ << 16) | id; |
+ } |
+ |
+ private: |
+ const TransactionType transaction_type_; |
+ const uint32_t change_id_; |
+ bool committed_; |
+ ViewManagerSynchronizer* synchronizer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ViewManagerTransaction); |
+}; |
+ |
+class CreateViewTreeNodeTransaction |
+ : public ViewManagerTransaction { |
+ public: |
+ CreateViewTreeNodeTransaction(uint16_t node_id, |
+ ViewManagerSynchronizer* synchronizer) |
+ : ViewManagerTransaction(TYPE_CREATE_VIEW_TREE_NODE, synchronizer), |
+ node_id_(node_id) {} |
+ virtual ~CreateViewTreeNodeTransaction() {} |
+ |
+ private: |
+ // Overridden from ViewManagerTransaction: |
+ virtual void DoCommit() OVERRIDE { |
+ service()->CreateNode( |
+ node_id_, |
+ base::Bind(&ViewManagerTransaction::OnActionCompleted, |
+ base::Unretained(this))); |
+ } |
+ |
+ virtual void DoActionCompleted(bool success) OVERRIDE { |
+ // TODO(beng): Failure means we tried to create with an extant id for this |
+ // connection. Figure out what to do. |
+ } |
+ |
+ const uint16_t node_id_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CreateViewTreeNodeTransaction); |
+}; |
+ |
+class HierarchyTransaction : public ViewManagerTransaction { |
+ public: |
+ enum HierarchyChangeType { |
+ TYPE_ADD, |
+ TYPE_REMOVE |
+ }; |
+ HierarchyTransaction(HierarchyChangeType hierarchy_change_type, |
+ uint16_t child_id, |
+ uint16_t parent_id, |
+ ViewManagerSynchronizer* synchronizer) |
+ : ViewManagerTransaction(TYPE_HIERARCHY, synchronizer), |
+ hierarchy_change_type_(hierarchy_change_type), |
+ child_id_(child_id), |
+ parent_id_(parent_id) {} |
+ virtual ~HierarchyTransaction() {} |
+ |
+ private: |
+ // Overridden from ViewManagerTransaction: |
+ virtual void DoCommit() OVERRIDE { |
+ switch (hierarchy_change_type_) { |
+ case TYPE_ADD: |
+ service()->AddNode( |
+ MakeTransportId(parent_id_), |
+ MakeTransportId(child_id_), |
+ change_id(), |
+ base::Bind(&ViewManagerTransaction::OnActionCompleted, |
+ base::Unretained(this))); |
+ break; |
+ case TYPE_REMOVE: |
+ service()->RemoveNodeFromParent( |
+ MakeTransportId(child_id_), |
+ change_id(), |
+ base::Bind(&ViewManagerTransaction::OnActionCompleted, |
+ base::Unretained(this))); |
+ break; |
+ } |
+ } |
+ |
+ virtual void DoActionCompleted(bool success) OVERRIDE { |
+ // TODO(beng): Failure means either one of the nodes specified didn't exist, |
+ // or we passed the same node id for both params. Roll back? |
+ } |
+ |
+ const HierarchyChangeType hierarchy_change_type_; |
+ const uint16_t child_id_; |
+ const uint16_t parent_id_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(HierarchyTransaction); |
+}; |
+ |
+ViewManagerSynchronizer::ViewManagerSynchronizer(ViewManager* view_manager) |
+ : view_manager_(view_manager), |
+ connected_(false), |
+ connection_id_(0), |
+ next_id_(0), |
+ next_change_id_(0) { |
+ InterfacePipe<services::view_manager::IViewManager, AnyInterface> |
+ view_manager_pipe; |
+ AllocationScope scope; |
+ ViewManagerPrivate(view_manager_).shell()->Connect( |
+ "mojo:mojo_view_manager", view_manager_pipe.handle_to_peer.Pass()); |
+ service_.reset(view_manager_pipe.handle_to_self.Pass(), this); |
+} |
+ |
+ViewManagerSynchronizer::~ViewManagerSynchronizer() { |
+} |
+ |
+uint16_t ViewManagerSynchronizer::CreateViewTreeNode() { |
+ uint16_t id = next_id_++; |
+ pending_transactions_.push_back(new CreateViewTreeNodeTransaction(id, this)); |
+ ScheduleSync(); |
+ return id; |
+} |
+ |
+void ViewManagerSynchronizer::AddChild(uint16_t child_id, uint16_t parent_id) { |
+ pending_transactions_.push_back( |
+ new HierarchyTransaction(HierarchyTransaction::TYPE_ADD, |
+ child_id, |
+ parent_id, |
+ this)); |
+ ScheduleSync(); |
+} |
+ |
+void ViewManagerSynchronizer::RemoveChild(uint16_t child_id, |
+ uint16_t parent_id) { |
+ pending_transactions_.push_back( |
+ new HierarchyTransaction(HierarchyTransaction::TYPE_REMOVE, |
+ child_id, |
+ parent_id, |
+ this)); |
+ ScheduleSync(); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// ViewManagerSynchronizer, IViewManagerClient implementation: |
+ |
+void ViewManagerSynchronizer::OnConnectionEstablished(uint16 connection_id) { |
+ connected_ = true; |
+ connection_id_ = connection_id; |
+ ScheduleSync(); |
+} |
+ |
+void ViewManagerSynchronizer::OnNodeHierarchyChanged(uint32_t node, |
+ uint32_t new_parent, |
+ uint32_t old_parent, |
+ uint32_t change_id) { |
+ if (change_id == 0) { |
+ // TODO(beng): Apply changes from another client. |
+ } |
+} |
+ |
+void ViewManagerSynchronizer::OnNodeViewReplaced(uint32_t node, |
+ uint32_t new_view_id, |
+ uint32_t old_view_id, |
+ uint32_t change_id) { |
+ // .. |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// ViewManagerSynchronizer, private: |
+ |
+void ViewManagerSynchronizer::ScheduleSync() { |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&ViewManagerSynchronizer::DoSync, base::Unretained(this))); |
+} |
+ |
+void ViewManagerSynchronizer::DoSync() { |
+ // The service connection may not be set up yet. OnConnectionEstablished() |
+ // will schedule another sync when it is. |
+ if (!connected_) |
+ return; |
+ |
+ Transactions::const_iterator it = pending_transactions_.begin(); |
+ for (; it != pending_transactions_.end(); ++it) { |
+ if (!(*it)->committed()) |
+ (*it)->Commit(); |
+ } |
+} |
+ |
+uint32_t ViewManagerSynchronizer::GetNextChangeId() { |
+ // TODO(beng): deal with change id collisions? Important in the "never ack'ed |
+ // change" case mentioned in OnNodeHierarchyChanged(). |
+ // "0" is a special value passed to other connected clients, so we can't use |
+ // it. |
+ next_change_id_ = std::max(1u, next_change_id_ + 1); |
+ return next_change_id_; |
+} |
+ |
+void ViewManagerSynchronizer::RemoveFromPendingQueue( |
+ ViewManagerTransaction* transaction) { |
+ DCHECK_EQ(transaction, pending_transactions_.front()); |
+ pending_transactions_.erase(pending_transactions_.begin()); |
+} |
+ |
+} // namespace view_manager |
+} // namespace services |
+} // namespace mojo |