| Index: media/base/user_input_monitor_linux.cc
|
| diff --git a/media/base/user_input_monitor_linux.cc b/media/base/user_input_monitor_linux.cc
|
| index 196b4e7407836319eb72af8b5298d0aebf84bc8e..138de0afe332d5031a95c467196fb8e7090d005e 100644
|
| --- a/media/base/user_input_monitor_linux.cc
|
| +++ b/media/base/user_input_monitor_linux.cc
|
| @@ -15,10 +15,12 @@
|
| #include "base/compiler_specific.h"
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| +#include "base/memory/weak_ptr.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/message_loop/message_pump_libevent.h"
|
| #include "base/posix/eintr_wrapper.h"
|
| #include "base/single_thread_task_runner.h"
|
| +#include "base/synchronization/lock.h"
|
| #include "media/base/keyboard_event_counter.h"
|
| #include "third_party/skia/include/core/SkPoint.h"
|
| #include "ui/base/keycodes/keyboard_code_conversion_x.h"
|
| @@ -32,32 +34,28 @@
|
| namespace media {
|
| namespace {
|
|
|
| -class UserInputMonitorLinux : public UserInputMonitor ,
|
| - public base::MessagePumpLibevent::Watcher {
|
| +// This is the actual implementation of event monitoring. It's separated from
|
| +// UserInputMonitorLinux since it needs to be deleted on the IO thread.
|
| +class UserInputMonitorLinuxCore
|
| + : public base::MessagePumpLibevent::Watcher,
|
| + public base::SupportsWeakPtr<UserInputMonitorLinuxCore> {
|
| public:
|
| - explicit UserInputMonitorLinux(
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
|
| - virtual ~UserInputMonitorLinux();
|
| -
|
| - virtual size_t GetKeyPressCount() const OVERRIDE;
|
| -
|
| - private:
|
| enum EventType {
|
| MOUSE_EVENT,
|
| KEYBOARD_EVENT
|
| };
|
|
|
| - virtual void StartMouseMonitoring() OVERRIDE;
|
| - virtual void StopMouseMonitoring() OVERRIDE;
|
| - virtual void StartKeyboardMonitoring() OVERRIDE;
|
| - virtual void StopKeyboardMonitoring() OVERRIDE;
|
| + explicit UserInputMonitorLinuxCore(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
|
| + const scoped_refptr<UserInputMonitor::MouseListenerList>&
|
| + mouse_listeners);
|
| + virtual ~UserInputMonitorLinuxCore();
|
|
|
| - //
|
| - // The following methods must be called on the IO thread.
|
| - //
|
| + size_t GetKeyPressCount() const;
|
| void StartMonitor(EventType type);
|
| void StopMonitor(EventType type);
|
|
|
| + private:
|
| // base::MessagePumpLibevent::Watcher interface.
|
| virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
|
| virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
|
| @@ -66,93 +64,70 @@ class UserInputMonitorLinux : public UserInputMonitor ,
|
| void ProcessXEvent(xEvent* event);
|
| static void ProcessReply(XPointer self, XRecordInterceptData* data);
|
|
|
| - // Task runner on which X Window events are received.
|
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
|
| + scoped_refptr<ObserverListThreadSafe<UserInputMonitor::MouseEventListener> >
|
| + mouse_listeners_;
|
|
|
| //
|
| // The following members should only be accessed on the IO thread.
|
| //
|
| base::MessagePumpLibevent::FileDescriptorWatcher controller_;
|
| - Display* display_;
|
| + Display* x_control_display_;
|
| Display* x_record_display_;
|
| XRecordRange* x_record_range_[2];
|
| XRecordContext x_record_context_;
|
| KeyboardEventCounter counter_;
|
|
|
| + DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinuxCore);
|
| +};
|
| +
|
| +class UserInputMonitorLinux : public UserInputMonitor {
|
| + public:
|
| + explicit UserInputMonitorLinux(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
|
| + virtual ~UserInputMonitorLinux();
|
| +
|
| + // Public UserInputMonitor overrides.
|
| + virtual size_t GetKeyPressCount() const OVERRIDE;
|
| +
|
| + private:
|
| + // Private UserInputMonitor overrides.
|
| + virtual void StartKeyboardMonitoring() OVERRIDE;
|
| + virtual void StopKeyboardMonitoring() OVERRIDE;
|
| + virtual void StartMouseMonitoring() OVERRIDE;
|
| + virtual void StopMouseMonitoring() OVERRIDE;
|
| +
|
| + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
|
| + UserInputMonitorLinuxCore* core_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinux);
|
| };
|
|
|
| -UserInputMonitorLinux::UserInputMonitorLinux(
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
|
| +UserInputMonitorLinuxCore::UserInputMonitorLinuxCore(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
|
| + const scoped_refptr<UserInputMonitor::MouseListenerList>& mouse_listeners)
|
| : io_task_runner_(io_task_runner),
|
| - display_(NULL),
|
| + mouse_listeners_(mouse_listeners),
|
| + x_control_display_(NULL),
|
| x_record_display_(NULL),
|
| x_record_context_(0) {
|
| x_record_range_[0] = NULL;
|
| x_record_range_[1] = NULL;
|
| }
|
|
|
| -UserInputMonitorLinux::~UserInputMonitorLinux() {
|
| - DCHECK(!display_);
|
| +UserInputMonitorLinuxCore::~UserInputMonitorLinuxCore() {
|
| + DCHECK(!x_control_display_);
|
| DCHECK(!x_record_display_);
|
| DCHECK(!x_record_range_[0]);
|
| DCHECK(!x_record_range_[1]);
|
| DCHECK(!x_record_context_);
|
| }
|
|
|
| -size_t UserInputMonitorLinux::GetKeyPressCount() const {
|
| +size_t UserInputMonitorLinuxCore::GetKeyPressCount() const {
|
| return counter_.GetKeyPressCount();
|
| }
|
|
|
| -void UserInputMonitorLinux::StartMouseMonitoring() {
|
| - if (!io_task_runner_->BelongsToCurrentThread()) {
|
| - io_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&UserInputMonitorLinux::StartMonitor,
|
| - base::Unretained(this),
|
| - MOUSE_EVENT));
|
| - return;
|
| - }
|
| - StartMonitor(MOUSE_EVENT);
|
| -}
|
| -
|
| -void UserInputMonitorLinux::StopMouseMonitoring() {
|
| - if (!io_task_runner_->BelongsToCurrentThread()) {
|
| - io_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&UserInputMonitorLinux::StopMonitor,
|
| - base::Unretained(this),
|
| - MOUSE_EVENT));
|
| - return;
|
| - }
|
| - StopMonitor(MOUSE_EVENT);
|
| -}
|
| -
|
| -void UserInputMonitorLinux::StartKeyboardMonitoring() {
|
| - if (!io_task_runner_->BelongsToCurrentThread()) {
|
| - io_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&UserInputMonitorLinux::StartMonitor,
|
| - base::Unretained(this),
|
| - KEYBOARD_EVENT));
|
| - return;
|
| - }
|
| - StartMonitor(KEYBOARD_EVENT);
|
| -}
|
| -
|
| -void UserInputMonitorLinux::StopKeyboardMonitoring() {
|
| - if (!io_task_runner_->BelongsToCurrentThread()) {
|
| - io_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&UserInputMonitorLinux::StopMonitor,
|
| - base::Unretained(this),
|
| - KEYBOARD_EVENT));
|
| - return;
|
| - }
|
| - StopMonitor(KEYBOARD_EVENT);
|
| -}
|
| -
|
| -void UserInputMonitorLinux::StartMonitor(EventType type) {
|
| +void UserInputMonitorLinuxCore::StartMonitor(EventType type) {
|
| DCHECK(io_task_runner_->BelongsToCurrentThread());
|
|
|
| if (type == KEYBOARD_EVENT)
|
| @@ -163,19 +138,20 @@ void UserInputMonitorLinux::StartMonitor(EventType type) {
|
| // and both channels are used from a separate thread, we'll need to duplicate
|
| // them with something like the following:
|
| // XOpenDisplay(DisplayString(display));
|
| - if (!display_)
|
| - display_ = XOpenDisplay(NULL);
|
| + if (!x_control_display_)
|
| + x_control_display_ = XOpenDisplay(NULL);
|
|
|
| if (!x_record_display_)
|
| x_record_display_ = XOpenDisplay(NULL);
|
|
|
| - if (!display_ || !x_record_display_) {
|
| + if (!x_control_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)) {
|
| + if (!XQueryExtension(
|
| + x_control_display_, "RECORD", &xr_opcode, &xr_event, &xr_error)) {
|
| LOG(ERROR) << "X Record extension not available.";
|
| return;
|
| }
|
| @@ -198,8 +174,8 @@ void UserInputMonitorLinux::StartMonitor(EventType type) {
|
| }
|
|
|
| if (x_record_context_) {
|
| - XRecordDisableContext(display_, x_record_context_);
|
| - XFlush(display_);
|
| + XRecordDisableContext(x_control_display_, x_record_context_);
|
| + XFlush(x_control_display_);
|
| XRecordFreeContext(x_record_display_, x_record_context_);
|
| x_record_context_ = 0;
|
| }
|
| @@ -222,7 +198,7 @@ void UserInputMonitorLinux::StartMonitor(EventType type) {
|
|
|
| if (!XRecordEnableContextAsync(x_record_display_,
|
| x_record_context_,
|
| - &UserInputMonitorLinux::ProcessReply,
|
| + &UserInputMonitorLinuxCore::ProcessReply,
|
| reinterpret_cast<XPointer>(this))) {
|
| LOG(ERROR) << "XRecordEnableContextAsync failed.";
|
| return;
|
| @@ -248,7 +224,7 @@ void UserInputMonitorLinux::StartMonitor(EventType type) {
|
| OnFileCanReadWithoutBlocking(ConnectionNumber(x_record_display_));
|
| }
|
|
|
| -void UserInputMonitorLinux::StopMonitor(EventType type) {
|
| +void UserInputMonitorLinuxCore::StopMonitor(EventType type) {
|
| DCHECK(io_task_runner_->BelongsToCurrentThread());
|
|
|
| if (x_record_range_[type]) {
|
| @@ -261,8 +237,8 @@ void UserInputMonitorLinux::StopMonitor(EventType type) {
|
| // 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_);
|
| + XRecordDisableContext(x_control_display_, x_record_context_);
|
| + XFlush(x_control_display_);
|
| XRecordFreeContext(x_record_display_, x_record_context_);
|
| x_record_context_ = 0;
|
|
|
| @@ -271,14 +247,14 @@ void UserInputMonitorLinux::StopMonitor(EventType type) {
|
| XCloseDisplay(x_record_display_);
|
| x_record_display_ = NULL;
|
| }
|
| - if (display_) {
|
| - XCloseDisplay(display_);
|
| - display_ = NULL;
|
| + if (x_control_display_) {
|
| + XCloseDisplay(x_control_display_);
|
| + x_control_display_ = NULL;
|
| }
|
| }
|
| }
|
|
|
| -void UserInputMonitorLinux::OnFileCanReadWithoutBlocking(int fd) {
|
| +void UserInputMonitorLinuxCore::OnFileCanReadWithoutBlocking(int fd) {
|
| DCHECK(io_task_runner_->BelongsToCurrentThread());
|
| XEvent event;
|
| // Fetch pending events if any.
|
| @@ -287,16 +263,17 @@ void UserInputMonitorLinux::OnFileCanReadWithoutBlocking(int fd) {
|
| }
|
| }
|
|
|
| -void UserInputMonitorLinux::OnFileCanWriteWithoutBlocking(int fd) {
|
| +void UserInputMonitorLinuxCore::OnFileCanWriteWithoutBlocking(int fd) {
|
| NOTREACHED();
|
| }
|
|
|
| -void UserInputMonitorLinux::ProcessXEvent(xEvent* event) {
|
| +void UserInputMonitorLinuxCore::ProcessXEvent(xEvent* event) {
|
| DCHECK(io_task_runner_->BelongsToCurrentThread());
|
| if (event->u.u.type == MotionNotify) {
|
| SkIPoint position(SkIPoint::Make(event->u.keyButtonPointer.rootX,
|
| event->u.keyButtonPointer.rootY));
|
| - OnMouseEvent(position);
|
| + mouse_listeners_->Notify(
|
| + &UserInputMonitor::MouseEventListener::OnMouseMoved, position);
|
| } else {
|
| ui::EventType type;
|
| if (event->u.u.type == KeyPress) {
|
| @@ -308,22 +285,71 @@ void UserInputMonitorLinux::ProcessXEvent(xEvent* event) {
|
| return;
|
| }
|
|
|
| - KeySym key_sym = XkbKeycodeToKeysym(display_, event->u.u.detail, 0, 0);
|
| + KeySym key_sym =
|
| + XkbKeycodeToKeysym(x_control_display_, event->u.u.detail, 0, 0);
|
| ui::KeyboardCode key_code = ui::KeyboardCodeFromXKeysym(key_sym);
|
| counter_.OnKeyboardEvent(type, key_code);
|
| }
|
| }
|
|
|
| // static
|
| -void UserInputMonitorLinux::ProcessReply(XPointer self,
|
| - XRecordInterceptData* data) {
|
| +void UserInputMonitorLinuxCore::ProcessReply(XPointer self,
|
| + XRecordInterceptData* data) {
|
| if (data->category == XRecordFromServer) {
|
| xEvent* event = reinterpret_cast<xEvent*>(data->data);
|
| - reinterpret_cast<UserInputMonitorLinux*>(self)->ProcessXEvent(event);
|
| + reinterpret_cast<UserInputMonitorLinuxCore*>(self)->ProcessXEvent(event);
|
| }
|
| XRecordFreeData(data);
|
| }
|
|
|
| +//
|
| +// Implementation of UserInputMonitorLinux.
|
| +//
|
| +
|
| +UserInputMonitorLinux::UserInputMonitorLinux(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
|
| + : io_task_runner_(io_task_runner),
|
| + core_(new UserInputMonitorLinuxCore(io_task_runner, mouse_listeners())) {}
|
| +
|
| +UserInputMonitorLinux::~UserInputMonitorLinux() {
|
| + if (!io_task_runner_->DeleteSoon(FROM_HERE, core_))
|
| + delete core_;
|
| +}
|
| +
|
| +size_t UserInputMonitorLinux::GetKeyPressCount() const {
|
| + return core_->GetKeyPressCount();
|
| +}
|
| +
|
| +void UserInputMonitorLinux::StartKeyboardMonitoring() {
|
| + io_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&UserInputMonitorLinuxCore::StartMonitor,
|
| + core_->AsWeakPtr(),
|
| + UserInputMonitorLinuxCore::KEYBOARD_EVENT));
|
| +}
|
| +
|
| +void UserInputMonitorLinux::StopKeyboardMonitoring() {
|
| + io_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&UserInputMonitorLinuxCore::StopMonitor,
|
| + core_->AsWeakPtr(),
|
| + UserInputMonitorLinuxCore::KEYBOARD_EVENT));
|
| +}
|
| +
|
| +void UserInputMonitorLinux::StartMouseMonitoring() {
|
| + io_task_runner_->PostTask(FROM_HERE,
|
| + base::Bind(&UserInputMonitorLinuxCore::StartMonitor,
|
| + core_->AsWeakPtr(),
|
| + UserInputMonitorLinuxCore::MOUSE_EVENT));
|
| +}
|
| +
|
| +void UserInputMonitorLinux::StopMouseMonitoring() {
|
| + io_task_runner_->PostTask(FROM_HERE,
|
| + base::Bind(&UserInputMonitorLinuxCore::StopMonitor,
|
| + core_->AsWeakPtr(),
|
| + UserInputMonitorLinuxCore::MOUSE_EVENT));
|
| +}
|
| +
|
| } // namespace
|
|
|
| scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
|
|
|