blob: 7af5ba92b112c2e0b7b658901650e283936041b3 [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 <map>
#include "base/bind.h"
#include "base/macros.h"
#include "base/stl_util.h"
#include "examples/bitmap_uploader/bitmap_uploader.h"
#include "examples/wm_flow/app/embedder.mojom.h"
#include "examples/wm_flow/embedded/embeddee.mojom.h"
#include "mojo/application/application_runner_chromium.h"
#include "mojo/common/weak_binding_set.h"
#include "mojo/public/c/system/main.h"
#include "mojo/public/cpp/application/application_connection.h"
#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/application_impl.h"
#include "mojo/public/cpp/application/connect.h"
#include "mojo/public/cpp/application/interface_factory_impl.h"
#include "mojo/public/cpp/application/service_provider_impl.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/interfaces/application/service_provider.mojom.h"
#include "mojo/services/view_manager/public/cpp/view.h"
#include "mojo/services/view_manager/public/cpp/view_manager.h"
#include "mojo/services/view_manager/public/cpp/view_manager_client_factory.h"
#include "mojo/services/view_manager/public/cpp/view_manager_context.h"
#include "mojo/services/view_manager/public/cpp/view_manager_delegate.h"
#include "mojo/services/view_manager/public/cpp/view_observer.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
namespace examples {
namespace {
const SkColor kColors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorYELLOW };
class EmbedderImpl : public Embedder {
public:
explicit EmbedderImpl(mojo::InterfaceRequest<Embedder> request)
: binding_(this, request.Pass()) {}
~EmbedderImpl() override {}
private:
// Overridden from Embedder:
void HelloWorld(const mojo::Callback<void()>& callback) override {
callback.Run();
}
mojo::StrongBinding<Embedder> binding_;
DISALLOW_COPY_AND_ASSIGN(EmbedderImpl);
};
class EmbedderImplProvider : public mojo::ServiceProvider {
public:
EmbedderImplProvider() {}
~EmbedderImplProvider() override {}
void AddBinding(mojo::InterfaceRequest<mojo::ServiceProvider> request) {
embeddee_exposed_services_.AddBinding(this, request.Pass());
}
private:
// mojo::ServiceProvider implementation
void ConnectToService(const mojo::String& interface_name,
mojo::ScopedMessagePipeHandle pipe_handle) override {
if (interface_name != Embedder::Name_)
return;
new EmbedderImpl(mojo::MakeRequest<Embedder>(pipe_handle.Pass()));
}
mojo::WeakBindingSet<mojo::ServiceProvider> embeddee_exposed_services_;
DISALLOW_COPY_AND_ASSIGN(EmbedderImplProvider);
};
} // namespace
// This app starts its life via Connect() rather than by being embed, so it does
// not start with a connection to the ViewManager service. It has to obtain a
// connection by connecting to the ViewManagerInit service and asking to be
// embed without a view context.
class WMFlowApp : public mojo::ApplicationDelegate,
public mojo::ViewManagerDelegate,
public mojo::ViewObserver {
public:
WMFlowApp() : shell_(nullptr), embed_count_(0) {}
~WMFlowApp() override { STLDeleteValues(&uploaders_); }
private:
typedef std::map<mojo::View*, mojo::BitmapUploader*> ViewToUploader;
// Overridden from ApplicationDelegate:
void Initialize(mojo::ApplicationImpl* app) override {
shell_ = app->shell();
view_manager_client_factory_.reset(
new mojo::ViewManagerClientFactory(app->shell(), this));
view_manager_context_.reset(new mojo::ViewManagerContext(app));
// FIXME: Mojo applications don't know their URLs yet:
// https://docs.google.com/a/chromium.org/document/d/1AQ2y6ekzvbdaMF5WrUQmneyXJnke-MnYYL4Gz1AKDos
url_ = GURL(app->args()[1]);
OpenNewWindow();
OpenNewWindow();
OpenNewWindow();
}
bool ConfigureIncomingConnection(
mojo::ApplicationConnection* connection) override {
connection->AddService(view_manager_client_factory_.get());
return true;
}
// Overridden from mojo::ViewManagerDelegate:
void OnEmbed(mojo::View* root,
mojo::InterfaceRequest<mojo::ServiceProvider> services,
mojo::ServiceProviderPtr exposed_services) override {
root->AddObserver(this);
mojo::BitmapUploader* uploader = new mojo::BitmapUploader(root);
uploaders_[root] = uploader;
uploader->Init(shell_);
// BitmapUploader does not track view size changes, we would
// need to subscribe to OnViewBoundsChanged and tell the bitmap uploader
// to invalidate itself. This is better done once if had a per-view
// object instead of holding per-view state on the ApplicationDelegate.
uploader->SetColor(kColors[embed_count_++ % arraysize(kColors)]);
mojo::View* embed = root->view_manager()->CreateView();
root->AddChild(embed);
mojo::Rect bounds;
bounds.x = bounds.y = 25;
bounds.width = root->bounds().width - 50;
bounds.height = root->bounds().height - 50;
embed->SetBounds(bounds);
embed->SetVisible(true);
mojo::ServiceProviderPtr embedee_exposed_services;
embeddee_provider_.AddBinding(GetProxy(&embedee_exposed_services));
GURL embedded_app_url = url_.Resolve("wm_flow_embedded.mojo");
mojo::ServiceProviderPtr imported;
embed->Embed(embedded_app_url.spec(), GetProxy(&imported),
embedee_exposed_services.Pass());
// FIXME: This is wrong. We're storing per-view state on this per-app
// delegate. Every time a new view is created embedee_ is replaced
// causing the previous one to shut down. This class should not
// be a ViewManagerDelegate, but rather a separate object should be
// created for each embedding.
mojo::ConnectToService(imported.get(), &embeddee_);
embeddee_->HelloBack(base::Bind(&WMFlowApp::HelloBackAck,
base::Unretained(this)));
}
void OnViewManagerDisconnected(mojo::ViewManager* view_manager) override {
STLDeleteValues(&uploaders_);
}
// Overridden from mojo::ViewObserver:
void OnViewInputEvent(mojo::View* view,
const mojo::EventPtr& event) override {
if (event->action == mojo::EVENT_TYPE_POINTER_UP &&
event->flags & mojo::EVENT_FLAGS_LEFT_MOUSE_BUTTON) {
OpenNewWindow();
}
}
void OnViewDestroyed(mojo::View* view) override {
if (uploaders_.find(view) != uploaders_.end()) {
delete uploaders_[view];
uploaders_.erase(view);
}
--embed_count_;
view->RemoveObserver(this);
}
void HelloBackAck() {
printf("HelloBack() ack'ed\n");
}
void OpenNewWindow() { view_manager_context_->Embed(url_.spec()); }
mojo::Shell* shell_;
int embed_count_;
scoped_ptr<mojo::ViewManagerClientFactory> view_manager_client_factory_;
scoped_ptr<mojo::ViewManagerContext> view_manager_context_;
EmbeddeePtr embeddee_;
EmbedderImplProvider embeddee_provider_;
ViewToUploader uploaders_;
GURL url_;
DISALLOW_COPY_AND_ASSIGN(WMFlowApp);
};
} // namespace examples
MojoResult MojoMain(MojoHandle application_request) {
mojo::ApplicationRunnerChromium runner(new examples::WMFlowApp);
return runner.Run(application_request);
}