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 |