Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1082)

Unified Diff: media/base/user_input_monitor_linux.cc

Issue 23702008: Adds the UserInputMonitor implementation for Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/base/user_input_monitor_mac.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..3b80f4b869bd656ffe853c22a4c1f8890a4785e0 100644
--- a/media/base/user_input_monitor_linux.cc
+++ b/media/base/user_input_monitor_linux.cc
@@ -15,10 +15,13 @@
#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/observer_list_threadsafe.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 +35,32 @@
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:
- 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);
+ virtual ~UserInputMonitorLinuxCore();
- //
- // The following methods must be called on the IO thread.
- //
+ void AddMouseListener(UserInputMonitor::MouseEventListener* listener);
+ void RemoveMouseListener(UserInputMonitor::MouseEventListener* listener);
+ size_t GetKeyPressCount() const;
void StartMonitor(EventType type);
void StopMonitor(EventType type);
+ base::WeakPtr<UserInputMonitorLinuxCore> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
Wez 2013/09/11 08:03:42 You can avoid this ugly WeakPtr getter by keeping
jiayl 2013/09/11 16:57:10 To reiterate why PostTask to IO thread from UserIn
Wez 2013/09/13 10:01:27 You could add the listener from UserInputMonitor,
+ }
+
+ private:
+ void OnMouseListenerAdded();
+ void OnMouseListenerRemoved();
// base::MessagePumpLibevent::Watcher interface.
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
@@ -66,93 +69,94 @@ 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.
//
+ size_t mouse_listeners_count_;
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_;
+ base::WeakPtrFactory<UserInputMonitorLinuxCore> weak_factory_;
+
+ 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 void AddMouseListener(MouseEventListener* listener) OVERRIDE;
+ virtual void RemoveMouseListener(MouseEventListener* listener) OVERRIDE;
+ virtual size_t GetKeyPressCount() const OVERRIDE;
+
+ private:
+ // Private UserInputMonitor overrides.
+ virtual void StartKeyboardMonitoring() OVERRIDE;
+ virtual void StopKeyboardMonitoring() OVERRIDE;
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+ UserInputMonitorLinuxCore* core_;
DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinux);
};
-UserInputMonitorLinux::UserInputMonitorLinux(
+UserInputMonitorLinuxCore::UserInputMonitorLinuxCore(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: io_task_runner_(io_task_runner),
- display_(NULL),
+ mouse_listeners_(
+ new ObserverListThreadSafe<UserInputMonitor::MouseEventListener>()),
+ mouse_listeners_count_(0),
+ x_control_display_(NULL),
x_record_display_(NULL),
- x_record_context_(0) {
+ x_record_context_(0),
+ weak_factory_(this) {
x_record_range_[0] = NULL;
x_record_range_[1] = NULL;
}
-UserInputMonitorLinux::~UserInputMonitorLinux() {
- DCHECK(!display_);
+UserInputMonitorLinuxCore::~UserInputMonitorLinuxCore() {
+ DCHECK_EQ(0u, mouse_listeners_count_);
+ mouse_listeners_->AssertEmpty();
+ 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 {
- 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 UserInputMonitorLinuxCore::AddMouseListener(
+ UserInputMonitor::MouseEventListener* listener) {
+ mouse_listeners_->AddObserver(listener);
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinuxCore::OnMouseListenerAdded,
+ weak_factory_.GetWeakPtr()));
}
-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 UserInputMonitorLinuxCore::RemoveMouseListener(
+ UserInputMonitor::MouseEventListener* listener) {
+ mouse_listeners_->RemoveObserver(listener);
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinuxCore::OnMouseListenerRemoved,
+ weak_factory_.GetWeakPtr()));
}
-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);
+size_t UserInputMonitorLinuxCore::GetKeyPressCount() const {
+ return counter_.GetKeyPressCount();
}
-void UserInputMonitorLinux::StartMonitor(EventType type) {
+void UserInputMonitorLinuxCore::StartMonitor(EventType type) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (type == KEYBOARD_EVENT)
@@ -163,19 +167,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 +203,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 +227,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 +253,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 +266,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 +276,32 @@ 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::OnMouseListenerAdded() {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ mouse_listeners_count_++;
+ if (mouse_listeners_count_ == 1) {
+ StartMonitor(MOUSE_EVENT);
+ DVLOG(2) << "Started mouse monitoring.";
+ }
+}
+
+void UserInputMonitorLinuxCore::OnMouseListenerRemoved() {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+ mouse_listeners_count_--;
+ if (mouse_listeners_count_ == 0) {
+ StopMonitor(MOUSE_EVENT);
+ DVLOG(2) << "Stopped mouse monitoring.";
+ }
+}
+
+void UserInputMonitorLinuxCore::OnFileCanReadWithoutBlocking(int fd) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
XEvent event;
// Fetch pending events if any.
@@ -287,16 +310,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 +332,65 @@ 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)) {}
+
+UserInputMonitorLinux::~UserInputMonitorLinux() {
+ if (!io_task_runner_->DeleteSoon(FROM_HERE, core_))
+ delete core_;
+}
+
+void UserInputMonitorLinux::AddMouseListener(MouseEventListener* listener) {
+ core_->AddMouseListener(listener);
+}
+
+void UserInputMonitorLinux::RemoveMouseListener(MouseEventListener* listener) {
+ core_->RemoveMouseListener(listener);
+}
+
+size_t UserInputMonitorLinux::GetKeyPressCount() const {
+ return core_->GetKeyPressCount();
+}
+
+void UserInputMonitorLinux::StartKeyboardMonitoring() {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinuxCore::StartMonitor,
+ core_->GetWeakPtr(),
+ UserInputMonitorLinuxCore::KEYBOARD_EVENT));
+}
+
+void UserInputMonitorLinux::StopKeyboardMonitoring() {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserInputMonitorLinuxCore::StopMonitor,
+ core_->GetWeakPtr(),
+ UserInputMonitorLinuxCore::KEYBOARD_EVENT));
+}
+
} // namespace
scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
« no previous file with comments | « media/base/user_input_monitor.cc ('k') | media/base/user_input_monitor_mac.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698