普通文本  |  292行  |  9.86 KB

// 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/connection_manager.h"

#include "base/logging.h"
#include "mojo/public/cpp/application/application_connection.h"
#include "mojo/public/interfaces/application/service_provider.mojom.h"
#include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
#include "mojo/services/view_manager/view_manager_service_impl.h"

namespace mojo {
namespace service {

ConnectionManager::ScopedChange::ScopedChange(
    ViewManagerServiceImpl* connection,
    ConnectionManager* connection_manager,
    bool is_delete_view)
    : connection_manager_(connection_manager),
      connection_id_(connection->id()),
      is_delete_view_(is_delete_view) {
  connection_manager_->PrepareForChange(this);
}

ConnectionManager::ScopedChange::~ScopedChange() {
  connection_manager_->FinishChange();
}

ConnectionManager::ConnectionManager(
    ApplicationConnection* app_connection,
    const Callback<void()>& native_viewport_closed_callback)
    : app_connection_(app_connection),
      next_connection_id_(1),
      display_manager_(app_connection,
                       this,
                       native_viewport_closed_callback),
      root_(new ServerView(this, RootViewId())),
      current_change_(NULL) {
  root_->SetBounds(gfx::Rect(800, 600));
}

ConnectionManager::~ConnectionManager() {
  while (!connections_created_by_connect_.empty())
    delete *(connections_created_by_connect_.begin());
  // All the connections should have been destroyed.
  DCHECK(connection_map_.empty());
  root_.reset();
}

ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() {
  const ConnectionSpecificId id = next_connection_id_++;
  DCHECK_LT(id, next_connection_id_);
  return id;
}

void ConnectionManager::AddConnection(ViewManagerServiceImpl* connection) {
  DCHECK_EQ(0u, connection_map_.count(connection->id()));
  connection_map_[connection->id()] = connection;
}

void ConnectionManager::RemoveConnection(ViewManagerServiceImpl* connection) {
  connection_map_.erase(connection->id());
  connections_created_by_connect_.erase(connection);

  // Notify remaining connections so that they can cleanup.
  for (ConnectionMap::const_iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->OnViewManagerServiceImplDestroyed(connection->id());
  }
}

void ConnectionManager::EmbedRoot(
    const std::string& url,
    InterfaceRequest<ServiceProvider> service_provider) {
  if (connection_map_.empty()) {
    EmbedImpl(kInvalidConnectionId,
              String::From(url),
              RootViewId(),
              service_provider.Pass());
    return;
  }
  ViewManagerServiceImpl* connection = GetConnection(kWindowManagerConnection);
  connection->client()->Embed(url, service_provider.Pass());
}

void ConnectionManager::Embed(
    ConnectionSpecificId creator_id,
    const String& url,
    Id transport_view_id,
    InterfaceRequest<ServiceProvider> service_provider) {
  EmbedImpl(creator_id,
            url,
            ViewIdFromTransportId(transport_view_id),
            service_provider.Pass())->set_delete_on_connection_error();
}

ViewManagerServiceImpl* ConnectionManager::GetConnection(
    ConnectionSpecificId connection_id) {
  ConnectionMap::iterator i = connection_map_.find(connection_id);
  return i == connection_map_.end() ? NULL : i->second;
}

ServerView* ConnectionManager::GetView(const ViewId& id) {
  if (id == root_->id())
    return root_.get();
  ConnectionMap::iterator i = connection_map_.find(id.connection_id);
  return i == connection_map_.end() ? NULL : i->second->GetView(id);
}

void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
  if (current_change_)
    current_change_->MarkConnectionAsMessaged(id);
}

bool ConnectionManager::DidConnectionMessageClient(
    ConnectionSpecificId id) const {
  return current_change_ && current_change_->DidMessageConnection(id);
}

const ViewManagerServiceImpl* ConnectionManager::GetConnectionWithRoot(
    const ViewId& id) const {
  for (ConnectionMap::const_iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    if (i->second->HasRoot(id))
      return i->second;
  }
  return NULL;
}

void ConnectionManager::DispatchViewInputEventToWindowManager(EventPtr event) {
  // Input events are forwarded to the WindowManager. The WindowManager
  // eventually calls back to us with DispatchOnViewInputEvent().
  ViewManagerServiceImpl* connection = GetConnection(kWindowManagerConnection);
  if (!connection)
    return;
  connection->client()->DispatchOnViewInputEvent(event.Pass());
}

void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view,
                                                 const gfx::Rect& old_bounds,
                                                 const gfx::Rect& new_bounds) {
  for (ConnectionMap::iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->ProcessViewBoundsChanged(
        view, old_bounds, new_bounds, IsChangeSource(i->first));
  }
}

