diff --git a/autotests/integration/touch_input_test.cpp b/autotests/integration/touch_input_test.cpp index 2a2381a060..06c3f70bf0 100644 --- a/autotests/integration/touch_input_test.cpp +++ b/autotests/integration/touch_input_test.cpp @@ -10,6 +10,7 @@ #include "abstract_client.h" #include "abstract_output.h" #include "platform.h" +#include "touch_input.h" #include "cursor.h" #include "screens.h" #include "wayland_server.h" @@ -40,6 +41,7 @@ private Q_SLOTS: void testCancel(); void testTouchMouseAction(); void testTouchPointCount(); + void testUpdateFocusOnDecorationDestroy(); private: AbstractClient *showWindow(bool decorated = false); @@ -67,7 +69,9 @@ void TouchInputTest::initTestCase() void TouchInputTest::init() { using namespace KWayland::Client; - QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::Decoration)); + QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | + Test::AdditionalWaylandInterface::Decoration | + Test::AdditionalWaylandInterface::XdgDecorationV1)); QVERIFY(Test::waitForWaylandTouch()); m_touch = Test::waylandSeat()->createTouch(Test::waylandSeat()); QVERIFY(m_touch); @@ -281,6 +285,95 @@ void TouchInputTest::testTouchPointCount() QCOMPARE(kwinApp()->platform()->touchPointCount(), 0); } +void TouchInputTest::testUpdateFocusOnDecorationDestroy() +{ + // This test verifies that a maximized client gets it's touch focus + // if decoration was focused and then destroyed on maximize with BorderlessMaximizedWindows option. + + QSignalSpy sequenceEndedSpy(m_touch, &KWayland::Client::Touch::sequenceEnded); + QVERIFY(sequenceEndedSpy.isValid()); + + // Enable the borderless maximized windows option. + auto group = kwinApp()->config()->group("Windows"); + group.writeEntry("BorderlessMaximizedWindows", true); + group.sync(); + Workspace::self()->slotReconfigure(); + QCOMPARE(options->borderlessMaximizedWindows(), true); + + // Create the test client. + QScopedPointer surface(Test::createSurface()); + QScopedPointer shellSurface( + Test::createXdgToplevelSurface(surface.data(), surface.data(), Test::CreationSetup::CreateOnly)); + QScopedPointer decoration(Test::createXdgToplevelDecorationV1(shellSurface.data())); + + QSignalSpy toplevelConfigureRequestedSpy(shellSurface.data(), &Test::XdgToplevel::configureRequested); + QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); + QSignalSpy decorationConfigureRequestedSpy(decoration.data(), &Test::XdgToplevelDecorationV1::configureRequested); + decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side); + surface->commit(KWayland::Client::Surface::CommitFlag::None); + + // Wait for the initial configure event. + Test::XdgToplevel::States states; + QVERIFY(surfaceConfigureRequestedSpy.wait()); + QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); + QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(0, 0)); + states = toplevelConfigureRequestedSpy.last().at(1).value(); + QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated)); + QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); + + // Map the client. + shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value()); + AbstractClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue); + QVERIFY(client); + QVERIFY(client->isActive()); + QCOMPARE(client->maximizeMode(), MaximizeMode::MaximizeRestore); + QCOMPARE(client->requestedMaximizeMode(), MaximizeMode::MaximizeRestore); + QCOMPARE(client->isDecorated(), true); + + // We should receive a configure event when the client becomes active. + QVERIFY(surfaceConfigureRequestedSpy.wait()); + QCOMPARE(surfaceConfigureRequestedSpy.count(), 2); + states = toplevelConfigureRequestedSpy.last().at(1).value(); + QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); + QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized)); + + // Simulate decoration hover + quint32 timestamp = 0; + kwinApp()->platform()->touchDown(1, client->frameGeometry().topLeft(), timestamp++); + QVERIFY(input()->touch()->decoration()); + + // Maximize when on decoration + workspace()->slotWindowMaximize(); + QVERIFY(surfaceConfigureRequestedSpy.wait()); + QCOMPARE(surfaceConfigureRequestedSpy.count(), 3); + QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024)); + states = toplevelConfigureRequestedSpy.last().at(1).value(); + QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated)); + QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized)); + + QSignalSpy frameGeometryChangedSpy(client, &AbstractClient::frameGeometryChanged); + QVERIFY(frameGeometryChangedSpy.isValid()); + shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value()); + Test::render(surface.data(), QSize(1280, 1024), Qt::blue); + QVERIFY(frameGeometryChangedSpy.wait()); + QCOMPARE(client->frameGeometry(), QRect(0, 0, 1280, 1024)); + QCOMPARE(client->maximizeMode(), MaximizeFull); + QCOMPARE(client->requestedMaximizeMode(), MaximizeFull); + QCOMPARE(client->isDecorated(), false); + + // Window should have focus + QVERIFY(!input()->touch()->decoration()); + kwinApp()->platform()->touchUp(1, timestamp++); + QVERIFY(!sequenceEndedSpy.wait(100)); + kwinApp()->platform()->touchDown(2, client->frameGeometry().center(), timestamp++); + kwinApp()->platform()->touchUp(2, timestamp++); + QVERIFY(sequenceEndedSpy.wait()); + + // Destroy the client. + shellSurface.reset(); + QVERIFY(Test::waitForWindowDestroyed(client)); +} + } WAYLANDTEST_MAIN(KWin::TouchInputTest)