core: Batch pointer input device events

This change introduces InputDevice::pointerFrame(). The main motivation
behind it is to allow batching multiple pointer events within a single
event frame.

BUG: 454428
This commit is contained in:
Vlad Zahorodnii 2023-05-04 17:15:40 +03:00
parent 60205c1348
commit e6b5cf283e
10 changed files with 77 additions and 10 deletions

View file

@ -1497,36 +1497,42 @@ void pointerAxisHorizontal(qreal delta, quint32 time, qint32 discreteDelta, Inpu
{
auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
Q_EMIT virtualPointer->pointerAxisChanged(InputRedirection::PointerAxis::PointerAxisHorizontal, delta, discreteDelta, source, std::chrono::milliseconds(time), virtualPointer);
Q_EMIT virtualPointer->pointerFrame(virtualPointer);
}
void pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta, InputRedirection::PointerAxisSource source)
{
auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
Q_EMIT virtualPointer->pointerAxisChanged(InputRedirection::PointerAxis::PointerAxisVertical, delta, discreteDelta, source, std::chrono::milliseconds(time), virtualPointer);
Q_EMIT virtualPointer->pointerFrame(virtualPointer);
}
void pointerButtonPressed(quint32 button, quint32 time)
{
auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
Q_EMIT virtualPointer->pointerButtonChanged(button, InputRedirection::PointerButtonState::PointerButtonPressed, std::chrono::milliseconds(time), virtualPointer);
Q_EMIT virtualPointer->pointerFrame(virtualPointer);
}
void pointerButtonReleased(quint32 button, quint32 time)
{
auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
Q_EMIT virtualPointer->pointerButtonChanged(button, InputRedirection::PointerButtonState::PointerButtonReleased, std::chrono::milliseconds(time), virtualPointer);
Q_EMIT virtualPointer->pointerFrame(virtualPointer);
}
void pointerMotion(const QPointF &position, quint32 time)
{
auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
Q_EMIT virtualPointer->pointerMotionAbsolute(position, std::chrono::milliseconds(time), virtualPointer);
Q_EMIT virtualPointer->pointerFrame(virtualPointer);
}
void pointerMotionRelative(const QPointF &delta, quint32 time)
{
auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
Q_EMIT virtualPointer->pointerMotion(delta, delta, std::chrono::milliseconds(time), virtualPointer);
Q_EMIT virtualPointer->pointerFrame(virtualPointer);
}
void touchCancel()

View file

@ -22,18 +22,22 @@ FakeInputDevice::FakeInputDevice(KWaylandServer::FakeInputDevice *device, QObjec
connect(device, &KWaylandServer::FakeInputDevice::pointerMotionRequested, this, [this](const QPointF &delta) {
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
Q_EMIT pointerMotion(delta, delta, time, this);
Q_EMIT pointerFrame(this);
});
connect(device, &KWaylandServer::FakeInputDevice::pointerMotionAbsoluteRequested, this, [this](const QPointF &pos) {
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
Q_EMIT pointerMotionAbsolute(pos, time, this);
Q_EMIT pointerFrame(this);
});
connect(device, &KWaylandServer::FakeInputDevice::pointerButtonPressRequested, this, [this](quint32 button) {
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
Q_EMIT pointerButtonChanged(button, InputRedirection::PointerButtonPressed, time, this);
Q_EMIT pointerFrame(this);
});
connect(device, &KWaylandServer::FakeInputDevice::pointerButtonReleaseRequested, this, [this](quint32 button) {
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
Q_EMIT pointerButtonChanged(button, InputRedirection::PointerButtonReleased, time, this);
Q_EMIT pointerFrame(this);
});
connect(device, &KWaylandServer::FakeInputDevice::pointerAxisRequested, this, [this](Qt::Orientation orientation, qreal delta) {
InputRedirection::PointerAxis axis;
@ -50,6 +54,7 @@ FakeInputDevice::FakeInputDevice(KWaylandServer::FakeInputDevice *device, QObjec
}
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, time, this);
Q_EMIT pointerFrame(this);
});
connect(device, &KWaylandServer::FakeInputDevice::touchDownRequested, this, [this](qint32 id, const QPointF &pos) {
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());

View file

@ -318,6 +318,7 @@ void Connection::processEvents()
pointerEvent->time(),
pointerEvent->device());
}
Q_EMIT pointerEvent->device()->pointerFrame(pointerEvent->device());
break;
}
case LIBINPUT_EVENT_POINTER_SCROLL_FINGER: {
@ -331,6 +332,7 @@ void Connection::processEvents()
pointerEvent->time(),
pointerEvent->device());
}
Q_EMIT pointerEvent->device()->pointerFrame(pointerEvent->device());
break;
}
case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS: {
@ -344,11 +346,13 @@ void Connection::processEvents()
pointerEvent->time(),
pointerEvent->device());
}
Q_EMIT pointerEvent->device()->pointerFrame(pointerEvent->device());
break;
}
case LIBINPUT_EVENT_POINTER_BUTTON: {
PointerEvent *pe = static_cast<PointerEvent *>(event.get());
Q_EMIT pe->device()->pointerButtonChanged(pe->button(), pe->buttonState(), pe->time(), pe->device());
Q_EMIT pe->device()->pointerFrame(pe->device());
break;
}
case LIBINPUT_EVENT_POINTER_MOTION: {
@ -369,12 +373,14 @@ void Connection::processEvents()
}
}
Q_EMIT pe->device()->pointerMotion(delta, deltaNonAccel, latestTime, pe->device());
Q_EMIT pe->device()->pointerFrame(pe->device());
break;
}
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: {
PointerEvent *pe = static_cast<PointerEvent *>(event.get());
if (workspace()) {
Q_EMIT pe->device()->pointerMotionAbsolute(pe->absolutePos(workspace()->geometry().size()), pe->time(), pe->device());
Q_EMIT pe->device()->pointerFrame(pe->device());
}
break;
}

