Index: ui/base/x/events_x.cc |
diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc |
index 4f2db853d7cb08892f4f8cb9a49e6dc114fc288a..5e4f9bd4e9d13fe99e28ffaf54b7c7bdce89bdaf 100644 |
--- a/ui/base/x/events_x.cc |
+++ b/ui/base/x/events_x.cc |
@@ -5,6 +5,7 @@ |
#include "ui/base/events.h" |
#include <X11/Xlib.h> |
+#include <X11/extensions/XInput.h> |
#include <X11/extensions/XInput2.h> |
#include <string.h> |
@@ -18,6 +19,10 @@ |
#include "base/message_pump_x.h" |
#endif |
+// Copied from xserver-properties.h |
+#define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel" |
Daniel Erat
2011/12/14 21:49:07
nit: just one space between symbol name and string
DaveMoore
2011/12/15 17:07:21
Done.
|
+#define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel" |
+ |
namespace { |
// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. |
@@ -35,6 +40,118 @@ static const int kMaxWheelButton = 9; |
static const int kMaxWheelButton = 7; |
#endif |
+// A class to support the detection of scroll events, using X11 valuators. |
+class UI_EXPORT ScrollEventData { |
+ public: |
+ // Returns the ScrollEventData singleton. |
+ static ScrollEventData* GetInstance() { |
+ return Singleton<ScrollEventData>::get(); |
+ } |
+ |
+ // Updates the list of devices. |
+ void UpdateDeviceList(Display* display) { |
+ int count; |
Daniel Erat
2011/12/14 21:49:07
nit: initialize to 0
DaveMoore
2011/12/15 17:07:21
Done.
|
+ scroll_devices_.reset(); |
+ device_to_valuators_.clear(); |
+ XDeviceInfo* dev_list = XListInputDevices(display, &count); |
+ Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false); |
+ for (int i = 0; i < count; ++i) { |
+ XDeviceInfo* dev = dev_list + i; |
+ if (dev->type == xi_touchpad) |
+ scroll_devices_[dev_list[i].id] = true; |
+ } |
+ if (dev_list) |
+ XFreeDeviceList(dev_list); |
+ |
+ XIDeviceInfo* info_list = XIQueryDevice(display, XIAllDevices, &count); |
+ Atom x_axis = XInternAtom(display, AXIS_LABEL_PROP_REL_HWHEEL, false); |
+ Atom y_axis = XInternAtom(display, AXIS_LABEL_PROP_REL_WHEEL, false); |
+ for (int i = 0; i < count; ++i) { |
+ XIDeviceInfo* info = info_list + i; |
+ |
+ if (!scroll_devices_[info->deviceid]) |
+ continue; |
+ |
+ if (info->use != XISlavePointer && info->use != XIFloatingSlave) { |
+ scroll_devices_[info->deviceid] = false; |
+ continue; |
+ } |
+ |
+ Valuators valuators = {-1, -1}; |
+ for (int j = 0; j < info->num_classes; ++j) { |
+ if (info->classes[j]->type != XIValuatorClass) |
+ continue; |
+ |
+ XIValuatorClassInfo* v = |
+ reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]); |
+ if (v->label == x_axis) |
+ valuators.x_scroll = v->number; |
+ else if (v->label == y_axis) |
+ valuators.y_scroll = v->number; |
+ } |
+ if (valuators.x_scroll >= 0 && valuators.y_scroll >= 0) |
+ device_to_valuators_[info->deviceid] = valuators; |
+ else |
+ scroll_devices_[info->deviceid] = false; |
+ } |
+ } |
+ |
+ // Returns true if this is a scroll event (a motion event with the necessary |
+ // valuators. Also returns the offsets. |x_offset| and |y_offset| can be |
Daniel Erat
2011/12/14 21:49:07
nit: add ')' after 'valuators'
either initialize
DaveMoore
2011/12/15 17:07:21
Done.
|
+ // NULL. |
+ bool GetScrollOffsets(const XEvent& xev, float* x_offset, float* y_offset) { |
+ XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); |
+ if (!scroll_devices_[xiev->deviceid]) |
+ return false; |
+ |
+ int x_scroll = device_to_valuators_[xiev->deviceid].x_scroll; |
+ int y_scroll = device_to_valuators_[xiev->deviceid].y_scroll; |
+ |
+ bool has_x_offset = XIMaskIsSet(xiev->valuators.mask, x_scroll); |
+ bool has_y_offset = XIMaskIsSet(xiev->valuators.mask, y_scroll); |
+ bool is_scroll = has_x_offset || has_y_offset; |
+ |
+ if (!x_offset && !y_offset) |
+ return is_scroll; |
+ |
+ double* valuators = xiev->valuators.values; |
+ for (int i = 0; i < xiev->valuators.mask_len * 8; ++i) { |
+ if (XIMaskIsSet(xiev->valuators.mask, i)) { |
+ if (x_offset && x_scroll == i) |
+ *x_offset = -(*valuators); |
+ else if (y_offset && y_scroll == i) |
+ *y_offset = -(*valuators); |
+ valuators++; |
+ } |
+ } |
+ |
+ return is_scroll; |
+ } |
+ |
+ private: |
+ // Requirement for Singleton |
+ friend struct DefaultSingletonTraits<ScrollEventData>; |
+ |
+ struct Valuators { |
+ int x_scroll; |
+ int y_scroll; |
+ }; |
+ |
+ ScrollEventData() { |
+ UpdateDeviceList(ui::GetXDisplay()); |
+ } |
+ |
+ ~ScrollEventData() {} |
+ |
+ // A quick lookup table for determining if events from the pointer device |
+ // should be processed. |
+ static const int kMaxDeviceNum = 128; |
+ std::bitset<kMaxDeviceNum> scroll_devices_; |
+ std::map<int, Valuators> device_to_valuators_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ScrollEventData); |
+}; |
+ |
int GetEventFlagsFromXState(unsigned int state) { |
int flags = 0; |
if (state & ControlMask) |
@@ -192,21 +309,22 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) { |
static_cast<XIDeviceEvent*>(native_event->xcookie.data); |
if (TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid)) |
return GetTouchEventType(native_event); |
- int button = EventButtonFromNative(native_event); |
switch (xievent->evtype) { |
case XI_ButtonPress: |
- if (button >= kMinWheelButton && |
- button <= kMaxWheelButton) |
- return ET_MOUSEWHEEL; |
- return ET_MOUSE_PRESSED; |
- case XI_ButtonRelease: |
- if (button >= kMinWheelButton && |
- button <= kMaxWheelButton) |
+ case XI_ButtonRelease: { |
+ int button = EventButtonFromNative(native_event); |
+ if (button >= kMinWheelButton && button <= kMaxWheelButton) |
return ET_MOUSEWHEEL; |
- return ET_MOUSE_RELEASED; |
+ return xievent->evtype == XI_ButtonPress ? |
+ ET_MOUSE_PRESSED : ET_MOUSE_RELEASED; |
+ } |
case XI_Motion: |
- return GetButtonMaskForX2Event(xievent) ? |
- ET_MOUSE_DRAGGED : ET_MOUSE_MOVED; |
+ if (GetScrollOffsets(native_event, NULL, NULL)) |
+ return ET_SCROLL; |
+ else if (GetButtonMaskForX2Event(xievent)) |
+ return ET_MOUSE_DRAGGED; |
+ else |
+ return ET_MOUSE_MOVED; |
} |
} |
default: |
@@ -405,6 +523,19 @@ float GetTouchForce(const base::NativeEvent& native_event) { |
return force; |
} |
+bool GetScrollOffsets(const base::NativeEvent& native_event, |
+ float* x_offset, |
+ float* y_offset) { |
+ return ScrollEventData::GetInstance()->GetScrollOffsets( |
+ *native_event, x_offset, y_offset); |
+} |
+ |
+void UpdateDeviceList() { |
+ Display* display = GetXDisplay(); |
+ ScrollEventData::GetInstance()->UpdateDeviceList(display); |
+ TouchFactory::GetInstance()->UpdateDeviceList(display); |
+} |
+ |
base::NativeEvent CreateNoopEvent() { |
static XEvent* noop = NULL; |
if (!noop) { |