Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/host/event_executor_linux.h" | 5 #include "remoting/host/event_executor_linux.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 #include <X11/keysym.h> | 8 #include <X11/keysym.h> |
| 9 #include <X11/extensions/XTest.h> | 9 #include <X11/extensions/XTest.h> |
| 10 #include <gdk/gdkx.h> | |
| 10 | 11 |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 13 #include "base/task.h" | 14 #include "base/task.h" |
| 14 #include "remoting/proto/internal.pb.h" | 15 #include "remoting/proto/internal.pb.h" |
| 15 | 16 |
| 16 // TODO(jamiewalch): Class to ensure that XFlush is called regardless of what | |
| 17 // fields are set in the MouseEvent. It's not worth refactoring HandleMouse to | |
| 18 // avoid the early returns because calling XFlush is not really the correct | |
| 19 // way of flushing the XTest requests; instead we should dispatch the requests | |
| 20 // to a suitable UI thread. | |
| 21 namespace { | |
| 22 class ScopedXFlusher { | |
| 23 public: | |
| 24 explicit ScopedXFlusher(Display* display) | |
| 25 : display_(display), needs_flush_(false) { | |
| 26 } | |
| 27 | |
| 28 ~ScopedXFlusher() { | |
| 29 if (needs_flush_) | |
| 30 XFlush(display_); | |
| 31 } | |
| 32 | |
| 33 void SignalFlush() { | |
| 34 needs_flush_ = true; | |
| 35 } | |
| 36 | |
| 37 private: | |
| 38 Display* display_; | |
| 39 bool needs_flush_; | |
| 40 }; | |
| 41 } | |
| 42 | |
| 43 namespace remoting { | 17 namespace remoting { |
| 44 | 18 |
| 45 using protocol::MouseEvent; | 19 using protocol::MouseEvent; |
| 46 using protocol::KeyEvent; | 20 using protocol::KeyEvent; |
| 47 | 21 |
| 48 static int MouseButtonToX11ButtonNumber( | 22 static int MouseButtonToX11ButtonNumber( |
| 49 protocol::MouseEvent::MouseButton button) { | 23 protocol::MouseEvent::MouseButton button) { |
| 50 switch (button) { | 24 switch (button) { |
| 51 case MouseEvent::BUTTON_LEFT: | 25 case MouseEvent::BUTTON_LEFT: |
| 52 return 1; | 26 return 1; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 root_window_(BadValue), | 234 root_window_(BadValue), |
| 261 width_(0), | 235 width_(0), |
| 262 height_(0) { | 236 height_(0) { |
| 263 } | 237 } |
| 264 | 238 |
| 265 EventExecutorLinuxPimpl::~EventExecutorLinuxPimpl() { | 239 EventExecutorLinuxPimpl::~EventExecutorLinuxPimpl() { |
| 266 DeinitXlib(); | 240 DeinitXlib(); |
| 267 } | 241 } |
| 268 | 242 |
| 269 bool EventExecutorLinuxPimpl::Init() { | 243 bool EventExecutorLinuxPimpl::Init() { |
| 270 // TODO(ajwong): We should specify the display string we are attaching to | 244 display_ = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); |
|
awong
2011/02/14 17:27:29
hmm...can we poke a hole into the message loop suc
Jamie
2011/02/14 19:12:38
I agree, but I couldn't see any clean way of doing
| |
| 271 // in the constructor. | |
| 272 display_ = XOpenDisplay(NULL); | |
| 273 if (!display_) { | 245 if (!display_) { |
| 274 LOG(ERROR) << "Unable to open display"; | 246 LOG(ERROR) << "Unable to open display"; |
| 275 return false; | 247 return false; |
| 276 } | 248 } |
| 277 | 249 |
| 278 root_window_ = RootWindow(display_, DefaultScreen(display_)); | 250 root_window_ = RootWindow(display_, DefaultScreen(display_)); |
| 279 if (root_window_ == BadValue) { | 251 if (root_window_ == BadValue) { |
| 280 LOG(ERROR) << "Unable to get the root window"; | 252 LOG(ERROR) << "Unable to get the root window"; |
| 281 DeinitXlib(); | 253 DeinitXlib(); |
| 282 return false; | 254 return false; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 if (keycode == 0) { | 294 if (keycode == 0) { |
| 323 LOG(WARNING) << "Ignoring undefined keysym: " << keysym | 295 LOG(WARNING) << "Ignoring undefined keysym: " << keysym |
| 324 << " for key: " << key_event->keycode(); | 296 << " for key: " << key_event->keycode(); |
| 325 return; | 297 return; |
| 326 } | 298 } |
| 327 | 299 |
| 328 VLOG(3) << "Got pepper key: " << key_event->keycode() | 300 VLOG(3) << "Got pepper key: " << key_event->keycode() |
| 329 << " sending keysym: " << keysym | 301 << " sending keysym: " << keysym |
| 330 << " to keycode: " << keycode; | 302 << " to keycode: " << keycode; |
| 331 XTestFakeKeyEvent(display_, keycode, key_event->pressed(), CurrentTime); | 303 XTestFakeKeyEvent(display_, keycode, key_event->pressed(), CurrentTime); |
| 332 | |
| 333 // TODO(jamiewalch): Get rid of this once we're dispatching to the UI thread. | |
| 334 XFlush(display_); | |
| 335 } | 304 } |
| 336 | 305 |
| 337 void EventExecutorLinuxPimpl::HandleMouse(const MouseEvent* event) { | 306 void EventExecutorLinuxPimpl::HandleMouse(const MouseEvent* event) { |
| 338 ScopedXFlusher flusher(display_); | |
| 339 if (event->has_x() && event->has_y()) { | 307 if (event->has_x() && event->has_y()) { |
| 340 if (event->x() < 0 || event->y() < 0 || | 308 if (event->x() < 0 || event->y() < 0 || |
| 341 event->x() > width_ || event->y() > height_) { | 309 event->x() > width_ || event->y() > height_) { |
| 342 // A misbehaving client may send these. Drop events that are out of range. | 310 // A misbehaving client may send these. Drop events that are out of range. |
| 343 // TODO(ajwong): How can we log this sanely? We don't want to DOS the | 311 // TODO(ajwong): How can we log this sanely? We don't want to DOS the |
| 344 // server with a misbehaving client by logging like crazy. | 312 // server with a misbehaving client by logging like crazy. |
| 345 return; | 313 return; |
| 346 } | 314 } |
| 347 | 315 |
| 348 VLOG(3) << "Moving mouse to " << event->x() | 316 VLOG(3) << "Moving mouse to " << event->x() |
| 349 << "," << event->y(); | 317 << "," << event->y(); |
| 350 flusher.SignalFlush(); | |
| 351 XTestFakeMotionEvent(display_, DefaultScreen(display_), | 318 XTestFakeMotionEvent(display_, DefaultScreen(display_), |
| 352 event->x(), event->y(), | 319 event->x(), event->y(), |
| 353 CurrentTime); | 320 CurrentTime); |
| 354 } | 321 } |
| 355 | 322 |
| 356 if (event->has_button() && event->has_button_down()) { | 323 if (event->has_button() && event->has_button_down()) { |
| 357 int button_number = MouseButtonToX11ButtonNumber(event->button()); | 324 int button_number = MouseButtonToX11ButtonNumber(event->button()); |
| 358 | 325 |
| 359 if (button_number < 0) { | 326 if (button_number < 0) { |
| 360 LOG(WARNING) << "Ignoring unknown button type: " | 327 LOG(WARNING) << "Ignoring unknown button type: " |
| 361 << event->button(); | 328 << event->button(); |
| 362 return; | 329 return; |
| 363 } | 330 } |
| 364 | 331 |
| 365 VLOG(3) << "Button " << event->button() | 332 VLOG(3) << "Button " << event->button() |
| 366 << " received, sending down " << button_number; | 333 << " received, sending down " << button_number; |
| 367 flusher.SignalFlush(); | |
| 368 XTestFakeButtonEvent(display_, button_number, event->button_down(), | 334 XTestFakeButtonEvent(display_, button_number, event->button_down(), |
| 369 CurrentTime); | 335 CurrentTime); |
| 370 } | 336 } |
| 371 | 337 |
| 372 if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) { | 338 if (event->has_wheel_offset_x() && event->has_wheel_offset_y()) { |
| 373 NOTIMPLEMENTED() << "No scroll wheel support yet."; | 339 NOTIMPLEMENTED() << "No scroll wheel support yet."; |
| 374 } | 340 } |
| 375 } | 341 } |
| 376 | 342 |
| 377 void EventExecutorLinuxPimpl::DeinitXlib() { | 343 void EventExecutorLinuxPimpl::DeinitXlib() { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 done->Run(); | 387 done->Run(); |
| 422 delete done; | 388 delete done; |
| 423 } | 389 } |
| 424 | 390 |
| 425 protocol::InputStub* CreateEventExecutor(MessageLoop* message_loop, | 391 protocol::InputStub* CreateEventExecutor(MessageLoop* message_loop, |
| 426 Capturer* capturer) { | 392 Capturer* capturer) { |
| 427 return new EventExecutorLinux(message_loop, capturer); | 393 return new EventExecutorLinux(message_loop, capturer); |
| 428 } | 394 } |
| 429 | 395 |
| 430 } // namespace remoting | 396 } // namespace remoting |
| OLD | NEW |