View file

@ -126,6 +126,10 @@ WaylandInputDevice::WaylandInputDevice(KWayland::Client::Pointer *pointer, Wayla
Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, std::chrono::milliseconds(time), this);
});
connect(pointer, &Pointer::frame, this, [this]() {
Q_EMIT pointerFrame(this);
});
KWayland::Client::PointerGestures *pointerGestures = m_seat->backend()->display()->pointerGestures();
if (pointerGestures) {
m_pinchGesture.reset(pointerGestures->createPinchGesture(m_pointer.get(), this));

View file

@ -416,6 +416,7 @@ void X11WindowedBackend::handleEvent(xcb_generic_event_t *e)
}
const QPointF position = output->mapFromGlobal(QPointF(event->root_x, event->root_y));
Q_EMIT m_pointerDevice->pointerMotionAbsolute(position, std::chrono::milliseconds(event->time), m_pointerDevice.get());
Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get());
} break;
case XCB_KEY_PRESS:
case XCB_KEY_RELEASE: {
@ -575,6 +576,7 @@ void X11WindowedBackend::handleButtonPress(xcb_button_press_event_t *event)
InputRedirection::PointerAxisSourceUnknown,
std::chrono::milliseconds(event->time),
m_pointerDevice.get());
Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get());
return;
}
uint32_t button = 0;
@ -601,6 +603,7 @@ void X11WindowedBackend::handleButtonPress(xcb_button_press_event_t *event)
} else {
Q_EMIT m_pointerDevice->pointerButtonChanged(button, InputRedirection::PointerButtonReleased, std::chrono::milliseconds(event->time), m_pointerDevice.get());
}
Q_EMIT m_pointerDevice->pointerFrame(m_pointerDevice.get());
}
void X11WindowedBackend::handleExpose(xcb_expose_event_t *event)

View file

@ -54,6 +54,7 @@ Q_SIGNALS:
void pointerMotion(const QPointF &delta, const QPointF &deltaNonAccelerated, std::chrono::microseconds time, InputDevice *device);
void pointerAxisChanged(InputRedirection::PointerAxis axis, qreal delta, qint32 deltaV120,
InputRedirection::PointerAxisSource source, std::chrono::microseconds time, InputDevice *device);
void pointerFrame(InputDevice *device);
void touchFrame(InputDevice *device);
void touchCanceled(InputDevice *device);
void touchDown(qint32 id, const QPointF &absolutePos, std::chrono::microseconds time, InputDevice *device);

View file

@ -111,6 +111,11 @@ bool InputEventFilter::pointerEvent(MouseEvent *event, quint32 nativeButton)
return false;
}
bool InputEventFilter::pointerFrame()
{
return false;
}
bool InputEventFilter::wheelEvent(WheelEvent *event)
{
return false;
@ -322,7 +327,6 @@ public:
if (pointerSurfaceAllowed()) {
// TODO: should the pointer position always stay in sync, i.e. not do the check?
seat->notifyPointerMotion(event->screenPos());
seat->notifyPointerFrame();
}
} else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) {
if (pointerSurfaceAllowed()) {
@ -332,11 +336,21 @@ public:
? KWaylandServer::PointerButtonState::Pressed
: KWaylandServer::PointerButtonState::Released;
seat->notifyPointerButton(nativeButton, state);
seat->notifyPointerFrame();
}
}
return true;
}
bool pointerFrame() override
{
if (!waylandServer()->isScreenLocked()) {
return false;
}
auto seat = waylandServer()->seat();
if (pointerSurfaceAllowed()) {
seat->notifyPointerFrame();
}
return true;
}
bool wheelEvent(WheelEvent *event) override
{
if (!waylandServer()->isScreenLocked()) {
@ -349,7 +363,6 @@ public:
seat->notifyPointerAxis(wheelEvent->orientation(), wheelEvent->delta(),
wheelEvent->deltaV120(),
kwinAxisSourceToKWaylandAxisSource(wheelEvent->axisSource()));
seat->notifyPointerFrame();
}
return true;
}
@ -1774,22 +1787,25 @@ public:
if (!e->delta().isNull()) {
seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestamp());
}
seat->notifyPointerFrame();
break;
}
case QEvent::MouseButtonPress:
seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Pressed);
seat->notifyPointerFrame();
break;
case QEvent::MouseButtonRelease:
seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Released);
seat->notifyPointerFrame();
break;
default:
break;
}
return true;
}
bool pointerFrame() override
{
auto seat = waylandServer()->seat();
seat->notifyPointerFrame();
return true;
}
bool wheelEvent(WheelEvent *event) override
{
auto seat = waylandServer()->seat();
@ -1797,7 +1813,6 @@ public:
auto _event = static_cast<WheelEvent *>(event);
seat->notifyPointerAxis(_event->orientation(), _event->delta(), _event->deltaV120(),
kwinAxisSourceToKWaylandAxisSource(_event->axisSource()));
seat->notifyPointerFrame();
return true;
}
bool keyEvent(KeyEvent *event) override
@ -2399,7 +2414,6 @@ public:
case QEvent::MouseMove: {
const auto pos = input()->globalPointer();
seat->notifyPointerMotion(pos);
seat->notifyPointerFrame();
Window *dragTarget = pickDragTarget(pos);
if (dragTarget) {
@ -2438,13 +2452,11 @@ public:
}
case QEvent::MouseButtonPress:
seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Pressed);
seat->notifyPointerFrame();
break;
case QEvent::MouseButtonRelease:
raiseDragTarget();
m_dragTarget = nullptr;
seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Released);
seat->notifyPointerFrame();
break;
default:
break;
@ -2453,6 +2465,20 @@ public:
return true;
}
bool pointerFrame() override
{
auto seat = waylandServer()->seat();
if (!seat->isDragPointer()) {
return false;
}
if (seat->isDragTouch()) {
return true;
}
seat->notifyPointerFrame();
return true;
}
bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
{
auto seat = waylandServer()->seat();
@ -2916,6 +2942,8 @@ void InputRedirection::addInputDevice(InputDevice *device)
m_pointer, &PointerInputRedirection::processButton);
connect(device, &InputDevice::pointerAxisChanged,
m_pointer, &PointerInputRedirection::processAxis);
connect(device, &InputDevice::pointerFrame,
m_pointer, &PointerInputRedirection::processFrame);
connect(device, &InputDevice::pinchGestureBegin,
m_pointer, &PointerInputRedirection::processPinchGestureBegin);
connect(device, &InputDevice::pinchGestureUpdate,

View file

@ -384,6 +384,7 @@ public:
* @return @c true to stop further event processing, @c false to pass to next filter
*/
virtual bool pointerEvent(MouseEvent *event, quint32 nativeButton);
virtual bool pointerFrame();
/**
* Event filter for pointer axis events.
*

View file

@ -433,6 +433,15 @@ void PointerInputRedirection::processHoldGestureCancelled(std::chrono::microseco
input()->processFilters(std::bind(&InputEventFilter::holdGestureCancelled, std::placeholders::_1, time));
}
void PointerInputRedirection::processFrame(KWin::InputDevice *device)
{
if (!inited()) {
return;
}
input()->processFilters(std::bind(&InputEventFilter::pointerFrame, std::placeholders::_1));
}
bool PointerInputRedirection::areButtonsPressed() const
{
for (auto state : m_buttons) {

View file

@ -143,6 +143,10 @@ public:
* @internal
*/
void processHoldGestureCancelled(std::chrono::microseconds time, KWin::InputDevice *device = nullptr);
/**
* @internal
*/
void processFrame(KWin::InputDevice *device = nullptr);
private:
void processMotionInternal(const QPointF &pos, const QPointF &delta, const QPointF &deltaNonAccelerated, std::chrono::microseconds time, InputDevice *device);