Index: remoting/host/local_input_monitor_x11.cc |
diff --git a/remoting/host/local_input_monitor_x11.cc b/remoting/host/local_input_monitor_x11.cc |
deleted file mode 100644 |
index 1da192f0a50abca11db0d66a6ab99ce87d11b0ae..0000000000000000000000000000000000000000 |
--- a/remoting/host/local_input_monitor_x11.cc |
+++ /dev/null |
@@ -1,329 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "remoting/host/local_input_monitor.h" |
- |
-#include <sys/select.h> |
-#include <unistd.h> |
-#define XK_MISCELLANY |
-#include <X11/keysymdef.h> |
- |
-#include "base/basictypes.h" |
-#include "base/bind.h" |
-#include "base/callback.h" |
-#include "base/compiler_specific.h" |
-#include "base/location.h" |
-#include "base/logging.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/message_loop/message_pump_libevent.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/threading/non_thread_safe.h" |
-#include "remoting/host/client_session_control.h" |
-#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" |
- |
-// These includes need to be later than dictated by the style guide due to |
-// Xlib header pollution, specifically the min, max, and Status macros. |
-#include <X11/XKBlib.h> |
-#include <X11/Xlibint.h> |
-#include <X11/extensions/record.h> |
- |
-namespace remoting { |
- |
-namespace { |
- |
-class LocalInputMonitorX11 : public base::NonThreadSafe, |
- public LocalInputMonitor { |
- public: |
- LocalInputMonitorX11( |
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
- base::WeakPtr<ClientSessionControl> client_session_control); |
- ~LocalInputMonitorX11() override; |
- |
- private: |
- // The actual implementation resides in LocalInputMonitorX11::Core class. |
- class Core |
- : public base::RefCountedThreadSafe<Core>, |
- public base::MessagePumpLibevent::Watcher { |
- public: |
- Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
- base::WeakPtr<ClientSessionControl> client_session_control); |
- |
- void Start(); |
- void Stop(); |
- |
- private: |
- friend class base::RefCountedThreadSafe<Core>; |
- ~Core() override; |
- |
- void StartOnInputThread(); |
- void StopOnInputThread(); |
- |
- // base::MessagePumpLibevent::Watcher interface. |
- void OnFileCanReadWithoutBlocking(int fd) override; |
- void OnFileCanWriteWithoutBlocking(int fd) override; |
- |
- // Processes key and mouse events. |
- void ProcessXEvent(xEvent* event); |
- |
- static void ProcessReply(XPointer self, XRecordInterceptData* data); |
- |
- // Task runner on which public methods of this class must be called. |
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
- |
- // Task runner on which X Window events are received. |
- scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_; |
- |
- // Points to the object receiving mouse event notifications and session |
- // disconnect requests. |
- base::WeakPtr<ClientSessionControl> client_session_control_; |
- |
- // Used to receive base::MessagePumpLibevent::Watcher events. |
- base::MessagePumpLibevent::FileDescriptorWatcher controller_; |
- |
- // True when Alt is pressed. |
- bool alt_pressed_; |
- |
- // True when Ctrl is pressed. |
- bool ctrl_pressed_; |
- |
- Display* display_; |
- Display* x_record_display_; |
- XRecordRange* x_record_range_[2]; |
- XRecordContext x_record_context_; |
- |
- DISALLOW_COPY_AND_ASSIGN(Core); |
- }; |
- |
- scoped_refptr<Core> core_; |
- |
- DISALLOW_COPY_AND_ASSIGN(LocalInputMonitorX11); |
-}; |
- |
-LocalInputMonitorX11::LocalInputMonitorX11( |
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
- base::WeakPtr<ClientSessionControl> client_session_control) |
- : core_(new Core(caller_task_runner, |
- input_task_runner, |
- client_session_control)) { |
- core_->Start(); |
-} |
- |
-LocalInputMonitorX11::~LocalInputMonitorX11() { |
- core_->Stop(); |
-} |
- |
-LocalInputMonitorX11::Core::Core( |
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
- base::WeakPtr<ClientSessionControl> client_session_control) |
- : caller_task_runner_(caller_task_runner), |
- input_task_runner_(input_task_runner), |
- client_session_control_(client_session_control), |
- alt_pressed_(false), |
- ctrl_pressed_(false), |
- display_(NULL), |
- x_record_display_(NULL), |
- x_record_context_(0) { |
- DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
- DCHECK(client_session_control_.get()); |
- |
- x_record_range_[0] = NULL; |
- x_record_range_[1] = NULL; |
-} |
- |
-void LocalInputMonitorX11::Core::Start() { |
- DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
- |
- input_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&Core::StartOnInputThread, this)); |
-} |
- |
-void LocalInputMonitorX11::Core::Stop() { |
- DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
- |
- input_task_runner_->PostTask(FROM_HERE, |
- base::Bind(&Core::StopOnInputThread, this)); |
-} |
- |
-LocalInputMonitorX11::Core::~Core() { |
- DCHECK(!display_); |
- DCHECK(!x_record_display_); |
- DCHECK(!x_record_range_[0]); |
- DCHECK(!x_record_range_[1]); |
- DCHECK(!x_record_context_); |
-} |
- |
-void LocalInputMonitorX11::Core::StartOnInputThread() { |
- DCHECK(input_task_runner_->BelongsToCurrentThread()); |
- DCHECK(!display_); |
- DCHECK(!x_record_display_); |
- DCHECK(!x_record_range_[0]); |
- DCHECK(!x_record_range_[1]); |
- DCHECK(!x_record_context_); |
- |
- // TODO(jamiewalch): We should pass the display in. At that point, since |
- // XRecord needs a private connection to the X Server for its data channel |
- // and both channels are used from a separate thread, we'll need to duplicate |
- // them with something like the following: |
- // XOpenDisplay(DisplayString(display)); |
- display_ = XOpenDisplay(NULL); |
- x_record_display_ = XOpenDisplay(NULL); |
- if (!display_ || !x_record_display_) { |
- LOG(ERROR) << "Couldn't open X display"; |
- return; |
- } |
- |
- int xr_opcode, xr_event, xr_error; |
- if (!XQueryExtension(display_, "RECORD", &xr_opcode, &xr_event, &xr_error)) { |
- LOG(ERROR) << "X Record extension not available."; |
- return; |
- } |
- |
- x_record_range_[0] = XRecordAllocRange(); |
- x_record_range_[1] = XRecordAllocRange(); |
- if (!x_record_range_[0] || !x_record_range_[1]) { |
- LOG(ERROR) << "XRecordAllocRange failed."; |
- return; |
- } |
- x_record_range_[0]->device_events.first = MotionNotify; |
- x_record_range_[0]->device_events.last = MotionNotify; |
- x_record_range_[1]->device_events.first = KeyPress; |
- x_record_range_[1]->device_events.last = KeyRelease; |
- XRecordClientSpec client_spec = XRecordAllClients; |
- |
- x_record_context_ = XRecordCreateContext( |
- x_record_display_, 0, &client_spec, 1, x_record_range_, |
- arraysize(x_record_range_)); |
- if (!x_record_context_) { |
- LOG(ERROR) << "XRecordCreateContext failed."; |
- return; |
- } |
- |
- if (!XRecordEnableContextAsync(x_record_display_, x_record_context_, |
- &Core::ProcessReply, |
- reinterpret_cast<XPointer>(this))) { |
- LOG(ERROR) << "XRecordEnableContextAsync failed."; |
- return; |
- } |
- |
- // Register OnFileCanReadWithoutBlocking() to be called every time there is |
- // something to read from |x_record_display_|. |
- base::MessageLoopForIO* message_loop = base::MessageLoopForIO::current(); |
- int result = |
- message_loop->WatchFileDescriptor(ConnectionNumber(x_record_display_), |
- true, |
- base::MessageLoopForIO::WATCH_READ, |
- &controller_, |
- this); |
- if (!result) { |
- LOG(ERROR) << "Failed to create X record task."; |
- return; |
- } |
- |
- // Fetch pending events if any. |
- while (XPending(x_record_display_)) { |
- XEvent ev; |
- XNextEvent(x_record_display_, &ev); |
- } |
-} |
- |
-void LocalInputMonitorX11::Core::StopOnInputThread() { |
- DCHECK(input_task_runner_->BelongsToCurrentThread()); |
- |
- // Context must be disabled via the control channel because we can't send |
- // any X protocol traffic over the data channel while it's recording. |
- if (x_record_context_) { |
- XRecordDisableContext(display_, x_record_context_); |
- XFlush(display_); |
- } |
- |
- controller_.StopWatchingFileDescriptor(); |
- |
- if (x_record_range_[0]) { |
- XFree(x_record_range_[0]); |
- x_record_range_[0] = NULL; |
- } |
- if (x_record_range_[1]) { |
- XFree(x_record_range_[1]); |
- x_record_range_[1] = NULL; |
- } |
- if (x_record_context_) { |
- XRecordFreeContext(x_record_display_, x_record_context_); |
- x_record_context_ = 0; |
- } |
- if (x_record_display_) { |
- XCloseDisplay(x_record_display_); |
- x_record_display_ = NULL; |
- } |
- if (display_) { |
- XCloseDisplay(display_); |
- display_ = NULL; |
- } |
-} |
- |
-void LocalInputMonitorX11::Core::OnFileCanReadWithoutBlocking(int fd) { |
- DCHECK(input_task_runner_->BelongsToCurrentThread()); |
- |
- // Fetch pending events if any. |
- while (XPending(x_record_display_)) { |
- XEvent ev; |
- XNextEvent(x_record_display_, &ev); |
- } |
-} |
- |
-void LocalInputMonitorX11::Core::OnFileCanWriteWithoutBlocking(int fd) { |
- NOTREACHED(); |
-} |
- |
-void LocalInputMonitorX11::Core::ProcessXEvent(xEvent* event) { |
- DCHECK(input_task_runner_->BelongsToCurrentThread()); |
- |
- if (event->u.u.type == MotionNotify) { |
- webrtc::DesktopVector position(event->u.keyButtonPointer.rootX, |
- event->u.keyButtonPointer.rootY); |
- caller_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&ClientSessionControl::OnLocalMouseMoved, |
- client_session_control_, |
- position)); |
- } else { |
- int key_code = event->u.u.detail; |
- bool down = event->u.u.type == KeyPress; |
- KeySym key_sym = XkbKeycodeToKeysym(display_, key_code, 0, 0); |
- if (key_sym == XK_Control_L || key_sym == XK_Control_R) { |
- ctrl_pressed_ = down; |
- } else if (key_sym == XK_Alt_L || key_sym == XK_Alt_R) { |
- alt_pressed_ = down; |
- } else if (key_sym == XK_Escape && down && alt_pressed_ && ctrl_pressed_) { |
- caller_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&ClientSessionControl::DisconnectSession, |
- client_session_control_)); |
- } |
- } |
-} |
- |
-// static |
-void LocalInputMonitorX11::Core::ProcessReply(XPointer self, |
- XRecordInterceptData* data) { |
- if (data->category == XRecordFromServer) { |
- xEvent* event = reinterpret_cast<xEvent*>(data->data); |
- reinterpret_cast<Core*>(self)->ProcessXEvent(event); |
- } |
- XRecordFreeData(data); |
-} |
- |
-} // namespace |
- |
-scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create( |
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> input_task_runner, |
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
- base::WeakPtr<ClientSessionControl> client_session_control) { |
- return make_scoped_ptr(new LocalInputMonitorX11( |
- caller_task_runner, input_task_runner, client_session_control)); |
-} |
- |
-} // namespace remoting |