2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2013-01-14 08:20:59 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
|
2013-01-14 08:20:59 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2013-01-14 08:20:59 +00:00
|
|
|
#include "testutils.h"
|
|
|
|
// KWin
|
2022-01-13 13:54:03 +00:00
|
|
|
#include "utils/xcbutils.h"
|
2013-01-14 08:20:59 +00:00
|
|
|
// Qt
|
|
|
|
#include <QApplication>
|
2018-06-05 10:52:57 +00:00
|
|
|
#include <QtTest>
|
2022-03-09 16:25:44 +00:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
|
|
#include <private/qtx11extras_p.h>
|
|
|
|
#else
|
2016-11-11 08:59:46 +00:00
|
|
|
#include <QX11Info>
|
2022-03-09 16:25:44 +00:00
|
|
|
#endif
|
2014-04-15 08:09:25 +00:00
|
|
|
#include <netwm.h>
|
2013-01-14 08:20:59 +00:00
|
|
|
// xcb
|
|
|
|
#include <xcb/xcb.h>
|
|
|
|
|
|
|
|
using namespace KWin;
|
|
|
|
using namespace KWin::Xcb;
|
|
|
|
|
|
|
|
class TestXcbWrapper : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2013-07-22 14:07:39 +00:00
|
|
|
private Q_SLOTS:
|
2015-02-18 07:31:53 +00:00
|
|
|
void initTestCase();
|
2013-01-14 08:20:59 +00:00
|
|
|
void init();
|
|
|
|
void cleanup();
|
|
|
|
void defaultCtor();
|
|
|
|
void normalCtor();
|
|
|
|
void copyCtorEmpty();
|
|
|
|
void copyCtorBeforeRetrieve();
|
|
|
|
void copyCtorAfterRetrieve();
|
|
|
|
void assignementEmpty();
|
|
|
|
void assignmentBeforeRetrieve();
|
|
|
|
void assignmentAfterRetrieve();
|
|
|
|
void discard();
|
2014-04-14 08:31:37 +00:00
|
|
|
void testQueryTree();
|
2014-04-14 08:50:56 +00:00
|
|
|
void testCurrentInput();
|
2014-04-14 09:12:01 +00:00
|
|
|
void testTransientFor();
|
2014-04-15 08:09:25 +00:00
|
|
|
void testPropertyByteArray();
|
|
|
|
void testPropertyBool();
|
2014-09-24 19:04:15 +00:00
|
|
|
void testAtom();
|
2015-02-02 13:56:21 +00:00
|
|
|
void testMotifEmpty();
|
|
|
|
void testMotif_data();
|
|
|
|
void testMotif();
|
2022-03-23 10:13:38 +00:00
|
|
|
|
2013-01-14 08:20:59 +00:00
|
|
|
private:
|
|
|
|
void testEmpty(WindowGeometry &geometry);
|
|
|
|
void testGeometry(WindowGeometry &geometry, const QRect &rect);
|
2014-09-24 19:04:15 +00:00
|
|
|
Window m_testWindow;
|
2013-01-14 08:20:59 +00:00
|
|
|
};
|
|
|
|
|
2015-02-18 07:31:53 +00:00
|
|
|
void TestXcbWrapper::initTestCase()
|
|
|
|
{
|
|
|
|
qApp->setProperty("x11RootWindow", QVariant::fromValue<quint32>(QX11Info::appRootWindow()));
|
2022-03-23 10:13:38 +00:00
|
|
|
qApp->setProperty("x11Connection", QVariant::fromValue<void *>(QX11Info::connection()));
|
2015-02-18 07:31:53 +00:00
|
|
|
}
|
|
|
|
|
2013-01-14 08:20:59 +00:00
|
|
|
void TestXcbWrapper::init()
|
|
|
|
{
|
2022-03-23 10:13:38 +00:00
|
|
|
const uint32_t values[] = {true};
|
2014-09-24 19:04:15 +00:00
|
|
|
m_testWindow.create(QRect(0, 0, 10, 10), XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, values);
|
|
|
|
QVERIFY(m_testWindow.isValid());
|
2013-01-14 08:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::cleanup()
|
|
|
|
{
|
2014-09-24 19:04:15 +00:00
|
|
|
m_testWindow.reset();
|
2013-01-14 08:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::testEmpty(WindowGeometry &geometry)
|
|
|
|
{
|
|
|
|
QCOMPARE(geometry.window(), noneWindow());
|
|
|
|
QVERIFY(!geometry.data());
|
|
|
|
QCOMPARE(geometry.isNull(), true);
|
|
|
|
QCOMPARE(geometry.rect(), QRect());
|
|
|
|
QVERIFY(!geometry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::testGeometry(WindowGeometry &geometry, const QRect &rect)
|
|
|
|
{
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(geometry.window(), (xcb_window_t)m_testWindow);
|
2013-01-14 08:20:59 +00:00
|
|
|
// now lets retrieve some data
|
|
|
|
QCOMPARE(geometry.rect(), rect);
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
QCOMPARE(geometry.isNull(), false);
|
|
|
|
QVERIFY(geometry);
|
|
|
|
QVERIFY(geometry.data());
|
|
|
|
QCOMPARE(geometry.data()->x, int16_t(rect.x()));
|
|
|
|
QCOMPARE(geometry.data()->y, int16_t(rect.y()));
|
|
|
|
QCOMPARE(geometry.data()->width, uint16_t(rect.width()));
|
|
|
|
QCOMPARE(geometry.data()->height, uint16_t(rect.height()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::defaultCtor()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry;
|
|
|
|
testEmpty(geometry);
|
|
|
|
QVERIFY(!geometry.isRetrieved());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::normalCtor()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry(m_testWindow);
|
|
|
|
QVERIFY(!geometry.isRetrieved());
|
|
|
|
testGeometry(geometry, QRect(0, 0, 10, 10));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::copyCtorEmpty()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry;
|
|
|
|
WindowGeometry other(geometry);
|
|
|
|
testEmpty(geometry);
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
testEmpty(other);
|
|
|
|
QVERIFY(!other.isRetrieved());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::copyCtorBeforeRetrieve()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry(m_testWindow);
|
|
|
|
QVERIFY(!geometry.isRetrieved());
|
|
|
|
WindowGeometry other(geometry);
|
|
|
|
testEmpty(geometry);
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
|
|
|
|
QVERIFY(!other.isRetrieved());
|
|
|
|
testGeometry(other, QRect(0, 0, 10, 10));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::copyCtorAfterRetrieve()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry(m_testWindow);
|
|
|
|
QVERIFY(geometry);
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
QCOMPARE(geometry.rect(), QRect(0, 0, 10, 10));
|
|
|
|
WindowGeometry other(geometry);
|
|
|
|
testEmpty(geometry);
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
|
|
|
|
QVERIFY(other.isRetrieved());
|
|
|
|
testGeometry(other, QRect(0, 0, 10, 10));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::assignementEmpty()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry;
|
|
|
|
WindowGeometry other;
|
|
|
|
testEmpty(geometry);
|
|
|
|
testEmpty(other);
|
|
|
|
|
|
|
|
other = geometry;
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
testEmpty(geometry);
|
|
|
|
testEmpty(other);
|
|
|
|
QVERIFY(!other.isRetrieved());
|
2022-01-21 11:47:06 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
QT_WARNING_PUSH
|
|
|
|
QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
|
2014-09-24 19:04:15 +00:00
|
|
|
// test assignment to self
|
|
|
|
geometry = geometry;
|
|
|
|
other = other;
|
|
|
|
testEmpty(geometry);
|
|
|
|
testEmpty(other);
|
2022-03-23 10:13:38 +00:00
|
|
|
QT_WARNING_POP
|
2013-01-14 08:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::assignmentBeforeRetrieve()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry(m_testWindow);
|
|
|
|
WindowGeometry other = geometry;
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
testEmpty(geometry);
|
|
|
|
|
|
|
|
QVERIFY(!other.isRetrieved());
|
|
|
|
testGeometry(other, QRect(0, 0, 10, 10));
|
|
|
|
|
|
|
|
other = WindowGeometry(m_testWindow);
|
|
|
|
QVERIFY(!other.isRetrieved());
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(other.window(), (xcb_window_t)m_testWindow);
|
2013-01-14 08:20:59 +00:00
|
|
|
other = WindowGeometry();
|
|
|
|
testEmpty(geometry);
|
2022-01-21 11:47:06 +00:00
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
QT_WARNING_PUSH
|
|
|
|
QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
|
2014-09-24 19:04:15 +00:00
|
|
|
// test assignment to self
|
|
|
|
geometry = geometry;
|
|
|
|
other = other;
|
|
|
|
testEmpty(geometry);
|
2022-03-23 10:13:38 +00:00
|
|
|
QT_WARNING_POP
|
2013-01-14 08:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::assignmentAfterRetrieve()
|
|
|
|
{
|
|
|
|
WindowGeometry geometry(m_testWindow);
|
|
|
|
QVERIFY(geometry);
|
|
|
|
QVERIFY(geometry.isRetrieved());
|
|
|
|
WindowGeometry other = geometry;
|
|
|
|
testEmpty(geometry);
|
|
|
|
|
|
|
|
QVERIFY(other.isRetrieved());
|
|
|
|
testGeometry(other, QRect(0, 0, 10, 10));
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
QT_WARNING_PUSH
|
|
|
|
QT_WARNING_DISABLE_CLANG("-Wself-assign-overloaded")
|
2014-09-24 19:04:15 +00:00
|
|
|
// test assignment to self
|
|
|
|
geometry = geometry;
|
|
|
|
other = other;
|
|
|
|
testEmpty(geometry);
|
|
|
|
testGeometry(other, QRect(0, 0, 10, 10));
|
2022-03-23 10:13:38 +00:00
|
|
|
QT_WARNING_POP
|
2014-09-24 19:04:15 +00:00
|
|
|
|
|
|
|
// set to empty again
|
2013-01-14 08:20:59 +00:00
|
|
|
other = WindowGeometry();
|
|
|
|
testEmpty(other);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::discard()
|
|
|
|
{
|
|
|
|
// discard of reply cannot be tested properly as we cannot check whether the reply has been discarded
|
|
|
|
// therefore it's more or less just a test to ensure that it doesn't crash and the code paths
|
|
|
|
// are taken.
|
|
|
|
WindowGeometry *geometry = new WindowGeometry();
|
|
|
|
delete geometry;
|
|
|
|
|
|
|
|
geometry = new WindowGeometry(m_testWindow);
|
|
|
|
delete geometry;
|
|
|
|
|
|
|
|
geometry = new WindowGeometry(m_testWindow);
|
|
|
|
QVERIFY(geometry->data());
|
|
|
|
delete geometry;
|
|
|
|
}
|
|
|
|
|
2014-04-14 08:31:37 +00:00
|
|
|
void TestXcbWrapper::testQueryTree()
|
|
|
|
{
|
|
|
|
Tree tree(m_testWindow);
|
|
|
|
// should have root as parent
|
|
|
|
QCOMPARE(tree.parent(), static_cast<xcb_window_t>(QX11Info::appRootWindow()));
|
|
|
|
// shouldn't have any children
|
|
|
|
QCOMPARE(tree->children_len, uint16_t(0));
|
|
|
|
QVERIFY(!tree.children());
|
|
|
|
|
|
|
|
// query for root
|
|
|
|
Tree root(QX11Info::appRootWindow());
|
|
|
|
// shouldn't have a parent
|
|
|
|
QCOMPARE(root.parent(), xcb_window_t(XCB_WINDOW_NONE));
|
|
|
|
QVERIFY(root->children_len > 0);
|
|
|
|
xcb_window_t *children = root.children();
|
|
|
|
bool found = false;
|
|
|
|
for (int i = 0; i < xcb_query_tree_children_length(root.data()); ++i) {
|
|
|
|
if (children[i] == tree.window()) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
QVERIFY(found);
|
|
|
|
|
|
|
|
// query for not existing window
|
|
|
|
Tree doesntExist(XCB_WINDOW_NONE);
|
|
|
|
QCOMPARE(doesntExist.parent(), xcb_window_t(XCB_WINDOW_NONE));
|
|
|
|
QVERIFY(doesntExist.isNull());
|
|
|
|
QVERIFY(doesntExist.isRetrieved());
|
|
|
|
}
|
|
|
|
|
2014-04-14 08:50:56 +00:00
|
|
|
void TestXcbWrapper::testCurrentInput()
|
|
|
|
{
|
|
|
|
xcb_connection_t *c = QX11Info::connection();
|
2014-09-24 19:04:15 +00:00
|
|
|
m_testWindow.map();
|
2014-04-14 08:50:56 +00:00
|
|
|
QX11Info::setAppTime(QX11Info::getTimestamp());
|
|
|
|
|
|
|
|
// let's set the input focus
|
2014-09-24 19:04:15 +00:00
|
|
|
m_testWindow.focus(XCB_INPUT_FOCUS_PARENT, QX11Info::appTime());
|
2014-04-14 08:50:56 +00:00
|
|
|
xcb_flush(c);
|
|
|
|
|
|
|
|
CurrentInput input;
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(input.window(), (xcb_window_t)m_testWindow);
|
2014-04-14 08:50:56 +00:00
|
|
|
|
|
|
|
// creating a copy should make the input object have no window any more
|
|
|
|
CurrentInput input2(input);
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(input2.window(), (xcb_window_t)m_testWindow);
|
2014-04-14 08:50:56 +00:00
|
|
|
QCOMPARE(input.window(), xcb_window_t(XCB_WINDOW_NONE));
|
|
|
|
}
|
|
|
|
|
2014-04-14 09:12:01 +00:00
|
|
|
void TestXcbWrapper::testTransientFor()
|
|
|
|
{
|
|
|
|
TransientFor transient(m_testWindow);
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(transient.window(), (xcb_window_t)m_testWindow);
|
2014-04-14 09:12:01 +00:00
|
|
|
// our m_testWindow doesn't have a transient for hint
|
|
|
|
xcb_window_t compareWindow = XCB_WINDOW_NONE;
|
|
|
|
QVERIFY(!transient.getTransientFor(&compareWindow));
|
|
|
|
QCOMPARE(compareWindow, xcb_window_t(XCB_WINDOW_NONE));
|
2014-04-15 08:09:25 +00:00
|
|
|
bool ok = true;
|
|
|
|
QCOMPARE(transient.value<xcb_window_t>(32, XCB_ATOM_WINDOW, XCB_WINDOW_NONE, &ok), xcb_window_t(XCB_WINDOW_NONE));
|
|
|
|
QVERIFY(!ok);
|
|
|
|
ok = true;
|
|
|
|
QCOMPARE(transient.value<xcb_window_t>(XCB_WINDOW_NONE, &ok), xcb_window_t(XCB_WINDOW_NONE));
|
|
|
|
QVERIFY(!ok);
|
2014-04-14 09:12:01 +00:00
|
|
|
|
|
|
|
// Create a Window with a transient for hint
|
|
|
|
Window transientWindow(createWindow());
|
2015-08-23 09:51:35 +00:00
|
|
|
xcb_window_t testWindowId = m_testWindow;
|
|
|
|
transientWindow.changeProperty(XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, 1, &testWindowId);
|
2014-04-14 09:12:01 +00:00
|
|
|
|
|
|
|
// let's get another transient object
|
|
|
|
TransientFor realTransient(transientWindow);
|
|
|
|
QVERIFY(realTransient.getTransientFor(&compareWindow));
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(compareWindow, (xcb_window_t)m_testWindow);
|
2014-04-15 08:09:25 +00:00
|
|
|
ok = false;
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(realTransient.value<xcb_window_t>(32, XCB_ATOM_WINDOW, XCB_WINDOW_NONE, &ok), (xcb_window_t)m_testWindow);
|
2014-04-15 08:09:25 +00:00
|
|
|
QVERIFY(ok);
|
|
|
|
ok = false;
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(realTransient.value<xcb_window_t>(XCB_WINDOW_NONE, &ok), (xcb_window_t)m_testWindow);
|
2014-04-15 08:09:25 +00:00
|
|
|
QVERIFY(ok);
|
|
|
|
ok = false;
|
2014-09-24 19:04:15 +00:00
|
|
|
QCOMPARE(realTransient.value<xcb_window_t>(), (xcb_window_t)m_testWindow);
|
2022-03-23 10:13:38 +00:00
|
|
|
QCOMPARE(realTransient.value<xcb_window_t *>(nullptr, &ok)[0], (xcb_window_t)m_testWindow);
|
2014-04-15 08:09:25 +00:00
|
|
|
QVERIFY(ok);
|
2022-03-23 10:13:38 +00:00
|
|
|
QCOMPARE(realTransient.value<xcb_window_t *>()[0], (xcb_window_t)m_testWindow);
|
2014-04-14 09:12:01 +00:00
|
|
|
|
|
|
|
// test for a not existing window
|
|
|
|
TransientFor doesntExist(XCB_WINDOW_NONE);
|
|
|
|
QVERIFY(!doesntExist.getTransientFor(&compareWindow));
|
|
|
|
}
|
|
|
|
|
2014-04-15 08:09:25 +00:00
|
|
|
void TestXcbWrapper::testPropertyByteArray()
|
|
|
|
{
|
|
|
|
Window testWindow(createWindow());
|
|
|
|
Property prop(false, testWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 100000);
|
|
|
|
QCOMPARE(prop.toByteArray(), QByteArray());
|
|
|
|
bool ok = true;
|
|
|
|
QCOMPARE(prop.toByteArray(&ok), QByteArray());
|
|
|
|
QVERIFY(!ok);
|
|
|
|
ok = true;
|
2022-03-23 10:13:38 +00:00
|
|
|
QVERIFY(!prop.value<const char *>());
|
|
|
|
QCOMPARE(prop.value<const char *>("bar", &ok), "bar");
|
2014-04-15 08:09:25 +00:00
|
|
|
QVERIFY(!ok);
|
|
|
|
QCOMPARE(QByteArray(StringProperty(testWindow, XCB_ATOM_WM_NAME)), QByteArray());
|
|
|
|
|
|
|
|
testWindow.changeProperty(XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 3, "foo");
|
|
|
|
prop = Property(false, testWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 100000);
|
|
|
|
QCOMPARE(prop.toByteArray(), QByteArrayLiteral("foo"));
|
|
|
|
QCOMPARE(prop.toByteArray(&ok), QByteArrayLiteral("foo"));
|
|
|
|
QVERIFY(ok);
|
2022-03-23 10:13:38 +00:00
|
|
|
QCOMPARE(prop.value<const char *>(nullptr, &ok), "foo");
|
2014-04-15 08:09:25 +00:00
|
|
|
QVERIFY(ok);
|
|
|
|
QCOMPARE(QByteArray(StringProperty(testWindow, XCB_ATOM_WM_NAME)), QByteArrayLiteral("foo"));
|
|
|
|
|
|
|
|
// verify incorrect format and type
|
|
|
|
QCOMPARE(prop.toByteArray(32), QByteArray());
|
|
|
|
QCOMPARE(prop.toByteArray(8, XCB_ATOM_CARDINAL), QByteArray());
|
|
|
|
|
|
|
|
// verify empty property
|
|
|
|
testWindow.changeProperty(XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, 0, nullptr);
|
|
|
|
prop = Property(false, testWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 100000);
|
|
|
|
QCOMPARE(prop.toByteArray(), QByteArray());
|
|
|
|
QCOMPARE(prop.toByteArray(&ok), QByteArray());
|
2022-03-23 10:13:38 +00:00
|
|
|
// valid bytearray
|
2014-06-11 09:08:02 +00:00
|
|
|
QVERIFY(ok);
|
2022-03-23 10:13:38 +00:00
|
|
|
// The bytearray should be empty
|
2014-06-11 09:08:02 +00:00
|
|
|
QVERIFY(prop.toByteArray().isEmpty());
|
2022-03-23 10:13:38 +00:00
|
|
|
// The bytearray should be not null
|
2014-06-11 09:08:02 +00:00
|
|
|
QVERIFY(!prop.toByteArray().isNull());
|
2022-03-23 10:13:38 +00:00
|
|
|
QVERIFY(!prop.value<const char *>());
|
2014-06-11 09:08:02 +00:00
|
|
|
QCOMPARE(QByteArray(StringProperty(testWindow, XCB_ATOM_WM_NAME)), QByteArray());
|
|
|
|
|
|
|
|
// verify non existing property
|
|
|
|
Xcb::Atom invalid(QByteArrayLiteral("INVALID_ATOM"));
|
|
|
|
prop = Property(false, testWindow, invalid, XCB_ATOM_STRING, 0, 100000);
|
|
|
|
QCOMPARE(prop.toByteArray(), QByteArray());
|
|
|
|
QCOMPARE(prop.toByteArray(&ok), QByteArray());
|
2022-03-23 10:13:38 +00:00
|
|
|
// invalid bytearray
|
2014-04-15 08:09:25 +00:00
|
|
|
QVERIFY(!ok);
|
2022-03-23 10:13:38 +00:00
|
|
|
// The bytearray should be empty
|
2014-06-11 09:08:02 +00:00
|
|
|
QVERIFY(prop.toByteArray().isEmpty());
|
2022-03-23 10:13:38 +00:00
|
|
|
// The bytearray should be not null
|
2014-06-11 09:08:02 +00:00
|
|
|
QVERIFY(prop.toByteArray().isNull());
|
2022-03-23 10:13:38 +00:00
|
|
|
QVERIFY(!prop.value<const char *>());
|
2014-04-15 08:09:25 +00:00
|
|
|
QCOMPARE(QByteArray(StringProperty(testWindow, XCB_ATOM_WM_NAME)), QByteArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::testPropertyBool()
|
|
|
|
{
|
|
|
|
Window testWindow(createWindow());
|
|
|
|
Atom blockCompositing(QByteArrayLiteral("_KDE_NET_WM_BLOCK_COMPOSITING"));
|
|
|
|
QVERIFY(blockCompositing != XCB_ATOM_NONE);
|
|
|
|
NETWinInfo info(QX11Info::connection(), testWindow, QX11Info::appRootWindow(), NET::Properties(), NET::WM2BlockCompositing);
|
|
|
|
|
|
|
|
Property prop(false, testWindow, blockCompositing, XCB_ATOM_CARDINAL, 0, 100000);
|
|
|
|
bool ok = true;
|
|
|
|
QVERIFY(!prop.toBool());
|
|
|
|
QVERIFY(!prop.toBool(&ok));
|
|
|
|
QVERIFY(!ok);
|
|
|
|
|
|
|
|
info.setBlockingCompositing(true);
|
|
|
|
xcb_flush(QX11Info::connection());
|
|
|
|
prop = Property(false, testWindow, blockCompositing, XCB_ATOM_CARDINAL, 0, 100000);
|
|
|
|
QVERIFY(prop.toBool());
|
|
|
|
QVERIFY(prop.toBool(&ok));
|
|
|
|
QVERIFY(ok);
|
|
|
|
|
|
|
|
// incorrect type and format
|
|
|
|
QVERIFY(!prop.toBool(8));
|
|
|
|
QVERIFY(!prop.toBool(32, blockCompositing));
|
|
|
|
QVERIFY(!prop.toBool(32, blockCompositing, &ok));
|
|
|
|
QVERIFY(!ok);
|
|
|
|
|
|
|
|
// incorrect value:
|
|
|
|
uint32_t d[] = {1, 0};
|
|
|
|
testWindow.changeProperty(blockCompositing, XCB_ATOM_CARDINAL, 32, 2, d);
|
|
|
|
prop = Property(false, testWindow, blockCompositing, XCB_ATOM_CARDINAL, 0, 100000);
|
|
|
|
QVERIFY(!prop.toBool());
|
|
|
|
ok = true;
|
|
|
|
QVERIFY(!prop.toBool(&ok));
|
|
|
|
QVERIFY(!ok);
|
|
|
|
}
|
|
|
|
|
2014-09-24 19:04:15 +00:00
|
|
|
void TestXcbWrapper::testAtom()
|
|
|
|
{
|
|
|
|
Atom atom(QByteArrayLiteral("WM_CLIENT_MACHINE"));
|
|
|
|
QCOMPARE(atom.name(), QByteArrayLiteral("WM_CLIENT_MACHINE"));
|
|
|
|
QVERIFY(atom == XCB_ATOM_WM_CLIENT_MACHINE);
|
|
|
|
QVERIFY(atom.isValid());
|
|
|
|
|
|
|
|
// test the const paths
|
|
|
|
const Atom &atom2(atom);
|
|
|
|
QVERIFY(atom2.isValid());
|
|
|
|
QVERIFY(atom2 == XCB_ATOM_WM_CLIENT_MACHINE);
|
|
|
|
QCOMPARE(atom2.name(), QByteArrayLiteral("WM_CLIENT_MACHINE"));
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
// destroy before retrieved
|
2014-09-24 19:04:15 +00:00
|
|
|
Atom atom3(QByteArrayLiteral("WM_CLIENT_MACHINE"));
|
|
|
|
QCOMPARE(atom3.name(), QByteArrayLiteral("WM_CLIENT_MACHINE"));
|
|
|
|
}
|
|
|
|
|
2015-02-02 13:56:21 +00:00
|
|
|
void TestXcbWrapper::testMotifEmpty()
|
|
|
|
{
|
|
|
|
Atom atom(QByteArrayLiteral("_MOTIF_WM_HINTS"));
|
|
|
|
MotifHints hints(atom);
|
|
|
|
// pre init
|
|
|
|
QCOMPARE(hints.hasDecoration(), false);
|
|
|
|
QCOMPARE(hints.noBorder(), false);
|
|
|
|
QCOMPARE(hints.resize(), true);
|
|
|
|
QCOMPARE(hints.move(), true);
|
|
|
|
QCOMPARE(hints.minimize(), true);
|
|
|
|
QCOMPARE(hints.maximize(), true);
|
|
|
|
QCOMPARE(hints.close(), true);
|
|
|
|
// post init, pre read
|
|
|
|
hints.init(m_testWindow);
|
|
|
|
QCOMPARE(hints.hasDecoration(), false);
|
|
|
|
QCOMPARE(hints.noBorder(), false);
|
|
|
|
QCOMPARE(hints.resize(), true);
|
|
|
|
QCOMPARE(hints.move(), true);
|
|
|
|
QCOMPARE(hints.minimize(), true);
|
|
|
|
QCOMPARE(hints.maximize(), true);
|
|
|
|
QCOMPARE(hints.close(), true);
|
|
|
|
// post read
|
|
|
|
hints.read();
|
|
|
|
QCOMPARE(hints.hasDecoration(), false);
|
|
|
|
QCOMPARE(hints.noBorder(), false);
|
|
|
|
QCOMPARE(hints.resize(), true);
|
|
|
|
QCOMPARE(hints.move(), true);
|
|
|
|
QCOMPARE(hints.minimize(), true);
|
|
|
|
QCOMPARE(hints.maximize(), true);
|
|
|
|
QCOMPARE(hints.close(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::testMotif_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<quint32>("flags");
|
2018-08-29 18:02:16 +00:00
|
|
|
QTest::addColumn<quint32>("functions");
|
2015-02-02 13:56:21 +00:00
|
|
|
QTest::addColumn<quint32>("decorations");
|
|
|
|
|
|
|
|
QTest::addColumn<bool>("expectedHasDecoration");
|
|
|
|
QTest::addColumn<bool>("expectedNoBorder");
|
|
|
|
QTest::addColumn<bool>("expectedResize");
|
|
|
|
QTest::addColumn<bool>("expectedMove");
|
|
|
|
QTest::addColumn<bool>("expectedMinimize");
|
|
|
|
QTest::addColumn<bool>("expectedMaximize");
|
|
|
|
QTest::addColumn<bool>("expectedClose");
|
|
|
|
|
2022-03-23 10:13:38 +00:00
|
|
|
QTest::newRow("none") << 0u << 0u << 0u << false << false << true << true << true << true << true;
|
|
|
|
QTest::newRow("noborder") << 2u << 5u << 0u << true << true << true << true << true << true << true;
|
|
|
|
QTest::newRow("border") << 2u << 5u << 1u << true << false << true << true << true << true << true;
|
|
|
|
QTest::newRow("resize") << 1u << 2u << 1u << false << false << true << false << false << false << false;
|
|
|
|
QTest::newRow("move") << 1u << 4u << 1u << false << false << false << true << false << false << false;
|
|
|
|
QTest::newRow("minimize") << 1u << 8u << 1u << false << false << false << false << true << false << false;
|
|
|
|
QTest::newRow("maximize") << 1u << 16u << 1u << false << false << false << false << false << true << false;
|
|
|
|
QTest::newRow("close") << 1u << 32u << 1u << false << false << false << false << false << false << true;
|
|
|
|
|
|
|
|
QTest::newRow("resize/all") << 1u << 3u << 1u << false << false << false << true << true << true << true;
|
|
|
|
QTest::newRow("move/all") << 1u << 5u << 1u << false << false << true << false << true << true << true;
|
|
|
|
QTest::newRow("minimize/all") << 1u << 9u << 1u << false << false << true << true << false << true << true;
|
|
|
|
QTest::newRow("maximize/all") << 1u << 17u << 1u << false << false << true << true << true << false << true;
|
|
|
|
QTest::newRow("close/all") << 1u << 33u << 1u << false << false << true << true << true << true << false;
|
2015-02-02 13:56:21 +00:00
|
|
|
|
|
|
|
QTest::newRow("all") << 1u << 62u << 1u << false << false << true << true << true << true << true;
|
|
|
|
QTest::newRow("all/all") << 1u << 63u << 1u << false << false << false << false << false << false << false;
|
|
|
|
QTest::newRow("all/all/deco") << 3u << 63u << 1u << true << false << false << false << false << false << false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestXcbWrapper::testMotif()
|
|
|
|
{
|
|
|
|
Atom atom(QByteArrayLiteral("_MOTIF_WM_HINTS"));
|
|
|
|
QFETCH(quint32, flags);
|
2018-08-29 18:02:16 +00:00
|
|
|
QFETCH(quint32, functions);
|
2015-02-02 13:56:21 +00:00
|
|
|
QFETCH(quint32, decorations);
|
|
|
|
quint32 data[] = {
|
|
|
|
flags,
|
2018-08-29 18:02:16 +00:00
|
|
|
functions,
|
2015-02-02 13:56:21 +00:00
|
|
|
decorations,
|
|
|
|
0,
|
2022-03-23 10:13:38 +00:00
|
|
|
0};
|
2015-02-02 13:56:21 +00:00
|
|
|
xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, m_testWindow, atom, atom, 32, 5, data);
|
|
|
|
xcb_flush(QX11Info::connection());
|
|
|
|
MotifHints hints(atom);
|
|
|
|
hints.init(m_testWindow);
|
|
|
|
hints.read();
|
|
|
|
QTEST(hints.hasDecoration(), "expectedHasDecoration");
|
|
|
|
QTEST(hints.noBorder(), "expectedNoBorder");
|
|
|
|
QTEST(hints.resize(), "expectedResize");
|
|
|
|
QTEST(hints.move(), "expectedMove");
|
|
|
|
QTEST(hints.minimize(), "expectedMinimize");
|
|
|
|
QTEST(hints.maximize(), "expectedMaximize");
|
|
|
|
QTEST(hints.close(), "expectedClose");
|
|
|
|
}
|
|
|
|
|
2016-09-08 13:08:45 +00:00
|
|
|
Q_CONSTRUCTOR_FUNCTION(forceXcb)
|
2016-09-08 13:15:41 +00:00
|
|
|
QTEST_MAIN(TestXcbWrapper)
|
2013-01-14 08:20:59 +00:00
|
|
|
#include "test_xcb_wrapper.moc"
|