| 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 |