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
This commit is contained in:
parent
e4930c0c41
commit
82054a406a
3 changed files with 85 additions and 1 deletions
|
@ -30,9 +30,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/pointer.h>
|
||||
#include <KWayland/Client/plasmashell.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
#include <KWayland/Client/shell.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
#include <KWayland/Client/xdgshell.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
@ -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<Test::ShellSurfaceType>("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> 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> surface(Test::createSurface());
|
||||
QFETCH(Test::ShellSurfaceType, type);
|
||||
QScopedPointer<QObject> 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*>(shellSurface.data())) {
|
||||
s->requestMove(Test::waylandSeat(), buttonSpy.first().first().value<quint32>());
|
||||
} else if (auto s = qobject_cast<XdgShellSurface*>(shellSurface.data())) {
|
||||
s->requestMove(Test::waylandSeat(), buttonSpy.first().first().value<quint32>());
|
||||
}
|
||||
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()
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue