From 82054a406a6470c763d72c39f6c7fdf5667ee629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 24 Oct 2016 17:09:40 +0200 Subject: [PATCH] Send a pointer leave when triggering a move resize Summary: When triggering a move resize all following pointer events are grabbed by KWin itself. Thus the correct behavior is to informe the client about it and send a pointer leave. This ensures that after the move resize ended the pointer gets a new enter. By sending anew pointer enter the position gets updated to the new position which so far did not happen and the client generated events on the wrong position. BUG: 371573 FIXED-IN: 5.8.3 Reviewers: #kwin, #plasma_on_wayland, broulik Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D3154 --- .../integration/move_resize_window_test.cpp | 70 ++++++++++++++++++- pointer_input.cpp | 15 ++++ pointer_input.h | 1 + 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/autotests/integration/move_resize_window_test.cpp b/autotests/integration/move_resize_window_test.cpp index 8c968f2024..e090dde134 100644 --- a/autotests/integration/move_resize_window_test.cpp +++ b/autotests/integration/move_resize_window_test.cpp @@ -30,9 +30,12 @@ along with this program. If not, see . #include #include +#include #include +#include #include #include +#include #include #include @@ -61,6 +64,8 @@ private Q_SLOTS: void testGrowShrink(); void testPointerMoveEnd_data(); void testPointerMoveEnd(); + void testClientSideMove_data(); + void testClientSideMove(); void testPlasmaShellSurfaceMovable_data(); void testPlasmaShellSurfaceMovable(); void testNetMove(); @@ -88,7 +93,8 @@ void MoveResizeWindowTest::initTestCase() void MoveResizeWindowTest::init() { - QVERIFY(Test::setupWaylandConnection(s_socketName, Test::AdditionalWaylandInterface::PlasmaShell)); + QVERIFY(Test::setupWaylandConnection(s_socketName, Test::AdditionalWaylandInterface::PlasmaShell | Test::AdditionalWaylandInterface::Seat)); + QVERIFY(Test::waitForWaylandPointer()); m_connection = Test::waylandConnection(); m_compositor = Test::waylandCompositor(); m_shell = Test::waylandShell(); @@ -402,6 +408,68 @@ void MoveResizeWindowTest::testPointerMoveEnd() surface.reset(); QVERIFY(Test::waitForWindowDestroyed(c)); } +void MoveResizeWindowTest::testClientSideMove_data() +{ + QTest::addColumn("type"); + + QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell; + QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5; +} + +void MoveResizeWindowTest::testClientSideMove() +{ + using namespace KWayland::Client; + Cursor::setPos(640, 512); + QScopedPointer pointer(Test::waylandSeat()->createPointer()); + QSignalSpy pointerEnteredSpy(pointer.data(), &Pointer::entered); + QVERIFY(pointerEnteredSpy.isValid()); + QSignalSpy pointerLeftSpy(pointer.data(), &Pointer::left); + QVERIFY(pointerLeftSpy.isValid()); + QSignalSpy buttonSpy(pointer.data(), &Pointer::buttonStateChanged); + QVERIFY(buttonSpy.isValid()); + + QScopedPointer surface(Test::createSurface()); + QFETCH(Test::ShellSurfaceType, type); + QScopedPointer shellSurface(Test::createShellSurface(type, surface.data())); + auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue); + QVERIFY(c); + + // move pointer into center of geometry + const QRect startGeometry = c->geometry(); + Cursor::setPos(startGeometry.center()); + QVERIFY(pointerEnteredSpy.wait()); + QCOMPARE(pointerEnteredSpy.first().last().toPoint(), QPoint(49, 24)); + // simulate press + quint32 timestamp = 1; + kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++); + QVERIFY(buttonSpy.wait()); + QSignalSpy moveStartSpy(c, &AbstractClient::clientStartUserMovedResized); + QVERIFY(moveStartSpy.isValid()); + if (auto s = qobject_cast(shellSurface.data())) { + s->requestMove(Test::waylandSeat(), buttonSpy.first().first().value()); + } else if (auto s = qobject_cast(shellSurface.data())) { + s->requestMove(Test::waylandSeat(), buttonSpy.first().first().value()); + } + QVERIFY(moveStartSpy.wait()); + QCOMPARE(c->isMove(), true); + QVERIFY(pointerLeftSpy.wait()); + + // move a bit + QSignalSpy clientMoveStepSpy(c, &AbstractClient::clientStepUserMovedResized); + QVERIFY(clientMoveStepSpy.isValid()); + const QPoint startPoint = startGeometry.center(); + const int dragDistance = QApplication::startDragDistance(); + // Why? + kwinApp()->platform()->pointerMotion(startPoint + QPoint(dragDistance, dragDistance) + QPoint(6, 6), timestamp++); + QCOMPARE(clientMoveStepSpy.count(), 1); + + // and release again + kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++); + QVERIFY(pointerEnteredSpy.wait()); + QCOMPARE(c->isMove(), false); + QCOMPARE(c->geometry(), startGeometry.translated(QPoint(dragDistance, dragDistance) + QPoint(6, 6))); + QCOMPARE(pointerEnteredSpy.last().last().toPoint(), QPoint(49, 24)); +} void MoveResizeWindowTest::testPlasmaShellSurfaceMovable_data() { diff --git a/pointer_input.cpp b/pointer_input.cpp index 7716a4e61e..c2a04d094d 100644 --- a/pointer_input.cpp +++ b/pointer_input.cpp @@ -154,12 +154,27 @@ void PointerInputRedirection::init() } } ); + // connect the move resize of all window + auto setupMoveResizeConnection = [this] (AbstractClient *c) { + connect(c, &AbstractClient::clientStartUserMovedResized, this, &PointerInputRedirection::updateOnStartMoveResize); + connect(c, &AbstractClient::clientFinishUserMovedResized, this, &PointerInputRedirection::update); + }; + const auto clients = workspace()->allClientList(); + std::for_each(clients.begin(), clients.end(), setupMoveResizeConnection); + connect(workspace(), &Workspace::clientAdded, this, setupMoveResizeConnection); + connect(waylandServer(), &WaylandServer::shellClientAdded, this, setupMoveResizeConnection); // warp the cursor to center of screen warp(screens()->geometry().center()); updateAfterScreenChange(); } +void PointerInputRedirection::updateOnStartMoveResize() +{ + m_window.clear(); + waylandServer()->seat()->setFocusedPointerSurface(nullptr); +} + void PointerInputRedirection::processMotion(const QPointF &pos, uint32_t time, LibInput::Device *device) { if (!m_inited) { diff --git a/pointer_input.h b/pointer_input.h index cd730e9acc..e1bef9c62f 100644 --- a/pointer_input.h +++ b/pointer_input.h @@ -128,6 +128,7 @@ public: void processPinchGestureCancelled(quint32 time, KWin::LibInput::Device *device = nullptr); private: + void updateOnStartMoveResize(); void updatePosition(const QPointF &pos); void updateButton(uint32_t button, InputRedirection::PointerButtonState state); void warpXcbOnSurfaceLeft(KWayland::Server::SurfaceInterface *surface);