| Index: apps/moterm/moterm_example_app.cc
|
| diff --git a/apps/moterm/moterm_example_app.cc b/apps/moterm/moterm_example_app.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..abe3842f53901495845eca5a5228f5a4dd84d17f
|
| --- /dev/null
|
| +++ b/apps/moterm/moterm_example_app.cc
|
| @@ -0,0 +1,208 @@
|
| +// Copyright 2015 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.
|
| +
|
| +// This is a simple example application (with an embeddable view), which embeds
|
| +// the Moterm view, uses it to prompt the user, etc.
|
| +
|
| +#include <string.h>
|
| +
|
| +#include <algorithm>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "examples/window_manager/window_manager.mojom.h"
|
| +#include "mojo/application/application_runner_chromium.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/bindings/array.h"
|
| +#include "mojo/public/interfaces/application/service_provider.mojom.h"
|
| +#include "mojo/public/interfaces/application/shell.mojom.h"
|
| +#include "mojo/services/files/public/interfaces/file.mojom.h"
|
| +#include "mojo/services/files/public/interfaces/types.mojom.h"
|
| +#include "mojo/services/terminal/public/interfaces/terminal.mojom.h"
|
| +#include "mojo/services/terminal/public/interfaces/terminal_client.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_delegate.h"
|
| +#include "mojo/services/view_manager/public/cpp/view_observer.h"
|
| +
|
| +// Kind of like |fputs()| (doesn't wait for result).
|
| +void Fputs(mojo::files::File* file, const char* s) {
|
| + size_t length = strlen(s);
|
| + mojo::Array<uint8_t> a(length);
|
| + memcpy(&a[0], s, length);
|
| +
|
| + file->Write(a.Pass(), 0, mojo::files::WHENCE_FROM_CURRENT,
|
| + mojo::files::File::WriteCallback());
|
| +}
|
| +
|
| +class MotermExampleAppView : public mojo::ViewObserver {
|
| + public:
|
| + explicit MotermExampleAppView(mojo::Shell* shell, mojo::View* view)
|
| + : shell_(shell), view_(view), moterm_view_(), weak_factory_(this) {
|
| + view_->AddObserver(this);
|
| +
|
| + moterm_view_ = view_->view_manager()->CreateView();
|
| + view_->AddChild(moterm_view_);
|
| + moterm_view_->SetBounds(view_->bounds());
|
| + moterm_view_->SetVisible(true);
|
| + mojo::ServiceProviderPtr moterm_sp;
|
| + moterm_view_->Embed("mojo:moterm", GetProxy(&moterm_sp), nullptr);
|
| + moterm_sp->ConnectToService(mojo::terminal::Terminal::Name_,
|
| + GetProxy(&moterm_terminal_).PassMessagePipe());
|
| + Resize();
|
| + StartPrompt(true);
|
| + }
|
| +
|
| + ~MotermExampleAppView() override {}
|
| +
|
| + private:
|
| + void Resize() {
|
| + moterm_terminal_->SetSize(0, 0, false, [](mojo::files::Error error,
|
| + uint32_t rows, uint32_t columns) {
|
| + DCHECK_EQ(error, mojo::files::ERROR_OK);
|
| + DVLOG(1) << "New size: " << rows << "x" << columns;
|
| + });
|
| + }
|
| +
|
| + void StartPrompt(bool first_time) {
|
| + if (!moterm_file_) {
|
| + moterm_terminal_->Connect(GetProxy(&moterm_file_), false,
|
| + [](mojo::files::Error error) {
|
| + DCHECK_EQ(error, mojo::files::ERROR_OK);
|
| + });
|
| + }
|
| +
|
| + if (first_time) {
|
| + // Display some welcome text.
|
| + Fputs(moterm_file_.get(),
|
| + "Welcome to "
|
| + "\x1b[1m\x1b[34mM\x1b[31mo\x1b[33mt\x1b[34me\x1b[32mr\x1b[31mm\n"
|
| + "\n");
|
| + }
|
| +
|
| + Fputs(moterm_file_.get(), "\x1b[0m\nWhere do you want to go today?\n:) ");
|
| + moterm_file_->Read(1000, 0, mojo::files::WHENCE_FROM_CURRENT,
|
| + base::Bind(&MotermExampleAppView::OnInputFromPrompt,
|
| + weak_factory_.GetWeakPtr()));
|
| + }
|
| + void OnInputFromPrompt(mojo::files::Error error,
|
| + mojo::Array<uint8_t> bytes_read) {
|
| + if (error != mojo::files::ERROR_OK || !bytes_read) {
|
| + // TODO(vtl): Handle errors?
|
| + NOTIMPLEMENTED();
|
| + return;
|
| + }
|
| +
|
| + std::string dest_url;
|
| + if (bytes_read.size() >= 1) {
|
| + base::TrimWhitespaceASCII(
|
| + std::string(reinterpret_cast<const char*>(&bytes_read[0]),
|
| + bytes_read.size()),
|
| + base::TRIM_ALL, &dest_url);
|
| + }
|
| +
|
| + if (dest_url.empty()) {
|
| + Fputs(moterm_file_.get(), "\nError: no destination URL given\n");
|
| + StartPrompt(false);
|
| + return;
|
| + }
|
| +
|
| + Fputs(moterm_file_.get(),
|
| + base::StringPrintf("\nGoing to %s ...\n", dest_url.c_str()).c_str());
|
| + moterm_file_.reset();
|
| +
|
| + mojo::ServiceProviderPtr dest_sp;
|
| + shell_->ConnectToApplication(dest_url, GetProxy(&dest_sp), nullptr);
|
| + mojo::terminal::TerminalClientPtr dest_terminal_client;
|
| + mojo::ConnectToService(dest_sp.get(), &dest_terminal_client);
|
| + moterm_terminal_->ConnectToClient(
|
| + dest_terminal_client.Pass(), true,
|
| + base::Bind(&MotermExampleAppView::OnDestinationDone,
|
| + weak_factory_.GetWeakPtr()));
|
| + }
|
| + void OnDestinationDone(mojo::files::Error error) {
|
| + // We should always succeed. (It'll only fail on synchronous failures, which
|
| + // only occur when it's busy.)
|
| + DCHECK_EQ(error, mojo::files::ERROR_OK);
|
| + StartPrompt(false);
|
| + }
|
| +
|
| + // |ViewObserver|:
|
| + void OnViewDestroyed(mojo::View* view) override {
|
| + DCHECK(view == view_);
|
| + delete this;
|
| + }
|
| +
|
| + void OnViewBoundsChanged(mojo::View* view,
|
| + const mojo::Rect& old_bounds,
|
| + const mojo::Rect& new_bounds) override {
|
| + DCHECK_EQ(view, view_);
|
| + moterm_view_->SetBounds(view_->bounds());
|
| + Resize();
|
| + }
|
| +
|
| + mojo::Shell* const shell_;
|
| + mojo::View* const view_;
|
| +
|
| + mojo::View* moterm_view_;
|
| + mojo::terminal::TerminalPtr moterm_terminal_;
|
| + // Valid while prompting.
|
| + mojo::files::FilePtr moterm_file_;
|
| +
|
| + base::WeakPtrFactory<MotermExampleAppView> weak_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MotermExampleAppView);
|
| +};
|
| +
|
| +class MotermExampleApp : public mojo::ApplicationDelegate,
|
| + public mojo::ViewManagerDelegate {
|
| + public:
|
| + MotermExampleApp() : application_impl_() {}
|
| + ~MotermExampleApp() override {}
|
| +
|
| + private:
|
| + // |mojo::ApplicationDelegate|:
|
| + void Initialize(mojo::ApplicationImpl* application_impl) override {
|
| + DCHECK(!application_impl_);
|
| + application_impl_ = application_impl;
|
| + view_manager_client_factory_.reset(
|
| + new mojo::ViewManagerClientFactory(application_impl_->shell(), this));
|
| + }
|
| +
|
| + bool ConfigureIncomingConnection(
|
| + mojo::ApplicationConnection* connection) override {
|
| + connection->AddService(view_manager_client_factory_.get());
|
| + return true;
|
| + }
|
| +
|
| + // |mojo::ViewManagerDelegate|:
|
| + void OnEmbed(mojo::View* root,
|
| + mojo::InterfaceRequest<mojo::ServiceProvider> services,
|
| + mojo::ServiceProviderPtr exposed_services) override {
|
| + new MotermExampleAppView(application_impl_->shell(), root);
|
| + }
|
| +
|
| + void OnViewManagerDisconnected(mojo::ViewManager* view_manager) override {
|
| + base::MessageLoop::current()->Quit();
|
| + }
|
| +
|
| + mojo::ApplicationImpl* application_impl_;
|
| + scoped_ptr<mojo::ViewManagerClientFactory> view_manager_client_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MotermExampleApp);
|
| +};
|
| +
|
| +MojoResult MojoMain(MojoHandle application_request) {
|
| + mojo::ApplicationRunnerChromium runner(new MotermExampleApp());
|
| + return runner.Run(application_request);
|
| +}
|
|
|