KWin
Loading...
Searching...
No Matches
maximize_test.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "kwin_wayland_test.h"
10
11#include "core/output.h"
14#include "pointer_input.h"
15#include "wayland_server.h"
16#include "window.h"
17#include "workspace.h"
18
19#include <KWayland/Client/compositor.h>
20#include <KWayland/Client/shm_pool.h>
21#include <KWayland/Client/surface.h>
22
23#include <KDecoration2/DecoratedClient>
24#include <KDecoration2/Decoration>
25#include <KDecoration2/DecorationSettings>
26
27#include <QSignalSpy>
28
29using namespace KWin;
30
31static const QString s_socketName = QStringLiteral("wayland_test_kwin_maximized-0");
32
33class TestMaximized : public QObject
34{
35 Q_OBJECT
36private Q_SLOTS:
37 void initTestCase();
38 void init();
39 void cleanup();
40
41 void testMaximizedPassedToDeco();
42 void testInitiallyMaximizedBorderless();
43 void testBorderlessMaximizedWindow();
44 void testMaximizedGainFocusAndBeActivated();
45};
46
47void TestMaximized::initTestCase()
48{
49 qRegisterMetaType<KWin::Window *>();
50 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
51 QVERIFY(waylandServer()->init(s_socketName));
53 QRect(0, 0, 1280, 1024),
54 QRect(1280, 0, 1280, 1024),
55 });
56
57 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
58
59 kwinApp()->start();
60 QVERIFY(applicationStartedSpy.wait());
61 const auto outputs = workspace()->outputs();
62 QCOMPARE(outputs.count(), 2);
63 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
64 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
65}
66
67void TestMaximized::init()
68{
69 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::XdgDecorationV1));
70
71 workspace()->setActiveOutput(QPoint(640, 512));
72 KWin::input()->pointer()->warp(QPoint(640, 512));
73}
74
75void TestMaximized::cleanup()
76{
78
79 // adjust config
80 auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
81 group.writeEntry("BorderlessMaximizedWindows", false);
82 group.sync();
84 QCOMPARE(options->borderlessMaximizedWindows(), false);
85}
86
87void TestMaximized::testMaximizedPassedToDeco()
88{
89 // this test verifies that when a XdgShellClient gets maximized the Decoration receives the signal
90
91 // Create the test window.
92 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
93 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
94 std::unique_ptr<Test::XdgToplevelDecorationV1> xdgDecoration(Test::createXdgToplevelDecorationV1(shellSurface.get()));
95
96 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
97 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
98 surface->commit(KWayland::Client::Surface::CommitFlag::None);
99 QVERIFY(surfaceConfigureRequestedSpy.wait());
100
101 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
102 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
103 QVERIFY(window);
104 QVERIFY(window->isDecorated());
105
106 auto decoration = window->decoration();
107 QVERIFY(decoration);
108 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
109
110 // Wait for configure event that signals the window is active now.
111 QVERIFY(surfaceConfigureRequestedSpy.wait());
112 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
113
114 // When there are no borders, there is no change to them when maximizing.
115 // TODO: we should test both cases with fixed fake decoration for autotests.
116 const bool hasBorders = Workspace::self()->decorationBridge()->settings()->borderSize() != KDecoration2::BorderSize::None;
117
118 // now maximize
119 QSignalSpy bordersChangedSpy(decoration, &KDecoration2::Decoration::bordersChanged);
120 QSignalSpy maximizedChangedSpy(decoration->client(), &KDecoration2::DecoratedClient::maximizedChanged);
121 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
122
124 QVERIFY(surfaceConfigureRequestedSpy.wait());
125 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
126 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024 - decoration->borderTop()));
127 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
128 Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
129 QVERIFY(frameGeometryChangedSpy.wait());
130
131 // If no borders, there is only the initial geometry shape change, but none through border resizing.
132 QCOMPARE(frameGeometryChangedSpy.count(), hasBorders ? 2 : 1);
133 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull);
134 QCOMPARE(maximizedChangedSpy.count(), 1);
135 QCOMPARE(maximizedChangedSpy.last().first().toBool(), true);
136 QCOMPARE(bordersChangedSpy.count(), hasBorders ? 1 : 0);
137 QCOMPARE(decoration->borderLeft(), 0);
138 QCOMPARE(decoration->borderBottom(), 0);
139 QCOMPARE(decoration->borderRight(), 0);
140 QVERIFY(decoration->borderTop() != 0);
141
142 // now unmaximize again
144 QVERIFY(surfaceConfigureRequestedSpy.wait());
145 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
146 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
147
148 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
149 Test::render(surface.get(), QSize(100, 50), Qt::red);
150 QVERIFY(frameGeometryChangedSpy.wait());
151 QCOMPARE(frameGeometryChangedSpy.count(), hasBorders ? 4 : 2);
152 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
153 QCOMPARE(maximizedChangedSpy.count(), 2);
154 QCOMPARE(maximizedChangedSpy.last().first().toBool(), false);
155 QCOMPARE(bordersChangedSpy.count(), hasBorders ? 2 : 0);
156 QVERIFY(decoration->borderTop() != 0);
157 QVERIFY(decoration->borderLeft() != !hasBorders);
158 QVERIFY(decoration->borderRight() != !hasBorders);
159 QVERIFY(decoration->borderBottom() != !hasBorders);
160
161 // Destroy the test window.
162 shellSurface.reset();
163 QVERIFY(Test::waitForWindowClosed(window));
164}
165
166void TestMaximized::testInitiallyMaximizedBorderless()
167{
168 // This test verifies that a window created as maximized, will be maximized and without Border with BorderlessMaximizedWindows
169
170 // adjust config
171 auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
172 group.writeEntry("BorderlessMaximizedWindows", true);
173 group.sync();
175 QCOMPARE(options->borderlessMaximizedWindows(), true);
176
177 // Create the test window.
178 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
179 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
180 std::unique_ptr<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.get()));
181
182 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
183 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
184 shellSurface->set_maximized();
185 QSignalSpy decorationConfigureRequestedSpy(decoration.get(), &Test::XdgToplevelDecorationV1::configureRequested);
186 decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
187 surface->commit(KWayland::Client::Surface::CommitFlag::None);
188
189 // Wait for the initial configure event.
190 Test::XdgToplevel::States states;
191 QVERIFY(surfaceConfigureRequestedSpy.wait());
192 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
193 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
194 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
195 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
196 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
197
198 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
199 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(1280, 1024), Qt::blue);
200 QVERIFY(window);
201 QVERIFY(!window->isDecorated());
202 QVERIFY(window->isActive());
203 QVERIFY(window->isMaximizable());
204 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull);
205 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
206 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
207 QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(),
208 Test::XdgToplevelDecorationV1::mode_server_side);
209
210 // Destroy the window.
211 shellSurface.reset();
212 surface.reset();
213 QVERIFY(Test::waitForWindowClosed(window));
214}
215void TestMaximized::testBorderlessMaximizedWindow()
216{
217 // This test verifies that a maximized window looses it's server-side
218 // decoration when the borderless maximized option is on.
219
220 // Enable the borderless maximized windows option.
221 auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
222 group.writeEntry("BorderlessMaximizedWindows", true);
223 group.sync();
225 QCOMPARE(options->borderlessMaximizedWindows(), true);
226
227 // Create the test window.
228 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
229 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly));
230 std::unique_ptr<Test::XdgToplevelDecorationV1> decoration(Test::createXdgToplevelDecorationV1(shellSurface.get()));
231
232 QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
233 QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
234 QSignalSpy decorationConfigureRequestedSpy(decoration.get(), &Test::XdgToplevelDecorationV1::configureRequested);
235 decoration->set_mode(Test::XdgToplevelDecorationV1::mode_server_side);
236 surface->commit(KWayland::Client::Surface::CommitFlag::None);
237
238 // Wait for the initial configure event.
239 Test::XdgToplevel::States states;
240 QVERIFY(surfaceConfigureRequestedSpy.wait());
241 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
242 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(0, 0));
243 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
244 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Activated));
245 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
246
247 // Map the window.
248 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
249 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
250 QVERIFY(window);
251 QVERIFY(window->isActive());
252 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
253 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
254 QCOMPARE(window->isDecorated(), true);
255
256 // We should receive a configure event when the window becomes active.
257 QVERIFY(surfaceConfigureRequestedSpy.wait());
258 QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
259 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
260 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
261 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
262
263 // Maximize the window.
264 const QRectF maximizeRestoreGeometry = window->frameGeometry();
266 QVERIFY(surfaceConfigureRequestedSpy.wait());
267 QCOMPARE(surfaceConfigureRequestedSpy.count(), 3);
268 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(1280, 1024));
269 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
270 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
271 QVERIFY(states.testFlag(Test::XdgToplevel::State::Maximized));
272
273 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged);
274 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
275 Test::render(surface.get(), QSize(1280, 1024), Qt::blue);
276 QVERIFY(frameGeometryChangedSpy.wait());
277 QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
278 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeFull);
279 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeFull);
280 QCOMPARE(window->isDecorated(), false);
281
282 // Restore the window.
284 QVERIFY(surfaceConfigureRequestedSpy.wait());
285 QCOMPARE(surfaceConfigureRequestedSpy.count(), 4);
286 QCOMPARE(toplevelConfigureRequestedSpy.last().at(0).toSize(), QSize(100, 50));
287 states = toplevelConfigureRequestedSpy.last().at(1).value<Test::XdgToplevel::States>();
288 QVERIFY(states.testFlag(Test::XdgToplevel::State::Activated));
289 QVERIFY(!states.testFlag(Test::XdgToplevel::State::Maximized));
290
291 shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
292 Test::render(surface.get(), QSize(100, 50), Qt::red);
293 QVERIFY(frameGeometryChangedSpy.wait());
294 QCOMPARE(window->frameGeometry(), maximizeRestoreGeometry);
295 QCOMPARE(window->maximizeMode(), MaximizeMode::MaximizeRestore);
296 QCOMPARE(window->requestedMaximizeMode(), MaximizeMode::MaximizeRestore);
297 QCOMPARE(window->isDecorated(), true);
298
299 // Destroy the window.
300 shellSurface.reset();
301 QVERIFY(Test::waitForWindowClosed(window));
302}
303
304void TestMaximized::testMaximizedGainFocusAndBeActivated()
305{
306 // This test verifies that a window will be raised and gain focus when it's maximized
307 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
308 std::unique_ptr<Test::XdgToplevel> xdgShellSurface(Test::createXdgToplevelSurface(surface.get()));
309 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
310 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
311 std::unique_ptr<Test::XdgToplevel> xdgShellSurface2(Test::createXdgToplevelSurface(surface2.get()));
312 auto window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
313
314 QVERIFY(!window->isActive());
315 QVERIFY(window2->isActive());
316 QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window, window2}));
317
319
320 QVERIFY(window->isActive());
321 QVERIFY(!window2->isActive());
322 QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window2, window}));
323
324 xdgShellSurface.reset();
325 QVERIFY(Test::waitForWindowClosed(window));
326 xdgShellSurface2.reset();
327 QVERIFY(Test::waitForWindowClosed(window2));
328}
329
331#include "maximize_test.moc"
std::unique_ptr< KDecoration2::DecorationSettingsPrivate > settings(KDecoration2::DecorationSettings *parent) override
PointerInputRedirection * pointer() const
Definition input.h:220
bool borderlessMaximizedWindows
Definition options.h:172
void warp(const QPointF &pos)
void configureRequested(quint32 serial)
void configureRequested(QtWayland::zxdg_toplevel_decoration_v1::mode mode)
void configureRequested(const QSize &size, KWin::Test::XdgToplevel::States states)
void performWindowOperation(KWin::Window *window, Options::WindowOperation op)
Decoration::DecorationBridge * decorationBridge() const
static Workspace * self()
Definition workspace.h:91
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
void slotReconfigure()
#define WAYLANDTEST_MAIN(TestObject)
Window * renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32, int timeout=5000)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
QList< KWayland::Client::Output * > outputs
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
XdgToplevelDecorationV1 * createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent=nullptr)
bool waitForWindowClosed(Window *window)
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
Options * options
Definition main.cpp:73
InputRedirection * input()
Definition input.h:549