blob: b88e1a3108c058a7adf6e7e9a99d2ad9e8edc9bd [file] [log] [blame]
// 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/view_manager/root_node_manager.h"
#include "base/logging.h"
#include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
#include "mojo/services/view_manager/view_manager_connection.h"
#include "ui/aura/env.h"
namespace mojo {
namespace view_manager {
namespace service {
RootNodeManager::ScopedChange::ScopedChange(
ViewManagerConnection* connection,
RootNodeManager* root,
RootNodeManager::ChangeType change_type,
bool is_delete_node)
: root_(root),
change_type_(change_type) {
root_->PrepareForChange(connection, is_delete_node);
}
RootNodeManager::ScopedChange::~ScopedChange() {
root_->FinishChange(change_type_);
}
RootNodeManager::Context::Context() {
// Pass in false as native viewport creates the PlatformEventSource.
aura::Env::CreateInstance(false);
}
RootNodeManager::Context::~Context() {
aura::Env::DeleteInstance();
}
RootNodeManager::RootNodeManager(ServiceProvider* service_provider,
RootViewManagerDelegate* view_manager_delegate)
: service_provider_(service_provider),
next_connection_id_(1),
next_server_change_id_(1),
change_source_(kRootConnection),
is_processing_delete_node_(false),
root_view_manager_(service_provider, this, view_manager_delegate),
root_(this, RootNodeId()) {
}
RootNodeManager::~RootNodeManager() {
while (!connections_created_by_connect_.empty())
delete *(connections_created_by_connect_.begin());
// All the connections should have been destroyed.
DCHECK(connection_map_.empty());
}
TransportConnectionId RootNodeManager::GetAndAdvanceNextConnectionId() {
const TransportConnectionId id = next_connection_id_++;
DCHECK_LT(id, next_connection_id_);
return id;
}
void RootNodeManager::AddConnection(ViewManagerConnection* connection) {
DCHECK_EQ(0u, connection_map_.count(connection->id()));
connection_map_[connection->id()] = connection;
}
void RootNodeManager::RemoveConnection(ViewManagerConnection* connection) {
connection_map_.erase(connection->id());
connections_created_by_connect_.erase(connection);
}
void RootNodeManager::InitialConnect(const std::string& url) {
CHECK(connection_map_.empty());
Array<TransportNodeId> roots(0);
ConnectImpl(String::From(url), roots);
}
void RootNodeManager::Connect(const String& url,
const Array<TransportNodeId>& node_ids) {
CHECK_GT(node_ids.size(), 0u);
ConnectImpl(url, node_ids)->set_delete_on_connection_error();
}
ViewManagerConnection* RootNodeManager::GetConnection(
TransportConnectionId connection_id) {
ConnectionMap::iterator i = connection_map_.find(connection_id);
return i == connection_map_.end() ? NULL : i->second;
}
Node* RootNodeManager::GetNode(const NodeId& id) {
if (id == root_.id())
return &root_;
ConnectionMap::iterator i = connection_map_.find(id.connection_id);
return i == connection_map_.end() ? NULL : i->second->GetNode(id);
}
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);
}
void RootNodeManager::ProcessNodeBoundsChanged(const Node* node,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) {
for (ConnectionMap::iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
i->second->ProcessNodeBoundsChanged(node, old_bounds, new_bounds,
IsChangeSource(i->first));
}
}
void RootNodeManager::ProcessNodeHierarchyChanged(const Node* node,
const Node* new_parent,
const Node* old_parent) {
for (ConnectionMap::iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
i->second->ProcessNodeHierarchyChanged(
node, new_parent, old_parent, next_server_change_id_,
IsChangeSource(i->first));
}
}
void RootNodeManager::ProcessNodeViewReplaced(const Node* node,
const View* new_view,
const View* old_view) {
for (ConnectionMap::iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
i->second->ProcessNodeViewReplaced(node, new_view, old_view,
IsChangeSource(i->first));
}
}
void RootNodeManager::ProcessNodeDeleted(const NodeId& node) {
for (ConnectionMap::iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
i->second->ProcessNodeDeleted(node, next_server_change_id_,
IsChangeSource(i->first));
}
}
void RootNodeManager::ProcessViewDeleted(const ViewId& view) {
for (ConnectionMap::iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
i->second->ProcessViewDeleted(view, IsChangeSource(i->first));
}
}
void RootNodeManager::PrepareForChange(ViewManagerConnection* connection,
bool is_delete_node) {
// Should only ever have one change in flight.
DCHECK_EQ(kRootConnection, change_source_);
change_source_ = connection->id();
is_processing_delete_node_ = is_delete_node;
}
void RootNodeManager::FinishChange(ChangeType change_type) {
// PrepareForChange/FinishChange should be balanced.
DCHECK_NE(kRootConnection, change_source_);
change_source_ = 0;
is_processing_delete_node_ = false;
if (change_type == CHANGE_TYPE_ADVANCE_SERVER_CHANGE_ID)
next_server_change_id_++;
}
ViewManagerConnection* RootNodeManager::ConnectImpl(
const String& url,
const Array<TransportNodeId>& node_ids) {
MessagePipe pipe;
service_provider_->ConnectToService(url, pipe.handle1.Pass());
ViewManagerConnection* connection = new ViewManagerConnection(this);
connection->SetRoots(node_ids);
BindToPipe(connection, pipe.handle0.Pass());
connections_created_by_connect_.insert(connection);
return connection;
}
void RootNodeManager::OnNodeHierarchyChanged(const Node* node,
const Node* new_parent,
const Node* old_parent) {
if (!root_view_manager_.in_setup())
ProcessNodeHierarchyChanged(node, new_parent, old_parent);
}
void RootNodeManager::OnNodeViewReplaced(const Node* node,
const View* new_view,
const View* old_view) {
ProcessNodeViewReplaced(node, new_view, old_view);
}
} // namespace service
} // namespace view_manager
} // namespace mojo