KWin
Loading...
Searching...
No Matches
dont_crash_aurorae_destroy_deco.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"
12#include "pointer_input.h"
13#include "wayland_server.h"
14#include "workspace.h"
15#include "x11window.h"
16
17#include <KDecoration2/Decoration>
18
19#include <QQuickItem>
20
21#include <linux/input.h>
22
23namespace KWin
24{
25
26static const QString s_socketName = QStringLiteral("wayland_test_kwin_dont_crash_aurorae_destroy_deco-0");
27
28class DontCrashAuroraeDestroyDecoTest : public QObject
29{
30 Q_OBJECT
31private Q_SLOTS:
32 void initTestCase();
33 void init();
34 void testBorderlessMaximizedWindows();
35};
36
37void DontCrashAuroraeDestroyDecoTest::initTestCase()
38{
40 QSKIP("no render node available");
41 return;
42 }
43 qputenv("XDG_DATA_DIRS", QCoreApplication::applicationDirPath().toUtf8());
44 qRegisterMetaType<KWin::Window *>();
45 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
46 QVERIFY(waylandServer()->init(s_socketName));
48 QRect(0, 0, 1280, 1024),
49 QRect(1280, 0, 1280, 1024),
50 });
51
52 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
53 config->group(QStringLiteral("org.kde.kdecoration2")).writeEntry("library", "org.kde.kwin.aurorae");
54 config->sync();
55 kwinApp()->setConfig(config);
56
57 // this test needs to enforce OpenGL compositing to get into the crashy condition
58 qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
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 setenv("QT_QPA_PLATFORM", "wayland", true);
66}
67
68void DontCrashAuroraeDestroyDecoTest::init()
69{
70 workspace()->setActiveOutput(QPoint(640, 512));
71 input()->pointer()->warp(QPoint(640, 512));
72}
73
74void DontCrashAuroraeDestroyDecoTest::testBorderlessMaximizedWindows()
75{
76 // this test verifies that Aurorae doesn't crash when clicking the maximize button
77 // with kwin config option BorderlessMaximizedWindows
78 // see BUG 362772
79
80 // first adjust the config
81 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
82 group.writeEntry("BorderlessMaximizedWindows", true);
83 group.sync();
85 QCOMPARE(options->borderlessMaximizedWindows(), true);
86
87 // create an xcb window
89 auto c = connection.get();
90 QVERIFY(!xcb_connection_has_error(c));
91
92 xcb_window_t windowId = xcb_generate_id(c);
93 xcb_create_window(c, XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0, 0, 100, 200, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
94 xcb_map_window(c, windowId);
95 xcb_flush(c);
96
97 // we should get a window for it
98 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
99 QVERIFY(windowCreatedSpy.wait());
100 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
101 QVERIFY(window);
102 QCOMPARE(window->window(), windowId);
103 QVERIFY(window->isDecorated());
104 QCOMPARE(window->maximizeMode(), MaximizeRestore);
105 QCOMPARE(window->noBorder(), false);
106 // verify that the deco is Aurorae
107 QCOMPARE(qstrcmp(window->decoration()->metaObject()->className(), "Aurorae::Decoration"), 0);
108 // find the maximize button
109 QQuickItem *item = window->decoration()->property("item").value<QQuickItem *>()->findChild<QQuickItem *>("maximizeButton");
110 QVERIFY(item);
111 const QPointF scenePoint = item->mapToScene(QPoint(0, 0));
112
113 // mark the window as ready for painting, otherwise it doesn't get input events
114 QMetaObject::invokeMethod(window, "setReadyForPainting");
115 QVERIFY(window->readyForPainting());
116
117 // simulate click on maximize button
118 QSignalSpy maximizedStateChangedSpy(window, &Window::maximizedChanged);
119 quint32 timestamp = 1;
120 Test::pointerMotion(window->frameGeometry().topLeft() + scenePoint.toPoint(), timestamp++);
121 Test::pointerButtonPressed(BTN_LEFT, timestamp++);
122 Test::pointerButtonReleased(BTN_LEFT, timestamp++);
123 QVERIFY(maximizedStateChangedSpy.wait());
124 QCOMPARE(window->maximizeMode(), MaximizeFull);
125 QCOMPARE(window->noBorder(), true);
126
127 // and destroy the window again
128 xcb_unmap_window(c, windowId);
129 xcb_destroy_window(c, windowId);
130 xcb_flush(c);
131
132 QSignalSpy windowClosedSpy(window, &X11Window::closed);
133 QVERIFY(windowClosedSpy.wait());
134}
135
136}
137
139#include "dont_crash_aurorae_destroy_deco.moc"
PointerInputRedirection * pointer() const
Definition input.h:220
bool borderlessMaximizedWindows
Definition options.h:172
void warp(const QPointF &pos)
void maximizedChanged()
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
void slotReconfigure()
#define WAYLANDTEST_MAIN(TestObject)
void setOutputConfig(const QList< QRect > &geometries)
void pointerButtonPressed(quint32 button, quint32 time)
XcbConnectionPtr createX11Connection()
QList< KWayland::Client::Output * > outputs
void pointerMotion(const QPointF &position, quint32 time)
bool renderNodeAvailable()
void pointerButtonReleased(quint32 button, quint32 time)
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
KWIN_EXPORT xcb_window_t rootWindow()
Definition xcb.h:24
@ MaximizeRestore
The window is not maximized in any direction.
Definition common.h:75
@ MaximizeFull
Equal to MaximizeVertical | MaximizeHorizontal.
Definition common.h:79
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
KWIN_EXPORT xcb_connection_t * connection()
Definition xcb.h:19
Options * options
Definition main.cpp:73
InputRedirection * input()
Definition input.h:549