OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This is a terminal client (i.e., a "raw" |mojo.terminal.Terminal| -- e.g., | 5 // This is a terminal client (i.e., a "raw" |mojo.terminal.Terminal| -- e.g., |
6 // moterm -- can be asked to talk to this) that prompts the user for a native | 6 // moterm -- can be asked to talk to this) that prompts the user for a native |
7 // (Linux) binary to run and then does so (via mojo:native_support). | 7 // (Linux) binary to run and then does so (via mojo:native_support). |
8 // | 8 // |
9 // E.g., first run mojo:moterm_example_app (embedded by a window manager). Then, | 9 // E.g., first run mojo:moterm_example_app (embedded by a window manager). Then, |
10 // at the prompt, enter "mojo:native_run_app". At the next prompt, enter "bash" | 10 // at the prompt, enter "mojo:native_run_app". At the next prompt, enter "bash" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 terminal_.set_connection_error_handler([this]() { delete this; }); | 47 terminal_.set_connection_error_handler([this]() { delete this; }); |
48 Start(); | 48 Start(); |
49 } | 49 } |
50 ~TerminalConnection() {} | 50 ~TerminalConnection() {} |
51 | 51 |
52 private: | 52 private: |
53 void Write(const char* s, mojo::files::File::WriteCallback callback) { | 53 void Write(const char* s, mojo::files::File::WriteCallback callback) { |
54 size_t length = strlen(s); | 54 size_t length = strlen(s); |
55 mojo::Array<uint8_t> a(length); | 55 mojo::Array<uint8_t> a(length); |
56 memcpy(&a[0], s, length); | 56 memcpy(&a[0], s, length); |
57 terminal_->Write(a.Pass(), 0, mojo::files::WHENCE_FROM_CURRENT, callback); | 57 terminal_->Write(a.Pass(), 0, mojo::files::Whence::FROM_CURRENT, callback); |
58 } | 58 } |
59 | 59 |
60 void Start() { | 60 void Start() { |
61 // TODO(vtl): Check canonical mode (via ioctl) first (or before |Read()|). | 61 // TODO(vtl): Check canonical mode (via ioctl) first (or before |Read()|). |
62 | 62 |
63 const char kPrompt[] = "\x1b[0mNative program to run?\n>>> "; | 63 const char kPrompt[] = "\x1b[0mNative program to run?\n>>> "; |
64 Write(kPrompt, [this](mojo::files::Error error, uint32_t) { | 64 Write(kPrompt, [this](mojo::files::Error error, uint32_t) { |
65 this->DidWritePrompt(error); | 65 this->DidWritePrompt(error); |
66 }); | 66 }); |
67 } | 67 } |
68 void DidWritePrompt(mojo::files::Error error) { | 68 void DidWritePrompt(mojo::files::Error error) { |
69 if (error != mojo::files::ERROR_OK) { | 69 if (error != mojo::files::Error::OK) { |
70 LOG(ERROR) << "Write() error: " << error; | 70 LOG(ERROR) << "Write() error: " << error; |
71 delete this; | 71 delete this; |
72 return; | 72 return; |
73 } | 73 } |
74 | 74 |
75 terminal_->Read( | 75 terminal_->Read( |
76 1000, 0, mojo::files::WHENCE_FROM_CURRENT, | 76 1000, 0, mojo::files::Whence::FROM_CURRENT, |
77 [this](mojo::files::Error error, mojo::Array<uint8_t> bytes_read) { | 77 [this](mojo::files::Error error, mojo::Array<uint8_t> bytes_read) { |
78 this->DidReadFromPrompt(error, bytes_read.Pass()); | 78 this->DidReadFromPrompt(error, bytes_read.Pass()); |
79 }); | 79 }); |
80 } | 80 } |
81 void DidReadFromPrompt(mojo::files::Error error, | 81 void DidReadFromPrompt(mojo::files::Error error, |
82 mojo::Array<uint8_t> bytes_read) { | 82 mojo::Array<uint8_t> bytes_read) { |
83 if (error != mojo::files::ERROR_OK || !bytes_read.size()) { | 83 if (error != mojo::files::Error::OK || !bytes_read.size()) { |
84 LOG(ERROR) << "Read() error: " << error; | 84 LOG(ERROR) << "Read() error: " << error; |
85 delete this; | 85 delete this; |
86 return; | 86 return; |
87 } | 87 } |
88 | 88 |
89 std::string input(reinterpret_cast<const char*>(&bytes_read[0]), | 89 std::string input(reinterpret_cast<const char*>(&bytes_read[0]), |
90 bytes_read.size()); | 90 bytes_read.size()); |
91 command_line_.clear(); | 91 command_line_.clear(); |
92 base::SplitStringAlongWhitespace(input, &command_line_); | 92 base::SplitStringAlongWhitespace(input, &command_line_); |
93 | 93 |
(...skipping 10 matching lines...) Expand all Loading... |
104 mojo::Array<uint32_t> in_values = mojo::Array<uint32_t>::New(1); | 104 mojo::Array<uint32_t> in_values = mojo::Array<uint32_t>::New(1); |
105 in_values[0] = mojo::files::kIoctlTerminalGetSettings; | 105 in_values[0] = mojo::files::kIoctlTerminalGetSettings; |
106 terminal_->Ioctl( | 106 terminal_->Ioctl( |
107 mojo::files::kIoctlTerminal, in_values.Pass(), | 107 mojo::files::kIoctlTerminal, in_values.Pass(), |
108 [this](mojo::files::Error error, mojo::Array<uint32_t> out_values) { | 108 [this](mojo::files::Error error, mojo::Array<uint32_t> out_values) { |
109 this->DidGetTerminalSettings(error, out_values.Pass()); | 109 this->DidGetTerminalSettings(error, out_values.Pass()); |
110 }); | 110 }); |
111 } | 111 } |
112 void DidGetTerminalSettings(mojo::files::Error error, | 112 void DidGetTerminalSettings(mojo::files::Error error, |
113 mojo::Array<uint32_t> out_values) { | 113 mojo::Array<uint32_t> out_values) { |
114 if (error != mojo::files::ERROR_OK || out_values.size() < 6) { | 114 if (error != mojo::files::Error::OK || out_values.size() < 6) { |
115 LOG(ERROR) << "Ioctl() (terminal get settings) error: " << error; | 115 LOG(ERROR) << "Ioctl() (terminal get settings) error: " << error; |
116 delete this; | 116 delete this; |
117 return; | 117 return; |
118 } | 118 } |
119 | 119 |
120 const size_t kBaseFieldCount = | 120 const size_t kBaseFieldCount = |
121 mojo::files::kIoctlTerminalTermiosBaseFieldCount; | 121 mojo::files::kIoctlTerminalTermiosBaseFieldCount; |
122 const uint32_t kLFlagIdx = mojo::files::kIoctlTerminalTermiosLFlagIndex; | 122 const uint32_t kLFlagIdx = mojo::files::kIoctlTerminalTermiosLFlagIndex; |
123 const uint32_t kLFlagICANON = mojo::files::kIoctlTerminalTermiosLFlagICANON; | 123 const uint32_t kLFlagICANON = mojo::files::kIoctlTerminalTermiosLFlagICANON; |
124 | 124 |
125 auto in_values = mojo::Array<uint32_t>::New(1 + kBaseFieldCount); | 125 auto in_values = mojo::Array<uint32_t>::New(1 + kBaseFieldCount); |
126 in_values[0] = mojo::files::kIoctlTerminalSetSettings; | 126 in_values[0] = mojo::files::kIoctlTerminalSetSettings; |
127 for (size_t i = 0; i < kBaseFieldCount; i++) | 127 for (size_t i = 0; i < kBaseFieldCount; i++) |
128 in_values[1 + i] = out_values[i]; | 128 in_values[1 + i] = out_values[i]; |
129 // Just turn off ICANON, which is in "lflag". | 129 // Just turn off ICANON, which is in "lflag". |
130 in_values[1 + kLFlagIdx] &= ~kLFlagICANON; | 130 in_values[1 + kLFlagIdx] &= ~kLFlagICANON; |
131 terminal_->Ioctl( | 131 terminal_->Ioctl( |
132 mojo::files::kIoctlTerminal, in_values.Pass(), | 132 mojo::files::kIoctlTerminal, in_values.Pass(), |
133 [this](mojo::files::Error error, mojo::Array<uint32_t> out_values) { | 133 [this](mojo::files::Error error, mojo::Array<uint32_t> out_values) { |
134 this->DidSetTerminalSettings(error, out_values.Pass()); | 134 this->DidSetTerminalSettings(error, out_values.Pass()); |
135 }); | 135 }); |
136 } | 136 } |
137 void DidSetTerminalSettings(mojo::files::Error error, | 137 void DidSetTerminalSettings(mojo::files::Error error, |
138 mojo::Array<uint32_t> out_values) { | 138 mojo::Array<uint32_t> out_values) { |
139 if (error != mojo::files::ERROR_OK) { | 139 if (error != mojo::files::Error::OK) { |
140 LOG(ERROR) << "Ioctl() (terminal set settings) error: " << error; | 140 LOG(ERROR) << "Ioctl() (terminal set settings) error: " << error; |
141 delete this; | 141 delete this; |
142 return; | 142 return; |
143 } | 143 } |
144 | 144 |
145 // Now, we can spawn. | 145 // Now, we can spawn. |
146 mojo::String path(command_line_[0]); | 146 mojo::String path(command_line_[0]); |
147 mojo::Array<mojo::String> argv; | 147 mojo::Array<mojo::String> argv; |
148 for (const auto& arg : command_line_) | 148 for (const auto& arg : command_line_) |
149 argv.push_back(arg); | 149 argv.push_back(arg); |
150 | 150 |
151 // TODO(vtl): If the |InterfacePtr| underlying |native_support_process_| | 151 // TODO(vtl): If the |InterfacePtr| underlying |native_support_process_| |
152 // encounters an error, then we're sort of dead in the water. | 152 // encounters an error, then we're sort of dead in the water. |
153 native_support_process_->SpawnWithTerminal( | 153 native_support_process_->SpawnWithTerminal( |
154 path, argv.Pass(), mojo::Array<mojo::String>(), terminal_.Pass(), | 154 path, argv.Pass(), mojo::Array<mojo::String>(), terminal_.Pass(), |
155 GetProxy(&process_controller_), [this](mojo::files::Error error) { | 155 GetProxy(&process_controller_), [this](mojo::files::Error error) { |
156 this->DidSpawnWithTerminal(error); | 156 this->DidSpawnWithTerminal(error); |
157 }); | 157 }); |
158 process_controller_.set_connection_error_handler([this]() { delete this; }); | 158 process_controller_.set_connection_error_handler([this]() { delete this; }); |
159 } | 159 } |
160 void DidSpawnWithTerminal(mojo::files::Error error) { | 160 void DidSpawnWithTerminal(mojo::files::Error error) { |
161 if (error != mojo::files::ERROR_OK) { | 161 if (error != mojo::files::Error::OK) { |
162 LOG(ERROR) << "SpawnWithTerminal() error: " << error; | 162 LOG(ERROR) << "SpawnWithTerminal() error: " << error; |
163 delete this; | 163 delete this; |
164 return; | 164 return; |
165 } | 165 } |
166 process_controller_->Wait( | 166 process_controller_->Wait( |
167 [this](mojo::files::Error error, int32_t exit_status) { | 167 [this](mojo::files::Error error, int32_t exit_status) { |
168 this->DidWait(error, exit_status); | 168 this->DidWait(error, exit_status); |
169 }); | 169 }); |
170 } | 170 } |
171 void DidWait(mojo::files::Error error, int32_t exit_status) { | 171 void DidWait(mojo::files::Error error, int32_t exit_status) { |
172 if (error != mojo::files::ERROR_OK) | 172 if (error != mojo::files::Error::OK) |
173 LOG(ERROR) << "Wait() error: " << error; | 173 LOG(ERROR) << "Wait() error: " << error; |
174 else if (exit_status != 0) // |exit_status| only valid if OK. | 174 else if (exit_status != 0) // |exit_status| only valid if OK. |
175 LOG(ERROR) << "Process exit status: " << exit_status; | 175 LOG(ERROR) << "Process exit status: " << exit_status; |
176 | 176 |
177 // We're done, regardless. | 177 // We're done, regardless. |
178 delete this; | 178 delete this; |
179 } | 179 } |
180 | 180 |
181 mojo::files::FilePtr terminal_; | 181 mojo::files::FilePtr terminal_; |
182 native_support::Process* native_support_process_; | 182 native_support::Process* native_support_process_; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 mojo::ApplicationImpl* application_impl_; | 242 mojo::ApplicationImpl* application_impl_; |
243 native_support::ProcessPtr native_support_process_; | 243 native_support::ProcessPtr native_support_process_; |
244 | 244 |
245 DISALLOW_COPY_AND_ASSIGN(NativeRunApp); | 245 DISALLOW_COPY_AND_ASSIGN(NativeRunApp); |
246 }; | 246 }; |
247 | 247 |
248 MojoResult MojoMain(MojoHandle application_request) { | 248 MojoResult MojoMain(MojoHandle application_request) { |
249 mojo::ApplicationRunnerChromium runner(new NativeRunApp()); | 249 mojo::ApplicationRunnerChromium runner(new NativeRunApp()); |
250 return runner.Run(application_request); | 250 return runner.Run(application_request); |
251 } | 251 } |
OLD | NEW |