Changeset View
Changeset View
Standalone View
Standalone View
autotests/integration/transient_placement.cpp
Show All 29 Lines | |||||
30 | 30 | | |||
31 | #include <KWayland/Client/connection_thread.h> | 31 | #include <KWayland/Client/connection_thread.h> | ||
32 | #include <KWayland/Client/compositor.h> | 32 | #include <KWayland/Client/compositor.h> | ||
33 | #include <KWayland/Client/event_queue.h> | 33 | #include <KWayland/Client/event_queue.h> | ||
34 | #include <KWayland/Client/keyboard.h> | 34 | #include <KWayland/Client/keyboard.h> | ||
35 | #include <KWayland/Client/registry.h> | 35 | #include <KWayland/Client/registry.h> | ||
36 | #include <KWayland/Client/plasmashell.h> | 36 | #include <KWayland/Client/plasmashell.h> | ||
37 | #include <KWayland/Client/pointer.h> | 37 | #include <KWayland/Client/pointer.h> | ||
38 | #include <KWayland/Client/shell.h> | | |||
39 | #include <KWayland/Client/seat.h> | 38 | #include <KWayland/Client/seat.h> | ||
40 | #include <KWayland/Client/server_decoration.h> | 39 | #include <KWayland/Client/server_decoration.h> | ||
41 | #include <KWayland/Client/shm_pool.h> | 40 | #include <KWayland/Client/shm_pool.h> | ||
42 | #include <KWayland/Client/surface.h> | 41 | #include <KWayland/Client/surface.h> | ||
43 | #include <KWayland/Client/touch.h> | 42 | #include <KWayland/Client/touch.h> | ||
44 | #include <KWayland/Client/xdgshell.h> | 43 | #include <KWayland/Client/xdgshell.h> | ||
45 | #include <KWayland/Server/seat_interface.h> | 44 | #include <KWayland/Server/seat_interface.h> | ||
46 | #include <KWayland/Server/surface_interface.h> | 45 | #include <KWayland/Server/surface_interface.h> | ||
47 | 46 | | |||
48 | | ||||
49 | namespace KWin | 47 | namespace KWin | ||
50 | { | 48 | { | ||
51 | 49 | | |||
52 | static const QString s_socketName = QStringLiteral("wayland_test_kwin_transient_placement-0"); | 50 | static const QString s_socketName = QStringLiteral("wayland_test_kwin_transient_placement-0"); | ||
53 | 51 | | |||
54 | class TransientPlacementTest : public QObject | 52 | class TransientPlacementTest : public QObject | ||
55 | { | 53 | { | ||
56 | Q_OBJECT | 54 | Q_OBJECT | ||
57 | private Q_SLOTS: | 55 | private Q_SLOTS: | ||
58 | void initTestCase(); | 56 | void initTestCase(); | ||
59 | void init(); | 57 | void init(); | ||
60 | void cleanup(); | 58 | void cleanup(); | ||
61 | void testSimplePosition_data(); | | |||
62 | void testSimplePosition(); | | |||
63 | void testDecorationPosition_data(); | | |||
64 | void testDecorationPosition(); | | |||
65 | void testXdgPopup_data(); | 59 | void testXdgPopup_data(); | ||
66 | void testXdgPopup(); | 60 | void testXdgPopup(); | ||
67 | void testXdgPopupWithPanel(); | 61 | void testXdgPopupWithPanel(); | ||
68 | | ||||
69 | private: | | |||
70 | AbstractClient *showWlShellWindow(const QSize &size, bool decorated = false, KWayland::Client::Surface *parent = nullptr, const QPoint &offset = QPoint()); | | |||
71 | | ||||
72 | KWayland::Client::Surface *surfaceForClient(AbstractClient *c) const; | | |||
73 | }; | 62 | }; | ||
74 | 63 | | |||
75 | void TransientPlacementTest::initTestCase() | 64 | void TransientPlacementTest::initTestCase() | ||
76 | { | 65 | { | ||
77 | qRegisterMetaType<KWin::ShellClient*>(); | 66 | qRegisterMetaType<KWin::ShellClient*>(); | ||
78 | qRegisterMetaType<KWin::AbstractClient*>(); | 67 | qRegisterMetaType<KWin::AbstractClient*>(); | ||
79 | QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); | 68 | QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); | ||
80 | QVERIFY(workspaceCreatedSpy.isValid()); | 69 | QVERIFY(workspaceCreatedSpy.isValid()); | ||
Show All 18 Lines | 84 | { | |||
99 | Cursor::setPos(QPoint(640, 512)); | 88 | Cursor::setPos(QPoint(640, 512)); | ||
100 | } | 89 | } | ||
101 | 90 | | |||
102 | void TransientPlacementTest::cleanup() | 91 | void TransientPlacementTest::cleanup() | ||
103 | { | 92 | { | ||
104 | Test::destroyWaylandConnection(); | 93 | Test::destroyWaylandConnection(); | ||
105 | } | 94 | } | ||
106 | 95 | | |||
107 | AbstractClient *TransientPlacementTest::showWlShellWindow(const QSize &size, bool decorated, KWayland::Client::Surface *parent, const QPoint &offset) | | |||
108 | { | | |||
109 | using namespace KWayland::Client; | | |||
110 | #define VERIFY(statement) \ | | |||
111 | if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\ | | |||
112 | return nullptr; | | |||
113 | #define COMPARE(actual, expected) \ | | |||
114 | if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ | | |||
115 | return nullptr; | | |||
116 | | ||||
117 | Surface *surface = Test::createSurface(Test::waylandCompositor()); | | |||
118 | VERIFY(surface); | | |||
119 | ShellSurface *shellSurface = Test::createShellSurface(surface, surface); | | |||
120 | VERIFY(shellSurface); | | |||
121 | if (parent) { | | |||
122 | shellSurface->setTransient(parent, offset); | | |||
123 | } | | |||
124 | if (decorated) { | | |||
125 | auto deco = Test::waylandServerSideDecoration()->create(surface, surface); | | |||
126 | QSignalSpy decoSpy(deco, &ServerSideDecoration::modeChanged); | | |||
127 | VERIFY(decoSpy.isValid()); | | |||
128 | VERIFY(decoSpy.wait()); | | |||
129 | deco->requestMode(ServerSideDecoration::Mode::Server); | | |||
130 | VERIFY(decoSpy.wait()); | | |||
131 | COMPARE(deco->mode(), ServerSideDecoration::Mode::Server); | | |||
132 | } | | |||
133 | // let's render | | |||
134 | auto c = Test::renderAndWaitForShown(surface, size, Qt::blue); | | |||
135 | | ||||
136 | VERIFY(c); | | |||
137 | COMPARE(workspace()->activeClient(), c); | | |||
138 | | ||||
139 | #undef VERIFY | | |||
140 | #undef COMPARE | | |||
141 | | ||||
142 | return c; | | |||
143 | } | | |||
144 | | ||||
145 | KWayland::Client::Surface *TransientPlacementTest::surfaceForClient(AbstractClient *c) const | | |||
146 | { | | |||
147 | const auto &surfaces = KWayland::Client::Surface::all(); | | |||
148 | auto it = std::find_if(surfaces.begin(), surfaces.end(), [c] (KWayland::Client::Surface *s) { return s->id() == c->surface()->id(); }); | | |||
149 | if (it != surfaces.end()) { | | |||
150 | return *it; | | |||
151 | } | | |||
152 | return nullptr; | | |||
153 | } | | |||
154 | | ||||
155 | void TransientPlacementTest::testSimplePosition_data() | | |||
156 | { | | |||
157 | QTest::addColumn<QSize>("parentSize"); | | |||
158 | QTest::addColumn<QPoint>("parentPosition"); | | |||
159 | QTest::addColumn<QSize>("transientSize"); | | |||
160 | QTest::addColumn<QPoint>("transientOffset"); | | |||
161 | QTest::addColumn<QRect>("expectedGeometry"); | | |||
162 | | ||||
163 | QTest::newRow("0/0") << QSize(640, 512) << QPoint(0, 0) << QSize(10, 100) << QPoint(0, 0) << QRect(0, 0, 10, 100); | | |||
164 | QTest::newRow("bottomRight") << QSize(640, 512) << QPoint(0, 0) << QSize(10, 100) << QPoint(639, 511) << QRect(639, 511, 10, 100); | | |||
165 | QTest::newRow("offset") << QSize(640, 512) << QPoint(200, 300) << QSize(100, 10) << QPoint(320, 256) << QRect(520, 556, 100, 10); | | |||
166 | QTest::newRow("right border") << QSize(1280, 1024) << QPoint(0, 0) << QSize(10, 100) << QPoint(1279, 50) << QRect(1270, 50, 10, 100); | | |||
167 | QTest::newRow("bottom border") << QSize(1280, 1024) << QPoint(0, 0) << QSize(10, 100) << QPoint(512, 1020) << QRect(512, 924, 10, 100); | | |||
168 | QTest::newRow("bottom right") << QSize(1280, 1024) << QPoint(0, 0) << QSize(10, 100) << QPoint(1279, 1020) << QRect(1270, 924, 10, 100); | | |||
169 | QTest::newRow("top border") << QSize(1280, 1024) << QPoint(0, -100) << QSize(10, 100) << QPoint(512, 50) << QRect(512, 0, 10, 100); | | |||
170 | QTest::newRow("left border") << QSize(1280, 1024) << QPoint(-100, 0) << QSize(100, 10) << QPoint(50, 512) << QRect(0, 512, 100, 10); | | |||
171 | QTest::newRow("top left") << QSize(1280, 1024) << QPoint(-100, -100) << QSize(100, 100) << QPoint(50, 50) << QRect(0, 0, 100, 100); | | |||
172 | QTest::newRow("bottom left") << QSize(1280, 1024) << QPoint(-100, 0) << QSize(100, 100) << QPoint(50, 1000) << QRect(0, 924, 100, 100); | | |||
173 | } | | |||
174 | | ||||
175 | void TransientPlacementTest::testSimplePosition() | | |||
176 | { | | |||
177 | // this test verifies that the position of a transient window is taken from the passed position | | |||
178 | // there are no further constraints like window too large to fit screen, cascading transients, etc | | |||
179 | // some test cases also verify that the transient fits on the screen | | |||
180 | QFETCH(QSize, parentSize); | | |||
181 | AbstractClient *parent = showWlShellWindow(parentSize); | | |||
182 | QVERIFY(parent->clientPos().isNull()); | | |||
183 | QVERIFY(!parent->isDecorated()); | | |||
184 | QFETCH(QPoint, parentPosition); | | |||
185 | parent->move(parentPosition); | | |||
186 | QFETCH(QSize, transientSize); | | |||
187 | QFETCH(QPoint, transientOffset); | | |||
188 | AbstractClient *transient = showWlShellWindow(transientSize, false, surfaceForClient(parent), transientOffset); | | |||
189 | QVERIFY(transient); | | |||
190 | QVERIFY(!transient->isDecorated()); | | |||
191 | QVERIFY(transient->hasTransientPlacementHint()); | | |||
192 | QTEST(transient->geometry(), "expectedGeometry"); | | |||
193 | } | | |||
194 | | ||||
195 | void TransientPlacementTest::testDecorationPosition_data() | | |||
196 | { | | |||
197 | QTest::addColumn<QSize>("parentSize"); | | |||
198 | QTest::addColumn<QPoint>("parentPosition"); | | |||
199 | QTest::addColumn<QSize>("transientSize"); | | |||
200 | QTest::addColumn<QPoint>("transientOffset"); | | |||
201 | QTest::addColumn<QRect>("expectedGeometry"); | | |||
202 | | ||||
203 | QTest::newRow("0/0") << QSize(640, 512) << QPoint(0, 0) << QSize(10, 100) << QPoint(0, 0) << QRect(0, 0, 10, 100); | | |||
204 | QTest::newRow("bottomRight") << QSize(640, 512) << QPoint(0, 0) << QSize(10, 100) << QPoint(639, 511) << QRect(639, 511, 10, 100); | | |||
205 | QTest::newRow("offset") << QSize(640, 512) << QPoint(200, 300) << QSize(100, 10) << QPoint(320, 256) << QRect(520, 556, 100, 10); | | |||
206 | } | | |||
207 | | ||||
208 | void TransientPlacementTest::testDecorationPosition() | | |||
209 | { | | |||
210 | // this test verifies that a transient window is correctly placed if the parent window has a | | |||
211 | // server side decoration | | |||
212 | QFETCH(QSize, parentSize); | | |||
213 | AbstractClient *parent = showWlShellWindow(parentSize, true); | | |||
214 | QVERIFY(!parent->clientPos().isNull()); | | |||
215 | QVERIFY(parent->isDecorated()); | | |||
216 | QFETCH(QPoint, parentPosition); | | |||
217 | parent->move(parentPosition); | | |||
218 | QFETCH(QSize, transientSize); | | |||
219 | QFETCH(QPoint, transientOffset); | | |||
220 | AbstractClient *transient = showWlShellWindow(transientSize, false, surfaceForClient(parent), transientOffset); | | |||
221 | QVERIFY(transient); | | |||
222 | QVERIFY(!transient->isDecorated()); | | |||
223 | QVERIFY(transient->hasTransientPlacementHint()); | | |||
224 | QFETCH(QRect, expectedGeometry); | | |||
225 | expectedGeometry.translate(parent->clientPos()); | | |||
226 | QCOMPARE(transient->geometry(), expectedGeometry); | | |||
227 | } | | |||
228 | | ||||
229 | void TransientPlacementTest::testXdgPopup_data() | 96 | void TransientPlacementTest::testXdgPopup_data() | ||
230 | { | 97 | { | ||
231 | using namespace KWayland::Client; | 98 | using namespace KWayland::Client; | ||
232 | 99 | | |||
233 | QTest::addColumn<QSize>("parentSize"); | 100 | QTest::addColumn<QSize>("parentSize"); | ||
234 | QTest::addColumn<QPoint>("parentPosition"); | 101 | QTest::addColumn<QPoint>("parentPosition"); | ||
235 | QTest::addColumn<XdgPositioner>("positioner"); | 102 | QTest::addColumn<XdgPositioner>("positioner"); | ||
236 | QTest::addColumn<QRect>("expectedGeometry"); | 103 | QTest::addColumn<QRect>("expectedGeometry"); | ||
▲ Show 20 Lines • Show All 244 Lines • Show Last 20 Lines |