diff options
author | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-15 17:52:02 +0000 |
---|---|---|
committer | davemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-15 17:52:02 +0000 |
commit | aca200e532f35181e8ae0d66e7f27ca7c6966bd1 (patch) | |
tree | 299d4785d08390f53efb91ac31c1c6d80d6dc130 /ui | |
parent | 112f03ff93d980249601674796f12f5bab4ee839 (diff) | |
download | chromium_src-aca200e532f35181e8ae0d66e7f27ca7c6966bd1.zip chromium_src-aca200e532f35181e8ae0d66e7f27ca7c6966bd1.tar.gz chromium_src-aca200e532f35181e8ae0d66e7f27ca7c6966bd1.tar.bz2 |
CMT can now generate motion events w/ valuators instead of a sequence of button events. This supports them
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/8907005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114660 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura/event.cc | 5 | ||||
-rw-r--r-- | ui/aura/event.h | 23 | ||||
-rw-r--r-- | ui/aura/root_window.cc | 22 | ||||
-rw-r--r-- | ui/aura/root_window.h | 5 | ||||
-rw-r--r-- | ui/aura/root_window_host_linux.cc | 28 | ||||
-rw-r--r-- | ui/base/events.h | 10 | ||||
-rw-r--r-- | ui/base/win/events_win.cc | 11 | ||||
-rw-r--r-- | ui/base/x/events_x.cc | 160 | ||||
-rw-r--r-- | ui/views/events/event.h | 13 | ||||
-rw-r--r-- | ui/views/events/event_aura.cc | 6 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.cc | 4 |
11 files changed, 265 insertions, 22 deletions
diff --git a/ui/aura/event.cc b/ui/aura/event.cc index 5cb2fd8..980b129 100644 --- a/ui/aura/event.cc +++ b/ui/aura/event.cc @@ -251,4 +251,9 @@ uint16 KeyEvent::GetUnmodifiedCharacter() const { #endif } +ScrollEvent::ScrollEvent(const base::NativeEvent& native_event) + : MouseEvent(native_event) { + ui::GetScrollOffsets(native_event, &x_offset_, &y_offset_); +} + } // namespace aura diff --git a/ui/aura/event.h b/ui/aura/event.h index 5dcb726..f4478f8 100644 --- a/ui/aura/event.h +++ b/ui/aura/event.h @@ -204,6 +204,29 @@ class AURA_EXPORT DropTargetEvent : public LocatedEvent { DISALLOW_COPY_AND_ASSIGN(DropTargetEvent); }; +class AURA_EXPORT ScrollEvent : public MouseEvent { + public: + ScrollEvent(const base::NativeEvent& native_event); + ScrollEvent(const ScrollEvent& model, + Window* source, + Window* target, + ui::EventType type, + int flags) + : MouseEvent(model, source, target, type, flags), + x_offset_(model.x_offset_), + y_offset_(model.y_offset_) { + } + + float x_offset() const { return x_offset_; } + float y_offset() const { return y_offset_; } + + private: + float x_offset_; + float y_offset_; + + DISALLOW_COPY_AND_ASSIGN(ScrollEvent); +}; + } // namespace aura #endif // UI_AURA_EVENT_H_ diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index 10535a7..ed230a5 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -170,6 +170,28 @@ bool RootWindow::DispatchKeyEvent(KeyEvent* event) { return false; } +bool RootWindow::DispatchScrollEvent(ScrollEvent* event) { + event->UpdateForTransform(layer()->transform()); + + last_mouse_location_ = event->location(); + + Window* target = + mouse_pressed_handler_ ? mouse_pressed_handler_ : capture_window_; + if (!target) + target = GetEventHandlerForPoint(event->location()); + + if (target && target->delegate()) { + int flags = event->flags(); + gfx::Point location_in_window = event->location(); + Window::ConvertPointToWindow(this, target, &location_in_window); + if (IsNonClientLocation(target, location_in_window)) + flags |= ui::EF_IS_NON_CLIENT; + ScrollEvent translated_event(*event, this, target, event->type(), flags); + return ProcessMouseEvent(target, &translated_event); + } + return false; +} + bool RootWindow::DispatchTouchEvent(TouchEvent* event) { event->UpdateForTransform(layer()->transform()); bool handled = false; diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h index 76f70b5..f7b0862 100644 --- a/ui/aura/root_window.h +++ b/ui/aura/root_window.h @@ -37,6 +37,8 @@ class RootWindowObserver; class KeyEvent; class MouseEvent; class ScreenAura; +class StackingClient; +class ScrollEvent; class TouchEvent; // RootWindow is responsible for hosting a set of windows. @@ -81,6 +83,9 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, // Handles a key event. Returns true if handled. bool DispatchKeyEvent(KeyEvent* event); + // Handles a scroll event. Returns true if handled. + bool DispatchScrollEvent(ScrollEvent* event); + // Handles a touch event. Returns true if handled. bool DispatchTouchEvent(TouchEvent* event); diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc index d577acd..6ed655b 100644 --- a/ui/aura/root_window_host_linux.cc +++ b/ui/aura/root_window_host_linux.cc @@ -197,7 +197,8 @@ int CoalescePendingXIMotionEvents(const XEvent* xev, XEvent* last_event) { } if (next_event.type == GenericEvent && - next_event.xgeneric.evtype == XI_Motion) { + next_event.xgeneric.evtype == XI_Motion && + !ui::GetScrollOffsets(&next_event, NULL, NULL)) { XIDeviceEvent* next_xievent = static_cast<XIDeviceEvent*>(next_event.xcookie.data); // Confirm that the motion event is targeted at the same window @@ -343,7 +344,6 @@ RootWindowHostLinux::RootWindowHostLinux(const gfx::Rect& bounds) XSelectInput(xdisplay_, x_root_window_, StructureNotifyMask); XFlush(xdisplay_); - // TODO(sad): Re-enable once crbug.com/106516 is fixed. if (base::MessagePumpForUI::HasXInput2()) ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_); @@ -422,22 +422,17 @@ base::MessagePumpDispatcher::DispatchStatus RootWindowHostLinux::Dispatch( // Update the device list if necessary. if (xev->xgeneric.evtype == XI_HierarchyChanged) { - factory->UpdateDeviceList(xdisplay_); + ui::UpdateDeviceList(); handled = true; break; } + ui::EventType type = ui::EventTypeFromNative(xev); // If this is a motion event we want to coalesce all pending motion // events that are at the top of the queue. XEvent last_event; int num_coalesced = 0; - if (xev->xgeneric.evtype == XI_Motion) { - num_coalesced = CoalescePendingXIMotionEvents(xev, &last_event); - if (num_coalesced > 0) - xev = &last_event; - } - ui::EventType type = ui::EventTypeFromNative(xev); switch (type) { case ui::ET_TOUCH_PRESSED: case ui::ET_TOUCH_RELEASED: @@ -446,10 +441,16 @@ base::MessagePumpDispatcher::DispatchStatus RootWindowHostLinux::Dispatch( handled = root_window_->DispatchTouchEvent(&touchev); break; } + case ui::ET_MOUSE_MOVED: + case ui::ET_MOUSE_DRAGGED: { + // If this is a motion event we want to coalesce all pending motion + // events that are at the top of the queue. + num_coalesced = CoalescePendingXIMotionEvents(xev, &last_event); + if (num_coalesced > 0) + xev = &last_event; + } case ui::ET_MOUSE_PRESSED: case ui::ET_MOUSE_RELEASED: - case ui::ET_MOUSE_MOVED: - case ui::ET_MOUSE_DRAGGED: case ui::ET_MOUSEWHEEL: case ui::ET_MOUSE_ENTERED: case ui::ET_MOUSE_EXITED: { @@ -457,6 +458,11 @@ base::MessagePumpDispatcher::DispatchStatus RootWindowHostLinux::Dispatch( handled = root_window_->DispatchMouseEvent(&mouseev); break; } + case ui::ET_SCROLL: { + ScrollEvent scrollev(xev); + handled = root_window_->DispatchScrollEvent(&scrollev); + break; + } case ui::ET_UNKNOWN: handled = false; break; diff --git a/ui/base/events.h b/ui/base/events.h index 69f83084..aab9366 100644 --- a/ui/base/events.h +++ b/ui/base/events.h @@ -35,6 +35,7 @@ enum EventType { ET_TOUCH_CANCELLED, ET_DROP_TARGET_EVENT, ET_FOCUS_CHANGE, + ET_SCROLL, }; // Event flags currently supported @@ -70,6 +71,9 @@ enum TouchStatus { // unused touch event was handled. }; +// Updates the list of devices for cached properties. +UI_EXPORT void UpdateDeviceList(); + // Get the EventType from a native event. UI_EXPORT EventType EventTypeFromNative(const base::NativeEvent& native_event); @@ -111,6 +115,12 @@ UI_EXPORT float GetTouchAngle(const base::NativeEvent& native_event); // Gets the force from a native_event. Normalized to be [0, 1]. Default is 0.0. UI_EXPORT float GetTouchForce(const base::NativeEvent& native_event); +// Returns whether this is a scroll event and optionally gets the amount to be +// scrolled. |x_offset| and |y_offset| can be NULL. +UI_EXPORT bool GetScrollOffsets(const base::NativeEvent& native_event, + float* x_offset, + float* y_offset); + // Creates and returns no-op event. UI_EXPORT base::NativeEvent CreateNoopEvent(); diff --git a/ui/base/win/events_win.cc b/ui/base/win/events_win.cc index 418d6d0..c745526 100644 --- a/ui/base/win/events_win.cc +++ b/ui/base/win/events_win.cc @@ -253,6 +253,17 @@ float GetTouchForce(const base::NativeEvent& native_event) { return 0.0; } +bool GetScrollOffsets(const base::NativeEvent& native_event, + float* x_offset, + float* y_offset) { + NOTIMPLEMENTED(); + return false; +} + +void UpdateDeviceList() { + NOTIMPLEMENTED(); +} + base::NativeEvent CreateNoopEvent() { MSG event; event.message = WM_USER; diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc index 4f2db85..b5c8bed 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" +#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,125 @@ 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) { + scroll_devices_.reset(); + device_to_valuators_.clear(); + + int count = 0; + 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 + // NULL. + bool GetScrollOffsets(const XEvent& xev, float* x_offset, float* y_offset) { + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); + + if (x_offset) + *x_offset = 0; + if (y_offset) + *y_offset = 0; + + 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 +316,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 +530,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) { diff --git a/ui/views/events/event.h b/ui/views/events/event.h index c0cf2e0..4d0d2f1 100644 --- a/ui/views/events/event.h +++ b/ui/views/events/event.h @@ -410,6 +410,19 @@ class VIEWS_EXPORT DropTargetEvent : public LocatedEvent { DISALLOW_COPY_AND_ASSIGN(DropTargetEvent); }; +class VIEWS_EXPORT ScrollEvent : public MouseEvent { + public: + explicit ScrollEvent(const NativeEvent& native_event); + float x_offset() const { return x_offset_; } + float y_offset() const { return y_offset_; } + + private: + float x_offset_; + float y_offset_; + + DISALLOW_COPY_AND_ASSIGN(ScrollEvent); +}; + } // namespace views #endif // UI_VIEWS_EVENTS_EVENT_H_ diff --git a/ui/views/events/event_aura.cc b/ui/views/events/event_aura.cc index 39ae3f7..9b3af83 100644 --- a/ui/views/events/event_aura.cc +++ b/ui/views/events/event_aura.cc @@ -59,4 +59,10 @@ MouseWheelEvent::MouseWheelEvent(const NativeEvent& native_event) offset_(ui::GetMouseWheelOffset(native_event->native_event())) { } +ScrollEvent::ScrollEvent(const NativeEvent& native_event) + : MouseEvent(native_event) { + CHECK(ui::GetScrollOffsets( + native_event->native_event(), &x_offset_, &y_offset_)); +} + } // namespace views diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 619018b..882a52e 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -651,6 +651,10 @@ bool NativeWidgetAura::OnMouseEvent(aura::MouseEvent* event) { MouseWheelEvent wheel_event(event); return delegate_->OnMouseEvent(wheel_event); } + if (event->type() == ui::ET_SCROLL) { + ScrollEvent scroll_event(static_cast<aura::ScrollEvent*>(event)); + return delegate_->OnMouseEvent(scroll_event); + } MouseEvent mouse_event(event); if (tooltip_manager_.get()) tooltip_manager_->UpdateTooltip(); |