OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // This is a simple example application (with an embeddable view), which embeds |
| 6 // the Moterm view, uses it to prompt the user, etc. |
| 7 |
| 8 #include <string.h> |
| 9 |
| 10 #include <algorithm> |
| 11 |
| 12 #include "base/bind.h" |
| 13 #include "base/macros.h" |
| 14 #include "base/memory/weak_ptr.h" |
| 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/strings/string_util.h" |
| 17 #include "base/strings/stringprintf.h" |
| 18 #include "examples/window_manager/window_manager.mojom.h" |
| 19 #include "mojo/application/application_runner_chromium.h" |
| 20 #include "mojo/public/c/system/main.h" |
| 21 #include "mojo/public/cpp/application/application_connection.h" |
| 22 #include "mojo/public/cpp/application/application_delegate.h" |
| 23 #include "mojo/public/cpp/application/application_impl.h" |
| 24 #include "mojo/public/cpp/application/connect.h" |
| 25 #include "mojo/public/cpp/bindings/array.h" |
| 26 #include "mojo/public/interfaces/application/service_provider.mojom.h" |
| 27 #include "mojo/public/interfaces/application/shell.mojom.h" |
| 28 #include "mojo/services/files/public/interfaces/file.mojom.h" |
| 29 #include "mojo/services/files/public/interfaces/types.mojom.h" |
| 30 #include "mojo/services/terminal/public/interfaces/terminal.mojom.h" |
| 31 #include "mojo/services/terminal/public/interfaces/terminal_client.mojom.h" |
| 32 #include "mojo/services/view_manager/public/cpp/view.h" |
| 33 #include "mojo/services/view_manager/public/cpp/view_manager.h" |
| 34 #include "mojo/services/view_manager/public/cpp/view_manager_client_factory.h" |
| 35 #include "mojo/services/view_manager/public/cpp/view_manager_delegate.h" |
| 36 #include "mojo/services/view_manager/public/cpp/view_observer.h" |
| 37 |
| 38 // Kind of like |fputs()| (doesn't wait for result). |
| 39 void Fputs(mojo::files::File* file, const char* s) { |
| 40 size_t length = strlen(s); |
| 41 mojo::Array<uint8_t> a(length); |
| 42 memcpy(&a[0], s, length); |
| 43 |
| 44 file->Write(a.Pass(), 0, mojo::files::WHENCE_FROM_CURRENT, |
| 45 mojo::files::File::WriteCallback()); |
| 46 } |
| 47 |
| 48 class MotermExampleAppView : public mojo::ViewObserver { |
| 49 public: |
| 50 explicit MotermExampleAppView(mojo::Shell* shell, mojo::View* view) |
| 51 : shell_(shell), view_(view), moterm_view_(), weak_factory_(this) { |
| 52 view_->AddObserver(this); |
| 53 |
| 54 moterm_view_ = view_->view_manager()->CreateView(); |
| 55 view_->AddChild(moterm_view_); |
| 56 moterm_view_->SetBounds(view_->bounds()); |
| 57 moterm_view_->SetVisible(true); |
| 58 mojo::ServiceProviderPtr moterm_sp; |
| 59 moterm_view_->Embed("mojo:moterm", GetProxy(&moterm_sp), nullptr); |
| 60 moterm_sp->ConnectToService(mojo::terminal::Terminal::Name_, |
| 61 GetProxy(&moterm_terminal_).PassMessagePipe()); |
| 62 Resize(); |
| 63 StartPrompt(true); |
| 64 } |
| 65 |
| 66 ~MotermExampleAppView() override {} |
| 67 |
| 68 private: |
| 69 void Resize() { |
| 70 moterm_terminal_->SetSize(0, 0, false, [](mojo::files::Error error, |
| 71 uint32_t rows, uint32_t columns) { |
| 72 DCHECK_EQ(error, mojo::files::ERROR_OK); |
| 73 DVLOG(1) << "New size: " << rows << "x" << columns; |
| 74 }); |
| 75 } |
| 76 |
| 77 void StartPrompt(bool first_time) { |
| 78 if (!moterm_file_) { |
| 79 moterm_terminal_->Connect(GetProxy(&moterm_file_), false, |
| 80 [](mojo::files::Error error) { |
| 81 DCHECK_EQ(error, mojo::files::ERROR_OK); |
| 82 }); |
| 83 } |
| 84 |
| 85 if (first_time) { |
| 86 // Display some welcome text. |
| 87 Fputs(moterm_file_.get(), |
| 88 "Welcome to " |
| 89 "\x1b[1m\x1b[34mM\x1b[31mo\x1b[33mt\x1b[34me\x1b[32mr\x1b[31mm\n" |
| 90 "\n"); |
| 91 } |
| 92 |
| 93 Fputs(moterm_file_.get(), "\x1b[0m\nWhere do you want to go today?\n:) "); |
| 94 moterm_file_->Read(1000, 0, mojo::files::WHENCE_FROM_CURRENT, |
| 95 base::Bind(&MotermExampleAppView::OnInputFromPrompt, |
| 96 weak_factory_.GetWeakPtr())); |
| 97 } |
| 98 void OnInputFromPrompt(mojo::files::Error error, |
| 99 mojo::Array<uint8_t> bytes_read) { |
| 100 if (error != mojo::files::ERROR_OK || !bytes_read) { |
| 101 // TODO(vtl): Handle errors? |
| 102 NOTIMPLEMENTED(); |
| 103 return; |
| 104 } |
| 105 |
| 106 std::string dest_url; |
| 107 if (bytes_read.size() >= 1) { |
| 108 base::TrimWhitespaceASCII( |
| 109 std::string(reinterpret_cast<const char*>(&bytes_read[0]), |
| 110 bytes_read.size()), |
| 111 base::TRIM_ALL, &dest_url); |
| 112 } |
| 113 |
| 114 if (dest_url.empty()) { |
| 115 Fputs(moterm_file_.get(), "\nError: no destination URL given\n"); |
| 116 StartPrompt(false); |
| 117 return; |
| 118 } |
| 119 |
| 120 Fputs(moterm_file_.get(), |
| 121 base::StringPrintf("\nGoing to %s ...\n", dest_url.c_str()).c_str()); |
| 122 moterm_file_.reset(); |
| 123 |
| 124 mojo::ServiceProviderPtr dest_sp; |
| 125 shell_->ConnectToApplication(dest_url, GetProxy(&dest_sp), nullptr); |
| 126 mojo::terminal::TerminalClientPtr dest_terminal_client; |
| 127 mojo::ConnectToService(dest_sp.get(), &dest_terminal_client); |
| 128 moterm_terminal_->ConnectToClient( |
| 129 dest_terminal_client.Pass(), true, |
| 130 base::Bind(&MotermExampleAppView::OnDestinationDone, |
| 131 weak_factory_.GetWeakPtr())); |
| 132 } |
| 133 void OnDestinationDone(mojo::files::Error error) { |
| 134 // We should always succeed. (It'll only fail on synchronous failures, which |
| 135 // only occur when it's busy.) |
| 136 DCHECK_EQ(error, mojo::files::ERROR_OK); |
| 137 StartPrompt(false); |
| 138 } |
| 139 |
| 140 // |ViewObserver|: |
| 141 void OnViewDestroyed(mojo::View* view) override { |
| 142 DCHECK(view == view_); |
| 143 delete this; |
| 144 } |
| 145 |
| 146 void OnViewBoundsChanged(mojo::View* view, |
| 147 const mojo::Rect& old_bounds, |
| 148 const mojo::Rect& new_bounds) override { |
| 149 DCHECK_EQ(view, view_); |
| 150 moterm_view_->SetBounds(view_->bounds()); |
| 151 Resize(); |
| 152 } |
| 153 |
| 154 mojo::Shell* const shell_; |
| 155 mojo::View* const view_; |
| 156 |
| 157 mojo::View* moterm_view_; |
| 158 mojo::terminal::TerminalPtr moterm_terminal_; |
| 159 // Valid while prompting. |
| 160 mojo::files::FilePtr moterm_file_; |
| 161 |
| 162 base::WeakPtrFactory<MotermExampleAppView> weak_factory_; |
| 163 |
| 164 DISALLOW_COPY_AND_ASSIGN(MotermExampleAppView); |
| 165 }; |
| 166 |
| 167 class MotermExampleApp : public mojo::ApplicationDelegate, |
| 168 public mojo::ViewManagerDelegate { |
| 169 public: |
| 170 MotermExampleApp() : application_impl_() {} |
| 171 ~MotermExampleApp() override {} |
| 172 |
| 173 private: |
| 174 // |mojo::ApplicationDelegate|: |
| 175 void Initialize(mojo::ApplicationImpl* application_impl) override { |
| 176 DCHECK(!application_impl_); |
| 177 application_impl_ = application_impl; |
| 178 view_manager_client_factory_.reset( |
| 179 new mojo::ViewManagerClientFactory(application_impl_->shell(), this)); |
| 180 } |
| 181 |
| 182 bool ConfigureIncomingConnection( |
| 183 mojo::ApplicationConnection* connection) override { |
| 184 connection->AddService(view_manager_client_factory_.get()); |
| 185 return true; |
| 186 } |
| 187 |
| 188 // |mojo::ViewManagerDelegate|: |
| 189 void OnEmbed(mojo::View* root, |
| 190 mojo::InterfaceRequest<mojo::ServiceProvider> services, |
| 191 mojo::ServiceProviderPtr exposed_services) override { |
| 192 new MotermExampleAppView(application_impl_->shell(), root); |
| 193 } |
| 194 |
| 195 void OnViewManagerDisconnected(mojo::ViewManager* view_manager) override { |
| 196 base::MessageLoop::current()->Quit(); |
| 197 } |
| 198 |
| 199 mojo::ApplicationImpl* application_impl_; |
| 200 scoped_ptr<mojo::ViewManagerClientFactory> view_manager_client_factory_; |
| 201 |
| 202 DISALLOW_COPY_AND_ASSIGN(MotermExampleApp); |
| 203 }; |
| 204 |
| 205 MojoResult MojoMain(MojoHandle application_request) { |
| 206 mojo::ApplicationRunnerChromium runner(new MotermExampleApp()); |
| 207 return runner.Run(application_request); |
| 208 } |
OLD | NEW |