20#include <xcb/xcb_icccm.h>
25static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_window_rules-0");
34 void testApplyInitialMaximizeVert();
35 void testWindowClassChange();
38void WindowRuleTest::initTestCase()
40 qRegisterMetaType<KWin::Window *>();
44 QRect(0, 0, 1280, 1024),
45 QRect(1280, 0, 1280, 1024),
49 QVERIFY(applicationStartedSpy.wait());
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);
57void WindowRuleTest::init()
64void WindowRuleTest::cleanup()
74 xcb_disconnect(pointer);
78void WindowRuleTest::testApplyInitialMaximizeVert()
83 workspace()->
rulebook()->
setConfig(KSharedConfig::openConfig(QFINDTESTDATA(
"./data/rules/maximize-vert-apply-initial"), KConfig::SimpleConfig));
88 QVERIFY(!xcb_connection_has_error(c.get()));
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(),
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");
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());
110 NETWinInfo info(c.get(), windowId,
rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
111 info.setWindowType(NET::Normal);
112 xcb_map_window(c.get(), windowId);
116 QVERIFY(windowCreatedSpy.wait());
117 X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
119 QVERIFY(window->isDecorated());
120 QVERIFY(!window->hasStrut());
121 QVERIFY(!window->readyForPainting());
122 QMetaObject::invokeMethod(window,
"setReadyForPainting");
123 QVERIFY(window->readyForPainting());
129 xcb_unmap_window(c.get(), windowId);
130 xcb_destroy_window(c.get(), windowId);
132 QVERIFY(windowClosedSpy.wait());
135void WindowRuleTest::testWindowClassChange()
137 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
138 config->group(QStringLiteral(
"General")).writeEntry(
"count", 1);
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);
153 QVERIFY(!xcb_connection_has_error(c.get()));
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(),
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");
172 NETWinInfo info(c.get(), windowId,
rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
173 info.setWindowType(NET::Normal);
174 xcb_map_window(c.get(), windowId);
178 QVERIFY(windowCreatedSpy.wait());
179 X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
181 QVERIFY(window->isDecorated());
182 QVERIFY(!window->hasStrut());
183 QVERIFY(!window->readyForPainting());
184 QMetaObject::invokeMethod(window,
"setReadyForPainting");
185 QVERIFY(window->readyForPainting());
187 QCOMPARE(window->keepAbove(),
false);
191 xcb_icccm_set_wm_class(c.get(), windowId, 23,
"org.kde.foo\0org.kde.foo");
193 QVERIFY(windowClassChangedSpy.wait());
194 QCOMPARE(window->keepAbove(),
true);
198 xcb_unmap_window(c.get(), windowId);
199 xcb_destroy_window(c.get(), windowId);
201 QVERIFY(windowClosedSpy.wait());
207#include "window_rules_test.moc"
void setConfig(const KSharedConfig::Ptr &config)
void windowClassChanged()
void windowAdded(KWin::Window *)
RuleBook * rulebook() const
QList< Output * > outputs() const
void setActiveOutput(Output *output)
#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()
@ MaximizeVertical
The window is maximized vertically.
WaylandServer * waylandServer()
InputRedirection * input()
KWIN_EXPORT Atoms * atoms
void operator()(xcb_connection_t *pointer)