void ConnectionManager::ProcessWillChangeViewHierarchy(
    const ServerView* view,
    const ServerView* new_parent,
    const ServerView* old_parent) {
  for (ConnectionMap::iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->ProcessWillChangeViewHierarchy(
        view, new_parent, old_parent, IsChangeSource(i->first));
  }
}

void ConnectionManager::ProcessViewHierarchyChanged(
    const ServerView* view,
    const ServerView* new_parent,
    const ServerView* old_parent) {
  for (ConnectionMap::iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->ProcessViewHierarchyChanged(
        view, new_parent, old_parent, IsChangeSource(i->first));
  }
}

void ConnectionManager::ProcessViewReorder(const ServerView* view,
                                           const ServerView* relative_view,
                                           const OrderDirection direction) {
  for (ConnectionMap::iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->ProcessViewReorder(
        view, relative_view, direction, IsChangeSource(i->first));
  }
}

void ConnectionManager::ProcessViewDeleted(const ViewId& view) {
  for (ConnectionMap::iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->ProcessViewDeleted(view, IsChangeSource(i->first));
  }
}

void ConnectionManager::PrepareForChange(ScopedChange* change) {
  // Should only ever have one change in flight.
  CHECK(!current_change_);
  current_change_ = change;
}

void ConnectionManager::FinishChange() {
  // PrepareForChange/FinishChange should be balanced.
  CHECK(current_change_);
  current_change_ = NULL;
}

ViewManagerServiceImpl* ConnectionManager::EmbedImpl(
    const ConnectionSpecificId creator_id,
    const String& url,
    const ViewId& root_id,
    InterfaceRequest<ServiceProvider> service_provider) {
  MessagePipe pipe;

  ServiceProvider* view_manager_service_provider =
      app_connection_->ConnectToApplication(url)->GetServiceProvider();
  view_manager_service_provider->ConnectToService(
      ViewManagerServiceImpl::Client::Name_, pipe.handle1.Pass());

  std::string creator_url;
  ConnectionMap::const_iterator it = connection_map_.find(creator_id);
  if (it != connection_map_.end())
    creator_url = it->second->url();

  ViewManagerServiceImpl* connection =
      new ViewManagerServiceImpl(this,
                                 creator_id,
                                 creator_url,
                                 url.To<std::string>(),
                                 root_id,
                                 service_provider.Pass());
  WeakBindToPipe(connection, pipe.handle0.Pass());
  connections_created_by_connect_.insert(connection);
  OnConnectionMessagedClient(connection->id());
  return connection;
}

void ConnectionManager::OnViewDestroyed(const ServerView* view) {
  ProcessViewDeleted(view->id());
}

void ConnectionManager::OnWillChangeViewHierarchy(
    const ServerView* view,
    const ServerView* new_parent,
    const ServerView* old_parent) {
  if (!display_manager_.in_setup())
    ProcessWillChangeViewHierarchy(view, new_parent, old_parent);
}

void ConnectionManager::OnViewHierarchyChanged(const ServerView* view,
                                               const ServerView* new_parent,
                                               const ServerView* old_parent) {
  if (!display_manager_.in_setup())
    ProcessViewHierarchyChanged(view, new_parent, old_parent);
  // TODO(beng): optimize.
  if (old_parent) {
    display_manager_.SchedulePaint(old_parent,
                                   gfx::Rect(old_parent->bounds().size()));
  }
  if (new_parent) {
    display_manager_.SchedulePaint(new_parent,
                                   gfx::Rect(new_parent->bounds().size()));
  }
}

void ConnectionManager::OnViewBoundsChanged(const ServerView* view,
                                            const gfx::Rect& old_bounds,
                                            const gfx::Rect& new_bounds) {
  ProcessViewBoundsChanged(view, old_bounds, new_bounds);
  if (!view->parent())
    return;

  // TODO(sky): optimize this.
  display_manager_.SchedulePaint(view->parent(), old_bounds);
  display_manager_.SchedulePaint(view->parent(), new_bounds);
}

void ConnectionManager::OnViewSurfaceIdChanged(const ServerView* view) {
  display_manager_.SchedulePaint(view, gfx::Rect(view->bounds().size()));
}

void ConnectionManager::OnWillChangeViewVisibility(const ServerView* view) {
  for (ConnectionMap::iterator i = connection_map_.begin();
       i != connection_map_.end();
       ++i) {
    i->second->ProcessWillChangeViewVisibility(view, IsChangeSource(i->first));
  }
}

}  // namespace service
}  // namespace mojo