f71ee59a37
Use input device specific apis to change the position of the cursor. The main reason to do so is to break the assumption that Cursor position is the same as pointer position, which I would like to rely on later to merge tablet and pointer cursors.
218 lines
7.8 KiB
C++
218 lines
7.8 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
#include "kwin_wayland_test.h"
|
|
|
|
#include "atoms.h"
|
|
#include "core/output.h"
|
|
#include "core/outputbackend.h"
|
|
#include "deleted.h"
|
|
#include "pointer_input.h"
|
|
#include "rules.h"
|
|
#include "wayland_server.h"
|
|
#include "workspace.h"
|
|
#include "x11window.h"
|
|
|
|
#include <netwm.h>
|
|
#include <xcb/xcb_icccm.h>
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_window_rules-0");
|
|
|
|
class WindowRuleTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
private Q_SLOTS:
|
|
void initTestCase();
|
|
void init();
|
|
void cleanup();
|
|
void testApplyInitialMaximizeVert_data();
|
|
void testApplyInitialMaximizeVert();
|
|
void testWindowClassChange();
|
|
};
|
|
|
|
void WindowRuleTest::initTestCase()
|
|
{
|
|
qRegisterMetaType<KWin::Window *>();
|
|
qRegisterMetaType<KWin::Deleted *>();
|
|
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
|
|
QVERIFY(waylandServer()->init(s_socketName));
|
|
QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024)));
|
|
|
|
kwinApp()->start();
|
|
QVERIFY(applicationStartedSpy.wait());
|
|
const auto outputs = workspace()->outputs();
|
|
QCOMPARE(outputs.count(), 2);
|
|
QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
|
|
QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
|
|
setenv("QT_QPA_PLATFORM", "wayland", true);
|
|
}
|
|
|
|
void WindowRuleTest::init()
|
|
{
|
|
workspace()->setActiveOutput(QPoint(640, 512));
|
|
input()->pointer()->warp(QPoint(640, 512));
|
|
QVERIFY(waylandServer()->windows().isEmpty());
|
|
}
|
|
|
|
void WindowRuleTest::cleanup()
|
|
{
|
|
// discards old rules
|
|
workspace()->rulebook()->load();
|
|
}
|
|
|
|
struct XcbConnectionDeleter
|
|
{
|
|
void operator()(xcb_connection_t *pointer)
|
|
{
|
|
xcb_disconnect(pointer);
|
|
}
|
|
};
|
|
|
|
void WindowRuleTest::testApplyInitialMaximizeVert_data()
|
|
{
|
|
QTest::addColumn<QByteArray>("role");
|
|
|
|
QTest::newRow("lowercase") << QByteArrayLiteral("mainwindow");
|
|
QTest::newRow("CamelCase") << QByteArrayLiteral("MainWindow");
|
|
}
|
|
|
|
void WindowRuleTest::testApplyInitialMaximizeVert()
|
|
{
|
|
// this test creates the situation of BUG 367554: creates a window and initial apply maximize vertical
|
|
// the window is matched by class and role
|
|
// load the rule
|
|
workspace()->rulebook()->setConfig(KSharedConfig::openConfig(QFINDTESTDATA("./data/rules/maximize-vert-apply-initial"), KConfig::SimpleConfig));
|
|
workspace()->slotReconfigure();
|
|
|
|
// create the test window
|
|
Test::XcbConnectionPtr c = Test::createX11Connection();
|
|
QVERIFY(!xcb_connection_has_error(c.get()));
|
|
|
|
xcb_window_t windowId = xcb_generate_id(c.get());
|
|
const QRect windowGeometry = QRect(0, 0, 10, 20);
|
|
const uint32_t values[] = {
|
|
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW};
|
|
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
|
|
windowGeometry.x(),
|
|
windowGeometry.y(),
|
|
windowGeometry.width(),
|
|
windowGeometry.height(),
|
|
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
|
|
xcb_size_hints_t hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
|
|
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
|
|
xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
|
|
xcb_icccm_set_wm_class(c.get(), windowId, 9, "kpat\0kpat");
|
|
|
|
QFETCH(QByteArray, role);
|
|
xcb_change_property(c.get(), XCB_PROP_MODE_REPLACE, windowId, atoms->wm_window_role, XCB_ATOM_STRING, 8, role.length(), role.constData());
|
|
|
|
NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
|
|
info.setWindowType(NET::Normal);
|
|
xcb_map_window(c.get(), windowId);
|
|
xcb_flush(c.get());
|
|
|
|
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
|
|
QVERIFY(windowCreatedSpy.wait());
|
|
X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
|
|
QVERIFY(window);
|
|
QVERIFY(window->isDecorated());
|
|
QVERIFY(!window->hasStrut());
|
|
QVERIFY(!window->isHiddenInternal());
|
|
QVERIFY(!window->readyForPainting());
|
|
QMetaObject::invokeMethod(window, "setReadyForPainting");
|
|
QVERIFY(window->readyForPainting());
|
|
QVERIFY(Test::waitForWaylandSurface(window));
|
|
QCOMPARE(window->maximizeMode(), MaximizeVertical);
|
|
|
|
// destroy window again
|
|
QSignalSpy windowClosedSpy(window, &X11Window::windowClosed);
|
|
xcb_unmap_window(c.get(), windowId);
|
|
xcb_destroy_window(c.get(), windowId);
|
|
xcb_flush(c.get());
|
|
QVERIFY(windowClosedSpy.wait());
|
|
}
|
|
|
|
void WindowRuleTest::testWindowClassChange()
|
|
{
|
|
KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
|
|
config->group("General").writeEntry("count", 1);
|
|
|
|
auto group = config->group("1");
|
|
group.writeEntry("above", true);
|
|
group.writeEntry("aboverule", 2);
|
|
group.writeEntry("wmclass", "org.kde.foo");
|
|
group.writeEntry("wmclasscomplete", false);
|
|
group.writeEntry("wmclassmatch", 1);
|
|
group.sync();
|
|
|
|
workspace()->rulebook()->setConfig(config);
|
|
workspace()->slotReconfigure();
|
|
|
|
// create the test window
|
|
Test::XcbConnectionPtr c = Test::createX11Connection();
|
|
QVERIFY(!xcb_connection_has_error(c.get()));
|
|
|
|
xcb_window_t windowId = xcb_generate_id(c.get());
|
|
const QRect windowGeometry = QRect(0, 0, 10, 20);
|
|
const uint32_t values[] = {
|
|
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW};
|
|
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(),
|
|
windowGeometry.x(),
|
|
windowGeometry.y(),
|
|
windowGeometry.width(),
|
|
windowGeometry.height(),
|
|
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);
|
|
xcb_size_hints_t hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y());
|
|
xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height());
|
|
xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints);
|
|
xcb_icccm_set_wm_class(c.get(), windowId, 23, "org.kde.bar\0org.kde.bar");
|
|
|
|
NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties);
|
|
info.setWindowType(NET::Normal);
|
|
xcb_map_window(c.get(), windowId);
|
|
xcb_flush(c.get());
|
|
|
|
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
|
|
QVERIFY(windowCreatedSpy.wait());
|
|
X11Window *window = windowCreatedSpy.last().first().value<X11Window *>();
|
|
QVERIFY(window);
|
|
QVERIFY(window->isDecorated());
|
|
QVERIFY(!window->hasStrut());
|
|
QVERIFY(!window->isHiddenInternal());
|
|
QVERIFY(!window->readyForPainting());
|
|
QMetaObject::invokeMethod(window, "setReadyForPainting");
|
|
QVERIFY(window->readyForPainting());
|
|
QVERIFY(Test::waitForWaylandSurface(window));
|
|
QCOMPARE(window->keepAbove(), false);
|
|
|
|
// now change class
|
|
QSignalSpy windowClassChangedSpy{window, &X11Window::windowClassChanged};
|
|
xcb_icccm_set_wm_class(c.get(), windowId, 23, "org.kde.foo\0org.kde.foo");
|
|
xcb_flush(c.get());
|
|
QVERIFY(windowClassChangedSpy.wait());
|
|
QCOMPARE(window->keepAbove(), true);
|
|
|
|
// destroy window
|
|
QSignalSpy windowClosedSpy(window, &X11Window::windowClosed);
|
|
xcb_unmap_window(c.get(), windowId);
|
|
xcb_destroy_window(c.get(), windowId);
|
|
xcb_flush(c.get());
|
|
QVERIFY(windowClosedSpy.wait());
|
|
}
|
|
|
|
}
|
|
|
|
WAYLANDTEST_MAIN(KWin::WindowRuleTest)
|
|
#include "window_rules_test.moc"
|