OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include "remoting/client/plugin/chromoting_instance.h" | 5 #include "remoting/client/plugin/chromoting_instance.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
15 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
16 #include "base/synchronization/waitable_event.h" | 16 #include "base/synchronization/waitable_event.h" |
17 #include "base/task.h" | 17 #include "base/task.h" |
18 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
19 #include "media/base/media.h" | 19 #include "media/base/media.h" |
20 #include "ppapi/cpp/completion_callback.h" | 20 #include "ppapi/cpp/completion_callback.h" |
21 #include "ppapi/cpp/input_event.h" | 21 #include "ppapi/cpp/input_event.h" |
22 #include "ppapi/cpp/rect.h" | 22 #include "ppapi/cpp/rect.h" |
23 // TODO(wez): Remove this when crbug.com/86353 is complete. | 23 // TODO(wez): Remove this when crbug.com/86353 is complete. |
24 #include "ppapi/cpp/private/var_private.h" | 24 #include "ppapi/cpp/private/var_private.h" |
25 #include "remoting/base/util.h" | 25 #include "remoting/base/util.h" |
26 #include "remoting/client/client_config.h" | 26 #include "remoting/client/client_config.h" |
27 #include "remoting/client/chromoting_client.h" | 27 #include "remoting/client/chromoting_client.h" |
| 28 #include "remoting/client/mouse_input_filter.h" |
28 #include "remoting/client/plugin/chromoting_scriptable_object.h" | 29 #include "remoting/client/plugin/chromoting_scriptable_object.h" |
29 #include "remoting/client/plugin/pepper_input_handler.h" | 30 #include "remoting/client/plugin/pepper_input_handler.h" |
30 #include "remoting/client/plugin/pepper_view.h" | 31 #include "remoting/client/plugin/pepper_view.h" |
31 #include "remoting/client/plugin/pepper_view_proxy.h" | 32 #include "remoting/client/plugin/pepper_view_proxy.h" |
32 #include "remoting/client/plugin/pepper_xmpp_proxy.h" | 33 #include "remoting/client/plugin/pepper_xmpp_proxy.h" |
33 #include "remoting/client/rectangle_update_decoder.h" | 34 #include "remoting/client/rectangle_update_decoder.h" |
34 #include "remoting/protocol/connection_to_host.h" | 35 #include "remoting/protocol/connection_to_host.h" |
35 #include "remoting/protocol/host_stub.h" | 36 #include "remoting/protocol/host_stub.h" |
| 37 #include "remoting/protocol/key_event_tracker.h" |
36 | 38 |
37 namespace remoting { | 39 namespace remoting { |
38 | 40 |
39 // This flag blocks LOGs to the UI if we're already in the middle of logging | 41 // This flag blocks LOGs to the UI if we're already in the middle of logging |
40 // to the UI. This prevents a potential infinite loop if we encounter an error | 42 // to the UI. This prevents a potential infinite loop if we encounter an error |
41 // while sending the log message to the UI. | 43 // while sending the log message to the UI. |
42 static bool g_logging_to_plugin = false; | 44 static bool g_logging_to_plugin = false; |
43 static bool g_has_logging_instance = false; | 45 static bool g_has_logging_instance = false; |
44 static ChromotingInstance* g_logging_instance = NULL; | 46 static ChromotingInstance* g_logging_instance = NULL; |
45 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 47 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 view_->SetSolidFill(0xFFCDCDCD); | 128 view_->SetSolidFill(0xFFCDCDCD); |
127 | 129 |
128 return true; | 130 return true; |
129 } | 131 } |
130 | 132 |
131 void ChromotingInstance::Connect(const ClientConfig& config) { | 133 void ChromotingInstance::Connect(const ClientConfig& config) { |
132 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 134 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
133 | 135 |
134 host_connection_.reset(new protocol::ConnectionToHost( | 136 host_connection_.reset(new protocol::ConnectionToHost( |
135 context_.network_message_loop(), this, true)); | 137 context_.network_message_loop(), this, true)); |
136 | |
137 input_handler_.reset(new PepperInputHandler(&context_, | |
138 host_connection_.get(), | |
139 view_proxy_)); | |
140 | |
141 client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), | 138 client_.reset(new ChromotingClient(config, &context_, host_connection_.get(), |
142 view_proxy_, rectangle_decoder_.get(), | 139 view_proxy_, rectangle_decoder_.get(), |
143 input_handler_.get(), base::Closure())); | 140 base::Closure())); |
144 | 141 |
145 LOG(INFO) << "Connecting to " << config.host_jid | 142 LOG(INFO) << "Connecting to " << config.host_jid |
146 << ". Local jid: " << config.local_jid << "."; | 143 << ". Local jid: " << config.local_jid << "."; |
147 | 144 |
148 // Setup the XMPP Proxy. | 145 // Setup the XMPP Proxy. |
149 ChromotingScriptableObject* scriptable_object = GetScriptableObject(); | 146 ChromotingScriptableObject* scriptable_object = GetScriptableObject(); |
150 scoped_refptr<PepperXmppProxy> xmpp_proxy = | 147 scoped_refptr<PepperXmppProxy> xmpp_proxy = |
151 new PepperXmppProxy(scriptable_object->AsWeakPtr(), | 148 new PepperXmppProxy(scriptable_object->AsWeakPtr(), |
152 plugin_message_loop_, | 149 plugin_message_loop_, |
153 context_.network_message_loop()); | 150 context_.network_message_loop()); |
(...skipping 15 matching lines...) Expand all Loading... |
169 if (client_.get()) { | 166 if (client_.get()) { |
170 // TODO(sergeyu): Should we disconnect asynchronously? | 167 // TODO(sergeyu): Should we disconnect asynchronously? |
171 base::WaitableEvent done_event(true, false); | 168 base::WaitableEvent done_event(true, false); |
172 client_->Stop(base::Bind(&base::WaitableEvent::Signal, | 169 client_->Stop(base::Bind(&base::WaitableEvent::Signal, |
173 base::Unretained(&done_event))); | 170 base::Unretained(&done_event))); |
174 done_event.Wait(); | 171 done_event.Wait(); |
175 client_.reset(); | 172 client_.reset(); |
176 } | 173 } |
177 | 174 |
178 input_handler_.reset(); | 175 input_handler_.reset(); |
| 176 key_event_tracker_.reset(); |
| 177 mouse_input_filter_.reset(); |
179 host_connection_.reset(); | 178 host_connection_.reset(); |
180 | 179 |
181 GetScriptableObject()->SetConnectionStatus( | 180 GetScriptableObject()->SetConnectionStatus( |
182 ChromotingScriptableObject::STATUS_CLOSED, | 181 ChromotingScriptableObject::STATUS_CLOSED, |
183 ChromotingScriptableObject::ERROR_NONE); | 182 ChromotingScriptableObject::ERROR_NONE); |
184 } | 183 } |
185 | 184 |
186 void ChromotingInstance::DidChangeView(const pp::Rect& position, | 185 void ChromotingInstance::DidChangeView(const pp::Rect& position, |
187 const pp::Rect& clip) { | 186 const pp::Rect& clip) { |
188 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 187 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
189 | 188 |
190 view_->SetPluginSize(SkISize::Make(position.width(), position.height())); | 189 SkISize new_size = SkISize::Make(position.width(), position.height()); |
191 | 190 if (view_->GetViewDimensions() != new_size) { |
192 // TODO(wez): Pass the dimensions of the plugin to the RectangleDecoder | 191 view_->SetPluginSize(new_size); |
193 // and let it generate the necessary refresh events. | 192 if (mouse_input_filter_.get()) { |
194 // If scale-to-fit is enabled then update the scaling ratios. | 193 mouse_input_filter_->SetInputDimensions(new_size); |
195 // We also force a full-frame refresh, in case the ratios changed. | 194 } |
196 if (scale_to_fit_) { | 195 rectangle_decoder_->SetOutputDimensions(new_size); |
197 rectangle_decoder_->SetScaleRatios(view_->GetHorizontalScaleRatio(), | |
198 view_->GetVerticalScaleRatio()); | |
199 rectangle_decoder_->RefreshFullFrame(); | |
200 } | 196 } |
201 | 197 |
202 // Notify the RectangleDecoder of the new clip rect. | |
203 rectangle_decoder_->UpdateClipRect( | 198 rectangle_decoder_->UpdateClipRect( |
204 SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height())); | 199 SkIRect::MakeXYWH(clip.x(), clip.y(), clip.width(), clip.height())); |
205 } | 200 } |
206 | 201 |
207 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { | 202 bool ChromotingInstance::HandleInputEvent(const pp::InputEvent& event) { |
208 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 203 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
209 if (!input_handler_.get()) { | 204 |
| 205 // Never inject events if the end of the input pipeline doesn't exist. |
| 206 // If it does exist but the pipeline doesn't, construct a pipeline. |
| 207 // TODO(wez): This is really ugly. We should create the pipeline when |
| 208 // the ConnectionToHost's InputStub exists. |
| 209 if (!host_connection_.get()) { |
210 return false; | 210 return false; |
| 211 } else if (!input_handler_.get()) { |
| 212 protocol::InputStub* input_stub = host_connection_->input_stub(); |
| 213 if (!input_stub) |
| 214 return false; |
| 215 mouse_input_filter_.reset(new MouseInputFilter(input_stub)); |
| 216 mouse_input_filter_->SetInputDimensions(view_->GetViewDimensions()); |
| 217 key_event_tracker_.reset( |
| 218 new protocol::KeyEventTracker(mouse_input_filter_.get())); |
| 219 input_handler_.reset( |
| 220 new PepperInputHandler(key_event_tracker_.get())); |
211 } | 221 } |
212 | 222 |
213 PepperInputHandler* pih | 223 // TODO(wez): When we have a good hook into Host dimensions changes, move |
214 = static_cast<PepperInputHandler*>(input_handler_.get()); | 224 // this there. |
| 225 mouse_input_filter_->SetOutputDimensions(view_->GetHostDimensions()); |
215 | 226 |
216 switch (event.GetType()) { | 227 return input_handler_->HandleInputEvent(event); |
217 case PP_INPUTEVENT_TYPE_MOUSEDOWN: { | |
218 pih->HandleMouseButtonEvent(true, pp::MouseInputEvent(event)); | |
219 return true; | |
220 } | |
221 | |
222 case PP_INPUTEVENT_TYPE_MOUSEUP: { | |
223 pih->HandleMouseButtonEvent(false, pp::MouseInputEvent(event)); | |
224 return true; | |
225 } | |
226 | |
227 case PP_INPUTEVENT_TYPE_MOUSEMOVE: | |
228 case PP_INPUTEVENT_TYPE_MOUSEENTER: | |
229 case PP_INPUTEVENT_TYPE_MOUSELEAVE: { | |
230 pih->HandleMouseMoveEvent(pp::MouseInputEvent(event)); | |
231 return true; | |
232 } | |
233 | |
234 case PP_INPUTEVENT_TYPE_WHEEL: { | |
235 pih->HandleMouseWheelEvent(pp::WheelInputEvent(event)); | |
236 return true; | |
237 } | |
238 | |
239 case PP_INPUTEVENT_TYPE_CONTEXTMENU: { | |
240 // We need to return true here or else we'll get a local (plugin) context | |
241 // menu instead of the mouseup event for the right click. | |
242 return true; | |
243 } | |
244 | |
245 case PP_INPUTEVENT_TYPE_KEYDOWN: { | |
246 pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); | |
247 VLOG(3) << "PP_INPUTEVENT_TYPE_KEYDOWN" << " key=" << key.GetKeyCode(); | |
248 pih->HandleKeyEvent(true, key); | |
249 return true; | |
250 } | |
251 | |
252 case PP_INPUTEVENT_TYPE_KEYUP: { | |
253 pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); | |
254 VLOG(3) << "PP_INPUTEVENT_TYPE_KEYUP" << " key=" << key.GetKeyCode(); | |
255 pih->HandleKeyEvent(false, key); | |
256 return true; | |
257 } | |
258 | |
259 case PP_INPUTEVENT_TYPE_CHAR: { | |
260 pih->HandleCharacterEvent(pp::KeyboardInputEvent(event)); | |
261 return true; | |
262 } | |
263 | |
264 default: { | |
265 LOG(INFO) << "Unhandled input event: " << event.GetType(); | |
266 break; | |
267 } | |
268 } | |
269 | |
270 return false; | |
271 } | 228 } |
272 | 229 |
273 ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { | 230 ChromotingScriptableObject* ChromotingInstance::GetScriptableObject() { |
274 pp::VarPrivate object = GetInstanceObject(); | 231 pp::VarPrivate object = GetInstanceObject(); |
275 if (!object.is_undefined()) { | 232 if (!object.is_undefined()) { |
276 pp::deprecated::ScriptableObject* so = object.AsScriptableObject(); | 233 pp::deprecated::ScriptableObject* so = object.AsScriptableObject(); |
277 DCHECK(so != NULL); | 234 DCHECK(so != NULL); |
278 return static_cast<ChromotingScriptableObject*>(so); | 235 return static_cast<ChromotingScriptableObject*>(so); |
279 } | 236 } |
280 LOG(ERROR) << "Unable to get ScriptableObject for Chromoting plugin."; | 237 LOG(ERROR) << "Unable to get ScriptableObject for Chromoting plugin."; |
281 return NULL; | 238 return NULL; |
282 } | 239 } |
283 | 240 |
284 void ChromotingInstance::SetScaleToFit(bool scale_to_fit) { | |
285 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | |
286 | |
287 if (scale_to_fit == scale_to_fit_) | |
288 return; | |
289 | |
290 scale_to_fit_ = scale_to_fit; | |
291 if (scale_to_fit) { | |
292 rectangle_decoder_->SetScaleRatios(view_->GetHorizontalScaleRatio(), | |
293 view_->GetVerticalScaleRatio()); | |
294 } else { | |
295 rectangle_decoder_->SetScaleRatios(1.0, 1.0); | |
296 } | |
297 | |
298 // TODO(wez): The RectangleDecoder should generate refresh events | |
299 // as necessary in response to any scaling change. | |
300 rectangle_decoder_->RefreshFullFrame(); | |
301 } | |
302 | |
303 // static | 241 // static |
304 void ChromotingInstance::RegisterLogMessageHandler() { | 242 void ChromotingInstance::RegisterLogMessageHandler() { |
305 base::AutoLock lock(g_logging_lock.Get()); | 243 base::AutoLock lock(g_logging_lock.Get()); |
306 | 244 |
307 VLOG(1) << "Registering global log handler"; | 245 VLOG(1) << "Registering global log handler"; |
308 | 246 |
309 // Record previous handler so we can call it in a chain. | 247 // Record previous handler so we can call it in a chain. |
310 g_logging_old_handler = logging::GetLogMessageHandler(); | 248 g_logging_old_handler = logging::GetLogMessageHandler(); |
311 | 249 |
312 // Set up log message handler. | 250 // Set up log message handler. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 return instance_object_; | 335 return instance_object_; |
398 } | 336 } |
399 | 337 |
400 ChromotingStats* ChromotingInstance::GetStats() { | 338 ChromotingStats* ChromotingInstance::GetStats() { |
401 if (!client_.get()) | 339 if (!client_.get()) |
402 return NULL; | 340 return NULL; |
403 return client_->GetStats(); | 341 return client_->GetStats(); |
404 } | 342 } |
405 | 343 |
406 void ChromotingInstance::ReleaseAllKeys() { | 344 void ChromotingInstance::ReleaseAllKeys() { |
407 if (!input_handler_.get()) { | 345 if (key_event_tracker_.get()) { |
408 return; | 346 key_event_tracker_->ReleaseAllKeys(); |
409 } | 347 } |
410 | |
411 input_handler_->ReleaseAllKeys(); | |
412 } | 348 } |
413 | 349 |
414 } // namespace remoting | 350 } // namespace remoting |
OLD | NEW |