KWin
Loading...
Searching...
No Matches
window_rules_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 "atoms.h"
12#include "core/output.h"
13#include "pointer_input.h"
14#include "rules.h"
15#include "wayland_server.h"
16#include "workspace.h"
17#include "x11window.h"
18
19#include <netwm.h>
20#include <xcb/xcb_icccm.h>
21
22namespace KWin
23{
24
25static const QString s_socketName = QStringLiteral("wayland_test_kwin_window_rules-0");
26
27class WindowRuleTest : public QObject
28{
29 Q_OBJECT
30private Q_SLOTS:
31 void initTestCase();
32 void init();
33 void cleanup();
34 void testApplyInitialMaximizeVert();
35 void testWindowClassChange();
36};
37
38void WindowRuleTest::initTestCase()
39{
40 qRegisterMetaType<KWin::Window *>();
41 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
42 QVERIFY(waylandServer()->init(s_socketName));
44 QRect(0, 0, 1280, 1024),
45 QRect(1280, 0, 1280, 1024),
46 });
47
48 kwinApp()->start();
49 QVERIFY(applicationStartedSpy.wait());
50 const auto outputs = workspace()->outputs();
51 QCOMPARE(outputs.count(), 2);
52 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
53 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
54 setenv("QT_QPA_PLATFORM", "wayland", true);
55}
56
57void WindowRuleTest::init()
58{
59 workspace()->setActiveOutput(QPoint(640, 512));
60 input()->pointer()->warp(QPoint(640, 512));
61 QVERIFY(waylandServer()->windows().isEmpty());
62}
63
64void WindowRuleTest::cleanup()
65{
66 // discards old rules
67 workspace()->rulebook()->load();
68}
69
71{
72 void operator()(xcb_connection_t *pointer)
73 {
74 xcb_disconnect(pointer);
75 }
76};
77
78void WindowRuleTest::testApplyInitialMaximizeVert()
79{
80 // this test creates the situation of BUG 367554: creates a window and initial apply maximize vertical
81 // the window is matched by class and role
82 // load the rule
83 workspace()->rulebook()->setConfig(KSharedConfig::openConfig(QFINDTESTDATA("./data/rules/maximize-vert-apply-initial"), KConfig::SimpleConfig));
85
86 // create the test window
88 QVERIFY(!xcb_connection_has_error(c.get()));
89
90 xcb_window_t windowId = xcb_generate_id(c.get());
91 const QRect windowGeometry = QRect(0, 0, 10, 20);
92 const uint32_t values[] = {
93 XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW};
94 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
95 windowGeometry.x(),
96 windowGeometry.y(),
97 windowGeometry.width(),
98 windowGeometry.height(),
99 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
100 xcb_size_hints_t hints;
101 memset(&hints, 0, sizeof(hints));
102 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
103 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
104 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
105 xcb_icccm_set_wm_class(c.get(), windowId, 9, "kpat\0kpat");
106
107 const QByteArray role = QByteArrayLiteral("mainwindow");
108 xcb_change_property(c.get(), XCB_PROP_MODE_REPLACE, windowId, atoms->wm_window_role, XCB_ATOM_STRING, 8, role.length(), role.constData());
109
110 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
111 info.setWindowType(NET::Normal);
112 xcb_map_window(c.get(), windowId);
113 xcb_flush(c.get());
114
115 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
116 QVERIFY(windowCreatedSpy.wait());
117 X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
118 QVERIFY(window);
119 QVERIFY(window->isDecorated());
120 QVERIFY(!window->hasStrut());
121 QVERIFY(!window->readyForPainting());
122 QMetaObject::invokeMethod(window, "setReadyForPainting");
123 QVERIFY(window->readyForPainting());
124 QVERIFY(Test::waitForWaylandSurface(window));
125 QCOMPARE(window->maximizeMode(), MaximizeVertical);
126
127 // destroy window again
128 QSignalSpy windowClosedSpy(window, &X11Window::closed);
129 xcb_unmap_window(c.get(), windowId);
130 xcb_destroy_window(c.get(), windowId);
131 xcb_flush(c.get());
132 QVERIFY(windowClosedSpy.wait());
133}
134
135void WindowRuleTest::testWindowClassChange()
136{
137 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
138 config->group(QStringLiteral("General")).writeEntry("count", 1);
139
140 auto group = config->group(QStringLiteral("1"));
141 group.writeEntry("above", true);
142 group.writeEntry("aboverule", 2);
143 group.writeEntry("wmclass", "org.kde.foo");
144 group.writeEntry("wmclasscomplete", false);
145 group.writeEntry("wmclassmatch", 1);
146 group.sync();
147
148 workspace()->rulebook()->setConfig(config);
150
151 // create the test window
153 QVERIFY(!xcb_connection_has_error(c.get()));
154
155 xcb_window_t windowId = xcb_generate_id(c.get());
156 const QRect windowGeometry = QRect(0, 0, 10, 20);
157 const uint32_t values[] = {
158 XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW};
159 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
160 windowGeometry.x(),
161 windowGeometry.y(),
162 windowGeometry.width(),
163 windowGeometry.height(),
164 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
165 xcb_size_hints_t hints;
166 memset(&hints, 0, sizeof(hints));
167 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
168 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
169 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
170 xcb_icccm_set_wm_class(c.get(), windowId, 23, "org.kde.bar\0org.kde.bar");
171
172 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
173 info.setWindowType(NET::Normal);
174 xcb_map_window(c.get(), windowId);
175 xcb_flush(c.get());
176
177 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
178 QVERIFY(windowCreatedSpy.wait());
179 X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
180 QVERIFY(window);
181 QVERIFY(window->isDecorated());
182 QVERIFY(!window->hasStrut());
183 QVERIFY(!window->readyForPainting());
184 QMetaObject::invokeMethod(window, "setReadyForPainting");
185 QVERIFY(window->readyForPainting());
186 QVERIFY(Test::waitForWaylandSurface(window));
187 QCOMPARE(window->keepAbove(), false);
188
189 // now change class
190 QSignalSpy windowClassChangedSpy{window, &X11Window::windowClassChanged};
191 xcb_icccm_set_wm_class(c.get(), windowId, 23, "org.kde.foo\0org.kde.foo");
192 xcb_flush(c.get());
193 QVERIFY(windowClassChangedSpy.wait());
194 QCOMPARE(window->keepAbove(), true);
195
196 // destroy window
197 QSignalSpy windowClosedSpy(window, &X11Window::closed);
198 xcb_unmap_window(c.get(), windowId);
199 xcb_destroy_window(c.get(), windowId);
200 xcb_flush(c.get());
201 QVERIFY(windowClosedSpy.wait());
202}
203
204}
205
207#include "window_rules_test.moc"
Xcb::Atom wm_window_role
Definition atoms.h:31
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
void load()
Definition rules.cpp:911
void setConfig(const KSharedConfig::Ptr &config)
Definition rules.h:313
void windowClassChanged()
void windowAdded(KWin::Window *)
RuleBook * rulebook() const
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
void slotReconfigure()
#define WAYLANDTEST_MAIN(TestObject)
void setOutputConfig(const QList< QRect > &geometries)
bool waitForWaylandSurface(Window *window)
XcbConnectionPtr createX11Connection()
std::unique_ptr< xcb_connection_t, XcbConnectionDeleter > XcbConnectionPtr
KWIN_EXPORT xcb_window_t rootWindow()
Definition xcb.h:24
@ MaximizeVertical
The window is maximized vertically.
Definition common.h:76
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549
KWIN_EXPORT Atoms * atoms
Definition main.cpp:74
void operator()(xcb_connection_t *pointer)