Commit 37b2923f authored by Naoki Fukino's avatar Naoki Fukino Committed by Commit Bot

Support wl_pointer v5 to handle fling scroll.

Fling (kinetic) scroll event is notified using pointer.axis_stop
event in wayland terms, but the event is not supported in wl_pointer v4.
This CL upgrade the version from v4 to v5 to handle the events.

Doc: go/lacros-fling

Bug: 1105310
Change-Id: I0c1ad3391ba772d2f9e4cacfd60d7db1905958c2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2404224Reviewed-by: default avatarMaksim Sisov (GMT+3) <msisov@igalia.com>
Commit-Queue: Naoki Fukino <fukino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808272}
parent c07e685f
...@@ -47,7 +47,7 @@ constexpr uint32_t kMaxCompositorVersion = 4; ...@@ -47,7 +47,7 @@ constexpr uint32_t kMaxCompositorVersion = 4;
constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1; constexpr uint32_t kMaxGtkPrimarySelectionDeviceManagerVersion = 1;
constexpr uint32_t kMaxKeyboardExtensionVersion = 1; constexpr uint32_t kMaxKeyboardExtensionVersion = 1;
constexpr uint32_t kMaxLinuxDmabufVersion = 3; constexpr uint32_t kMaxLinuxDmabufVersion = 3;
constexpr uint32_t kMaxSeatVersion = 4; constexpr uint32_t kMaxSeatVersion = 5;
constexpr uint32_t kMaxShmVersion = 1; constexpr uint32_t kMaxShmVersion = 1;
constexpr uint32_t kMaxXdgShellVersion = 1; constexpr uint32_t kMaxXdgShellVersion = 1;
constexpr uint32_t kMaxDeviceManagerVersion = 3; constexpr uint32_t kMaxDeviceManagerVersion = 3;
......
...@@ -37,6 +37,12 @@ bool HasAnyPointerButtonFlag(int flags) { ...@@ -37,6 +37,12 @@ bool HasAnyPointerButtonFlag(int flags) {
EF_FORWARD_MOUSE_BUTTON)) != 0; EF_FORWARD_MOUSE_BUTTON)) != 0;
} }
// Number of fingers for scroll gestures.
constexpr int kGestureScrollFingerCount = 2;
// Maximum size of the stored recent pointer frame information.
constexpr int kRecentPointerFrameMaxSize = 20;
} // namespace } // namespace
struct WaylandEventSource::TouchPoint { struct WaylandEventSource::TouchPoint {
...@@ -200,6 +206,51 @@ void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2d& offset) { ...@@ -200,6 +206,51 @@ void WaylandEventSource::OnPointerAxisEvent(const gfx::Vector2d& offset) {
MouseWheelEvent event(offset, pointer_location_, pointer_location_, MouseWheelEvent event(offset, pointer_location_, pointer_location_,
EventTimeForNow(), flags, 0); EventTimeForNow(), flags, 0);
DispatchEvent(&event); DispatchEvent(&event);
current_pointer_frame_.dx += offset.x();
current_pointer_frame_.dy += offset.y();
}
void WaylandEventSource::OnPointerFrameEvent() {
base::TimeTicks now = EventTimeForNow();
current_pointer_frame_.dt = now - last_pointer_frame_time_;
last_pointer_frame_time_ = now;
// Dispatch Fling event if pointer.axis_stop is notified and the recent
// pointer.axis events meets the criteria to start fling scroll.
if (current_pointer_frame_.dx == 0 && current_pointer_frame_.dy == 0 &&
current_pointer_frame_.is_axis_stop) {
gfx::Vector2dF initial_velocity = ComputeFlingVelocity();
float vx = initial_velocity.x();
float vy = initial_velocity.y();
ScrollEvent event(
vx == 0 && vy == 0 ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START,
pointer_location_, pointer_location_, now,
pointer_flags_ | keyboard_modifiers_, vx, vy, vx, vy,
kGestureScrollFingerCount);
DispatchEvent(&event);
recent_pointer_frames_.clear();
} else {
if (recent_pointer_frames_.size() + 1 > kRecentPointerFrameMaxSize)
recent_pointer_frames_.pop_back();
recent_pointer_frames_.push_front(current_pointer_frame_);
}
// Reset |current_pointer_frame_|.
current_pointer_frame_.dx = 0;
current_pointer_frame_.dy = 0;
current_pointer_frame_.is_axis_stop = false;
}
void WaylandEventSource::OnPointerAxisSourceEvent(uint32_t axis_source) {
current_pointer_frame_.axis_source = axis_source;
}
void WaylandEventSource::OnPointerAxisStopEvent(uint32_t axis) {
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
current_pointer_frame_.dy = 0;
} else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
current_pointer_frame_.dx = 0;
}
current_pointer_frame_.is_axis_stop = true;
} }
void WaylandEventSource::OnTouchCreated(WaylandTouch* touch) { void WaylandEventSource::OnTouchCreated(WaylandTouch* touch) {
...@@ -359,4 +410,28 @@ bool WaylandEventSource::ShouldUnsetTouchFocus(WaylandWindow* win, ...@@ -359,4 +410,28 @@ bool WaylandEventSource::ShouldUnsetTouchFocus(WaylandWindow* win,
return result == touch_points_.end(); return result == touch_points_.end();
} }
gfx::Vector2dF WaylandEventSource::ComputeFlingVelocity() {
// Return average velocity in the last 200ms.
// TODO(fukino): Make the formula similar to libgestures's
// RegressScrollVelocity(). crbug.com/1129263.
base::TimeDelta dt;
float dx = 0.0f;
float dy = 0.0f;
for (auto& frame : recent_pointer_frames_) {
if (frame.axis_source != WL_POINTER_AXIS_SOURCE_FINGER)
break;
if (frame.dx == 0 && frame.dy == 0)
break;
if (dt + frame.dt > base::TimeDelta::FromMilliseconds(200))
break;
dx += frame.dx;
dy += frame.dy;
dt += frame.dt;
}
float dt_inv = 1.0f / dt.InSecondsF();
return dt.is_zero() ? gfx::Vector2dF()
: gfx::Vector2dF(dx * dt_inv, dy * dt_inv);
}
} // namespace ui } // namespace ui
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_ #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_
#define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_ #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_
#include <deque>
#include <memory> #include <memory>
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
...@@ -99,6 +100,9 @@ class WaylandEventSource : public PlatformEventSource, ...@@ -99,6 +100,9 @@ class WaylandEventSource : public PlatformEventSource,
WaylandWindow* window = nullptr) override; WaylandWindow* window = nullptr) override;
void OnPointerMotionEvent(const gfx::PointF& location) override; void OnPointerMotionEvent(const gfx::PointF& location) override;
void OnPointerAxisEvent(const gfx::Vector2d& offset) override; void OnPointerAxisEvent(const gfx::Vector2d& offset) override;
void OnPointerFrameEvent() override;
void OnPointerAxisSourceEvent(uint32_t axis_source) override;
void OnPointerAxisStopEvent(uint32_t axis) override;
// WaylandTouch::Delegate // WaylandTouch::Delegate
void OnTouchCreated(WaylandTouch* touch) override; void OnTouchCreated(WaylandTouch* touch) override;
...@@ -114,6 +118,13 @@ class WaylandEventSource : public PlatformEventSource, ...@@ -114,6 +118,13 @@ class WaylandEventSource : public PlatformEventSource,
void OnTouchCancelEvent() override; void OnTouchCancelEvent() override;
private: private:
struct PointerFrame {
uint32_t axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
float dx = 0.0f;
float dy = 0.0f;
base::TimeDelta dt;
bool is_axis_stop = false;
};
struct TouchPoint; struct TouchPoint;
// PlatformEventSource: // PlatformEventSource:
...@@ -130,6 +141,9 @@ class WaylandEventSource : public PlatformEventSource, ...@@ -130,6 +141,9 @@ class WaylandEventSource : public PlatformEventSource,
base::Optional<PointerId> id = base::nullopt); base::Optional<PointerId> id = base::nullopt);
bool ShouldUnsetTouchFocus(WaylandWindow* window, PointerId id); bool ShouldUnsetTouchFocus(WaylandWindow* window, PointerId id);
// Computes initial velocity of fling scroll based on recent frames.
gfx::Vector2dF ComputeFlingVelocity();
WaylandWindowManager* const window_manager_; WaylandWindowManager* const window_manager_;
// Input device objects. Owned by WaylandConnection. // Input device objects. Owned by WaylandConnection.
...@@ -149,6 +163,16 @@ class WaylandEventSource : public PlatformEventSource, ...@@ -149,6 +163,16 @@ class WaylandEventSource : public PlatformEventSource,
// Last known pointer location. // Last known pointer location.
gfx::PointF pointer_location_; gfx::PointF pointer_location_;
// Current frame
PointerFrame current_pointer_frame_;
// Time of the last pointer frame event.
base::TimeTicks last_pointer_frame_time_;
// Recent pointer frames to compute fling scroll.
// Front is newer, and back is older.
std::deque<PointerFrame> recent_pointer_frames_;
// The window the pointer is over. // The window the pointer is over.
WaylandWindow* window_with_pointer_focus_ = nullptr; WaylandWindow* window_with_pointer_focus_ = nullptr;
......
...@@ -21,9 +21,11 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer, ...@@ -21,9 +21,11 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
Delegate* delegate) Delegate* delegate)
: obj_(pointer), connection_(connection), delegate_(delegate) { : obj_(pointer), connection_(connection), delegate_(delegate) {
static const wl_pointer_listener listener = { static const wl_pointer_listener listener = {
&WaylandPointer::Enter, &WaylandPointer::Leave, &WaylandPointer::Motion, &WaylandPointer::Enter, &WaylandPointer::Leave,
&WaylandPointer::Button, &WaylandPointer::Axis, &WaylandPointer::Motion, &WaylandPointer::Button,
}; &WaylandPointer::Axis, &WaylandPointer::Frame,
&WaylandPointer::AxisSource, &WaylandPointer::AxisStop,
&WaylandPointer::AxisDiscrete};
DCHECK(delegate_); DCHECK(delegate_);
delegate_->OnPointerCreated(this); delegate_->OnPointerCreated(this);
...@@ -136,4 +138,37 @@ void WaylandPointer::Axis(void* data, ...@@ -136,4 +138,37 @@ void WaylandPointer::Axis(void* data,
pointer->delegate_->OnPointerAxisEvent(offset); pointer->delegate_->OnPointerAxisEvent(offset);
} }
// static
void WaylandPointer::Frame(void* data, wl_pointer* obj) {
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
pointer->delegate_->OnPointerFrameEvent();
}
// static
void WaylandPointer::AxisSource(void* data,
wl_pointer* obj,
uint32_t axis_source) {
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
pointer->delegate_->OnPointerAxisSourceEvent(axis_source);
}
// static
void WaylandPointer::AxisStop(void* data,
wl_pointer* obj,
uint32_t time,
uint32_t axis) {
WaylandPointer* pointer = static_cast<WaylandPointer*>(data);
pointer->delegate_->OnPointerAxisStopEvent(axis);
}
// static
void WaylandPointer::AxisDiscrete(void* data,
wl_pointer* obj,
uint32_t axis,
int32_t discrete) {
// TODO(fukino): Use this events for better handling of mouse wheel events.
// crbug.com/1129259.
NOTIMPLEMENTED_LOG_ONCE();
}
} // namespace ui } // namespace ui
...@@ -60,6 +60,16 @@ class WaylandPointer { ...@@ -60,6 +60,16 @@ class WaylandPointer {
uint32_t time, uint32_t time,
uint32_t axis, uint32_t axis,
wl_fixed_t value); wl_fixed_t value);
static void Frame(void* data, wl_pointer* obj);
static void AxisSource(void* data, wl_pointer* obj, uint32_t axis_source);
static void AxisStop(void* data,
wl_pointer* obj,
uint32_t time,
uint32_t axis);
static void AxisDiscrete(void* data,
wl_pointer* obj,
uint32_t axis,
int32_t discrete);
wl::Object<wl_pointer> obj_; wl::Object<wl_pointer> obj_;
WaylandConnection* const connection_; WaylandConnection* const connection_;
...@@ -79,6 +89,9 @@ class WaylandPointer::Delegate { ...@@ -79,6 +89,9 @@ class WaylandPointer::Delegate {
WaylandWindow* window = nullptr) = 0; WaylandWindow* window = nullptr) = 0;
virtual void OnPointerMotionEvent(const gfx::PointF& location) = 0; virtual void OnPointerMotionEvent(const gfx::PointF& location) = 0;
virtual void OnPointerAxisEvent(const gfx::Vector2d& offset) = 0; virtual void OnPointerAxisEvent(const gfx::Vector2d& offset) = 0;
virtual void OnPointerFrameEvent() = 0;
virtual void OnPointerAxisSourceEvent(uint32_t axis_source) = 0;
virtual void OnPointerAxisStopEvent(uint32_t axis) = 0;
}; };
} // namespace ui } // namespace ui
......
...@@ -253,6 +253,8 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) { ...@@ -253,6 +253,8 @@ bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
return has_keyboard_focus_; return has_keyboard_focus_;
if (event->IsTouchEvent()) if (event->IsTouchEvent())
return has_touch_focus_; return has_touch_focus_;
if (event->IsScrollEvent())
return has_pointer_focus_;
return false; return false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment