summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-07 22:06:34 +0000
committerderat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-07 22:06:34 +0000
commit562b8d289eb1db9b1253691c83b7c5fcc7138602 (patch)
tree164e60c061d4baa7f60fc808f85fb3d259dda864 /ui
parenteea61f21716ce9dca63a4a8693514e07f8bbf230 (diff)
downloadchromium_src-562b8d289eb1db9b1253691c83b7c5fcc7138602.zip
chromium_src-562b8d289eb1db9b1253691c83b7c5fcc7138602.tar.gz
chromium_src-562b8d289eb1db9b1253691c83b7c5fcc7138602.tar.bz2
X11: Avoid treating scrollwheel events as button presses.
This fixes a few scrollwheel-related problems in events_x.c: - GetEventFlagsForButton() was getting called for scrollwheel events and DLOG-ing a warning. This change makes us avoid calling it for core scrollwheel events and removes the warning (since it can still get called for buttons other 1-3 when inspecting the button mask for XInput events). - EventTypeFromNative() was classifying button 6 and 7 (left and right scrollwheel) events as button presses and releases instead of as scrolls. As a result, doing a two-finger left or right scroll on a Chrome OS device would trigger a failed assertion in WebKit. I'm also adding some basic unit tests. BUG=102675 TEST=added, also manually checked that the warning and crash are gone Review URL: http://codereview.chromium.org/8423065 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108920 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/base/x/events_x.cc92
-rw-r--r--ui/base/x/events_x_unittest.cc118
-rw-r--r--ui/ui_unittests.gypi5
3 files changed, 175 insertions, 40 deletions
diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc
index 39404a5..329acbe 100644
--- a/ui/base/x/events_x.cc
+++ b/ui/base/x/events_x.cc
@@ -14,7 +14,15 @@
namespace {
// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
-static int kWheelScrollAmount = 53;
+static const int kWheelScrollAmount = 53;
+
+static const int kMinWheelButton = 4;
+#if defined(OS_CHROMEOS)
+// Chrome OS also uses buttons 8 and 9 for scrolling.
+static const int kMaxWheelButton = 9;
+#else
+static const int kMaxWheelButton = 7;
+#endif
int GetEventFlagsFromXState(unsigned int state) {
int flags = 0;
@@ -51,9 +59,9 @@ int GetEventFlagsForButton(int button) {
return ui::EF_MIDDLE_BUTTON_DOWN;
case 3:
return ui::EF_RIGHT_BUTTON_DOWN;
+ default:
+ return 0;
}
- DLOG(WARNING) << "Unexpected button (" << button << ") received.";
- return 0;
}
int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
@@ -145,24 +153,14 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
case KeyRelease:
return ET_KEY_RELEASED;
case ButtonPress:
- if (native_event->xbutton.button == 4 ||
- native_event->xbutton.button == 5)
+ if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
+ static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
return ET_MOUSEWHEEL;
-#if defined (OS_CHROMEOS)
- if (native_event->xbutton.button == 8 ||
- native_event->xbutton.button == 9)
- return ET_MOUSEWHEEL;
-#endif
return ET_MOUSE_PRESSED;
case ButtonRelease:
- if (native_event->xbutton.button == 4 ||
- native_event->xbutton.button == 5)
- return ET_MOUSEWHEEL;
-#if defined (OS_CHROMEOS)
- if (native_event->xbutton.button == 8 ||
- native_event->xbutton.button == 9)
+ if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
+ static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
return ET_MOUSEWHEEL;
-#endif
return ET_MOUSE_RELEASED;
case MotionNotify:
if (native_event->xmotion.state &
@@ -180,19 +178,15 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) {
return GetTouchEventType(native_event);
switch (xievent->evtype) {
case XI_ButtonPress:
-#if defined (OS_CHROMEOS)
- if (xievent->detail == 8 || xievent->detail == 9)
+ if (xievent->detail >= kMinWheelButton &&
+ xievent->detail <= kMaxWheelButton)
return ET_MOUSEWHEEL;
-#endif
- return (xievent->detail == 4 || xievent->detail == 5) ?
- ET_MOUSEWHEEL : ET_MOUSE_PRESSED;
+ return ET_MOUSE_PRESSED;
case XI_ButtonRelease:
-#if defined (OS_CHROMEOS)
- if (xievent->detail == 8 || xievent->detail == 9)
+ if (xievent->detail >= kMinWheelButton &&
+ xievent->detail <= kMaxWheelButton)
return ET_MOUSEWHEEL;
-#endif
- return (xievent->detail == 4 || xievent->detail == 5) ?
- ET_MOUSEWHEEL : ET_MOUSE_RELEASED;
+ return ET_MOUSE_RELEASED;
case XI_Motion:
return GetButtonMaskForX2Event(xievent) ?
ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
@@ -210,22 +204,30 @@ int EventFlagsFromNative(const base::NativeEvent& native_event) {
case KeyRelease:
return GetEventFlagsFromXState(native_event->xbutton.state);
case ButtonPress:
- case ButtonRelease:
- return GetEventFlagsFromXState(native_event->xbutton.state) |
- GetEventFlagsForButton(native_event->xbutton.button);
+ case ButtonRelease: {
+ int flags = GetEventFlagsFromXState(native_event->xbutton.state);
+ const EventType type = EventTypeFromNative(native_event);
+ if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
+ flags |= GetEventFlagsForButton(native_event->xbutton.button);
+ return flags;
+ }
case MotionNotify:
return GetEventFlagsFromXState(native_event->xmotion.state);
case GenericEvent: {
XIDeviceEvent* xievent =
static_cast<XIDeviceEvent*>(native_event->xcookie.data);
- bool touch =
+ const bool touch =
TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
switch (xievent->evtype) {
case XI_ButtonPress:
- case XI_ButtonRelease:
- return GetButtonMaskForX2Event(xievent) |
- GetEventFlagsFromXState(xievent->mods.effective) |
- (touch ? 0 : GetEventFlagsForButton(xievent->detail));
+ case XI_ButtonRelease: {
+ int flags = GetButtonMaskForX2Event(xievent) |
+ GetEventFlagsFromXState(xievent->mods.effective);
+ const EventType type = EventTypeFromNative(native_event);
+ if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
+ flags |= GetEventFlagsForButton(xievent->detail);
+ return flags;
+ }
case XI_Motion:
return GetButtonMaskForX2Event(xievent) |
GetEventFlagsFromXState(xievent->mods.effective);
@@ -280,13 +282,23 @@ int GetMouseWheelOffset(const base::NativeEvent& native_event) {
} else {
button = native_event->xbutton.button;
}
+ switch (button) {
+ case 4:
#if defined(OS_CHROMEOS)
- if (button == 8)
- return kWheelScrollAmount;
- else if (button == 9)
- return -kWheelScrollAmount;
+ case 8:
#endif
- return button == 4 ? kWheelScrollAmount : -kWheelScrollAmount;
+ return kWheelScrollAmount;
+
+ case 5:
+#if defined(OS_CHROMEOS)
+ case 9:
+#endif
+ return -kWheelScrollAmount;
+
+ default:
+ // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)?
+ return 0;
+ }
}
int GetTouchId(const base::NativeEvent& xev) {
diff --git a/ui/base/x/events_x_unittest.cc b/ui/base/x/events_x_unittest.cc
new file mode 100644
index 0000000..2419ff6
--- /dev/null
+++ b/ui/base/x/events_x_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 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 <cstring>
+
+#include <X11/Xlib.h>
+
+// Generically-named #defines from Xlib that conflict with symbols in GTest.
+#undef Bool
+#undef None
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/events.h"
+#include "ui/gfx/point.h"
+
+namespace ui {
+
+namespace {
+
+// Initializes the passed-in Xlib event.
+void InitButtonEvent(XEvent* event,
+ bool is_press,
+ const gfx::Point& location,
+ int button,
+ int state) {
+ memset(event, 0, sizeof(*event));
+
+ // We don't bother setting fields that the event code doesn't use, such as
+ // x_root/y_root and window/root/subwindow.
+ XButtonEvent* button_event = &(event->xbutton);
+ button_event->type = is_press ? ButtonPress : ButtonRelease;
+ button_event->x = location.x();
+ button_event->y = location.y();
+ button_event->button = button;
+ button_event->state = state;
+}
+
+} // namespace
+
+TEST(EventsXTest, ButtonEvents) {
+ XEvent event;
+ gfx::Point location(5, 10);
+
+ InitButtonEvent(&event, true, location, 1, 0);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+
+ InitButtonEvent(&event, true, location, 2, Button1Mask | ShiftMask);
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_MIDDLE_BUTTON_DOWN |
+ ui::EF_SHIFT_DOWN,
+ ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+
+ InitButtonEvent(&event, false, location, 3, 0);
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(ui::EF_RIGHT_BUTTON_DOWN, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+
+ // Scroll up.
+ InitButtonEvent(&event, true, location, 4, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+ EXPECT_GT(ui::GetMouseWheelOffset(&event), 0);
+
+ // Scroll down.
+ InitButtonEvent(&event, true, location, 5, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+ EXPECT_LT(ui::GetMouseWheelOffset(&event), 0);
+
+ // Scroll left, typically.
+ InitButtonEvent(&event, true, location, 6, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+ EXPECT_EQ(0, ui::GetMouseWheelOffset(&event));
+
+ // Scroll right, typically.
+ InitButtonEvent(&event, true, location, 7, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+ EXPECT_EQ(0, ui::GetMouseWheelOffset(&event));
+
+#if defined(OS_CHROMEOS)
+ // Scroll up.
+ InitButtonEvent(&event, true, location, 8, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+ EXPECT_GT(ui::GetMouseWheelOffset(&event), 0);
+
+ // Scroll down.
+ InitButtonEvent(&event, true, location, 9, 0);
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
+ EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
+ EXPECT_EQ(location, ui::EventLocationFromNative(&event));
+ EXPECT_TRUE(ui::IsMouseEvent(&event));
+ EXPECT_LT(ui::GetMouseWheelOffset(&event), 0);
+#endif
+
+ // TODO(derat): Test XInput code.
+}
+
+} // namespace ui
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
index 5dc86a6..82d5200 100644
--- a/ui/ui_unittests.gypi
+++ b/ui/ui_unittests.gypi
@@ -120,6 +120,11 @@
],
},
}],
+ ['OS == "linux"', {
+ 'sources': [
+ 'base/x/events_x_unittest.cc',
+ ],
+ }],
['OS != "mac"', {
'sources': [
'gfx/transform_unittest.cc',