Warning, file /plasma/kwin/autotests/integration/input_stacking_order.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "kwin_wayland_test.h" 0010 0011 #include "core/output.h" 0012 #include "core/outputbackend.h" 0013 #include "cursor.h" 0014 #include "deleted.h" 0015 #include "wayland/seat_interface.h" 0016 #include "wayland_server.h" 0017 #include "window.h" 0018 #include "workspace.h" 0019 #include <kwineffects.h> 0020 0021 #include <KWayland/Client/compositor.h> 0022 #include <KWayland/Client/connection_thread.h> 0023 #include <KWayland/Client/event_queue.h> 0024 #include <KWayland/Client/pointer.h> 0025 #include <KWayland/Client/registry.h> 0026 #include <KWayland/Client/seat.h> 0027 #include <KWayland/Client/shm_pool.h> 0028 #include <KWayland/Client/surface.h> 0029 0030 namespace KWin 0031 { 0032 0033 static const QString s_socketName = QStringLiteral("wayland_test_kwin_input_stacking_order-0"); 0034 0035 class InputStackingOrderTest : public QObject 0036 { 0037 Q_OBJECT 0038 private Q_SLOTS: 0039 void initTestCase(); 0040 void init(); 0041 void cleanup(); 0042 void testPointerFocusUpdatesOnStackingOrderChange(); 0043 0044 private: 0045 void render(KWayland::Client::Surface *surface); 0046 }; 0047 0048 void InputStackingOrderTest::initTestCase() 0049 { 0050 qRegisterMetaType<KWin::Window *>(); 0051 qRegisterMetaType<KWin::Deleted *>(); 0052 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0053 QVERIFY(waylandServer()->init(s_socketName)); 0054 QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); 0055 0056 kwinApp()->start(); 0057 QVERIFY(applicationStartedSpy.wait()); 0058 const auto outputs = workspace()->outputs(); 0059 QCOMPARE(outputs.count(), 2); 0060 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0061 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0062 setenv("QT_QPA_PLATFORM", "wayland", true); 0063 } 0064 0065 void InputStackingOrderTest::init() 0066 { 0067 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat)); 0068 QVERIFY(Test::waitForWaylandPointer()); 0069 0070 workspace()->setActiveOutput(QPoint(640, 512)); 0071 Cursors::self()->mouse()->setPos(QPoint(640, 512)); 0072 } 0073 0074 void InputStackingOrderTest::cleanup() 0075 { 0076 Test::destroyWaylandConnection(); 0077 } 0078 0079 void InputStackingOrderTest::render(KWayland::Client::Surface *surface) 0080 { 0081 Test::render(surface, QSize(100, 50), Qt::blue); 0082 Test::flushWaylandConnection(); 0083 } 0084 0085 void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange() 0086 { 0087 // this test creates two windows which overlap 0088 // the pointer is in the overlapping area which means the top most window has focus 0089 // as soon as the top most window gets lowered the window should lose focus and the 0090 // other window should gain focus without a mouse event in between 0091 0092 // create pointer and signal spy for enter and leave signals 0093 auto pointer = Test::waylandSeat()->createPointer(Test::waylandSeat()); 0094 QVERIFY(pointer); 0095 QVERIFY(pointer->isValid()); 0096 QSignalSpy enteredSpy(pointer, &KWayland::Client::Pointer::entered); 0097 QSignalSpy leftSpy(pointer, &KWayland::Client::Pointer::left); 0098 0099 // now create the two windows and make them overlap 0100 QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded); 0101 std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface(); 0102 QVERIFY(surface1); 0103 Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get()); 0104 QVERIFY(shellSurface1); 0105 render(surface1.get()); 0106 QVERIFY(windowAddedSpy.wait()); 0107 Window *window1 = workspace()->activeWindow(); 0108 QVERIFY(window1); 0109 0110 std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface(); 0111 QVERIFY(surface2); 0112 Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get()); 0113 QVERIFY(shellSurface2); 0114 render(surface2.get()); 0115 QVERIFY(windowAddedSpy.wait()); 0116 0117 Window *window2 = workspace()->activeWindow(); 0118 QVERIFY(window2); 0119 QVERIFY(window1 != window2); 0120 0121 // now make windows overlap 0122 window2->move(window1->pos()); 0123 QCOMPARE(window1->frameGeometry(), window2->frameGeometry()); 0124 0125 // enter 0126 Test::pointerMotion(QPointF(25, 25), 1); 0127 QVERIFY(enteredSpy.wait()); 0128 QCOMPARE(enteredSpy.count(), 1); 0129 // window 2 should have focus 0130 QCOMPARE(pointer->enteredSurface(), surface2.get()); 0131 // also on the server 0132 QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window2->surface()); 0133 0134 // raise window 1 above window 2 0135 QVERIFY(leftSpy.isEmpty()); 0136 workspace()->raiseWindow(window1); 0137 // should send leave to window2 0138 QVERIFY(leftSpy.wait()); 0139 QCOMPARE(leftSpy.count(), 1); 0140 // and an enter to window1 0141 QCOMPARE(enteredSpy.count(), 2); 0142 QCOMPARE(pointer->enteredSurface(), surface1.get()); 0143 QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window1->surface()); 0144 0145 // let's destroy window1, that should pass focus to window2 again 0146 QSignalSpy windowClosedSpy(window1, &Window::windowClosed); 0147 surface1.reset(); 0148 QVERIFY(windowClosedSpy.wait()); 0149 QVERIFY(enteredSpy.wait()); 0150 QCOMPARE(enteredSpy.count(), 3); 0151 QCOMPARE(pointer->enteredSurface(), surface2.get()); 0152 QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window2->surface()); 0153 } 0154 0155 } 0156 0157 WAYLANDTEST_MAIN(KWin::InputStackingOrderTest) 0158 #include "input_stacking_order.moc"