diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -28,8 +28,15 @@ #include #include +#include +#include +#include +#include + #include +using namespace KWayland::Client; + namespace KWin { @@ -41,6 +48,7 @@ private Q_SLOTS: void initTestCase(); void init(); + void cleanup(); void testEnterLeave(); void testPointerPressRelease(); void testPointerAxis(); @@ -173,6 +181,13 @@ void InternalWindowTest::init() { Cursor::setPos(QPoint(1280, 512)); + QVERIFY(Test::setupWaylandConnection(s_socketName, Test::AdditionalWaylandInterface::Seat)); + QVERIFY(Test::waitForWaylandKeyboard()); +} + +void InternalWindowTest::cleanup() +{ + Test::destroyWaylandConnection(); } void InternalWindowTest::testEnterLeave() @@ -285,6 +300,9 @@ QVERIFY(releaseSpy.isValid()); QVERIFY(clientAddedSpy.wait()); QCOMPARE(clientAddedSpy.count(), 1); + auto internalClient = clientAddedSpy.first().first().value(); + QVERIFY(internalClient); + QVERIFY(internalClient->isInternal()); quint32 timestamp = 1; QFETCH(QPoint, cursorPos); @@ -296,6 +314,51 @@ kwinApp()->platform()->keyboardKeyReleased(KEY_A, timestamp++); QTRY_COMPARE(releaseSpy.count(), 1); QCOMPARE(pressSpy.count(), 1); + + // let's hide the window again and create a "real" window + win.hide(); + clientAddedSpy.clear(); + + QScopedPointer keyboard(Test::waylandSeat()->createKeyboard()); + QVERIFY(!keyboard.isNull()); + QVERIFY(keyboard->isValid()); + QSignalSpy enteredSpy(keyboard.data(), &Keyboard::entered); + QVERIFY(enteredSpy.isValid()); + QSignalSpy leftSpy(keyboard.data(), &Keyboard::left); + QVERIFY(leftSpy.isValid()); + QScopedPointer surface(Test::createSurface()); + QScopedPointer shellSurface(Test::createShellSurface(Test::ShellSurfaceType::WlShell, surface.data())); + + // now let's render + auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue); + QVERIFY(c); + QVERIFY(c->isActive()); + + if (enteredSpy.isEmpty()) { + QVERIFY(enteredSpy.wait()); + } + QCOMPARE(enteredSpy.count(), 1); + + QSignalSpy windowShownSpy(internalClient, &ShellClient::windowShown); + QVERIFY(windowShownSpy.isValid()); + win.show(); + QCOMPARE(windowShownSpy.count(), 1); + QVERIFY(leftSpy.isEmpty()); + QVERIFY(!leftSpy.wait(100)); + + // now let's trigger a key, which should result in a leave + kwinApp()->platform()->keyboardKeyPressed(KEY_A, timestamp++); + QVERIFY(leftSpy.wait()); + QCOMPARE(pressSpy.count(), 2); + + kwinApp()->platform()->keyboardKeyReleased(KEY_A, timestamp++); + QTRY_COMPARE(releaseSpy.count(), 2); + + // after hiding the internal window, next key press should trigger an enter + win.hide(); + kwinApp()->platform()->keyboardKeyPressed(KEY_A, timestamp++); + QVERIFY(enteredSpy.wait()); + kwinApp()->platform()->keyboardKeyReleased(KEY_A, timestamp++); } void InternalWindowTest::testTouch() diff --git a/autotests/integration/kwin_wayland_test.h b/autotests/integration/kwin_wayland_test.h --- a/autotests/integration/kwin_wayland_test.h +++ b/autotests/integration/kwin_wayland_test.h @@ -109,6 +109,7 @@ bool waitForWaylandPointer(); bool waitForWaylandTouch(); +bool waitForWaylandKeyboard(); void flushWaylandConnection(); diff --git a/autotests/integration/test_helpers.cpp b/autotests/integration/test_helpers.cpp --- a/autotests/integration/test_helpers.cpp +++ b/autotests/integration/test_helpers.cpp @@ -247,6 +247,18 @@ return hasTouchSpy.wait(); } +bool waitForWaylandKeyboard() +{ + if (!s_waylandConnection.seat) { + return false; + } + QSignalSpy hasKeyboardSpy(s_waylandConnection.seat, &Seat::hasKeyboardChanged); + if (!hasKeyboardSpy.isValid()) { + return false; + } + return hasKeyboardSpy.wait(); +} + void render(Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format) { QImage img(size, format); diff --git a/input.cpp b/input.cpp --- a/input.cpp +++ b/input.cpp @@ -340,6 +340,7 @@ if (!effects || !static_cast< EffectsHandlerImpl* >(effects)->hasKeyboardGrab()) { return false; } + waylandServer()->seat()->setFocusedKeyboardSurface(nullptr); static_cast< EffectsHandlerImpl* >(effects)->grabbedKeyboardEvent(event); return true; } @@ -487,7 +488,11 @@ return false; } event->setAccepted(false); - return QCoreApplication::sendEvent(found, event); + if (QCoreApplication::sendEvent(found, event)) { + waylandServer()->seat()->setFocusedKeyboardSurface(nullptr); + return true; + } + return false; } bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { @@ -718,6 +723,7 @@ if (!TabBox::TabBox::self() || !TabBox::TabBox::self()->isGrabbed()) { return false; } + waylandServer()->seat()->setFocusedKeyboardSurface(nullptr); if (event->type() == QEvent::KeyPress) TabBox::TabBox::self()->keyPress(event->modifiers() | event->key()); return true;