Light-weight wrapper class for an xcb_window_t
The idea behind this class is to relieve the developer from having to call xcb_destroy_window once it is no longer needed. That is having a RAII approach to windows. In addition the class provides some simple method wrappers for the most common use cases inside KWin: * map * unmap * setGeometry - basically a moveResizeWindow * ...
This commit is contained in:
parent
e68f7f960b
commit
f238cbc3f5
4 changed files with 407 additions and 20 deletions
|
@ -66,3 +66,19 @@ target_link_libraries( testXcbWrapper
|
|||
${XCB_XCB_LIBRARIES}
|
||||
${X11_XCB_LIBRARIES}
|
||||
)
|
||||
|
||||
########################################################
|
||||
# Test XcbWindow
|
||||
########################################################
|
||||
set( testXcbWindow_SRCS
|
||||
test_xcb_window.cpp
|
||||
)
|
||||
kde4_add_unit_test( testXcbWindow TESTNAME kwin-TestXcbWindow ${testXcbWindow_SRCS} )
|
||||
|
||||
target_link_libraries( testXcbWindow
|
||||
${QT_QTTEST_LIBRARY}
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
${XCB_XCB_LIBRARIES}
|
||||
${X11_XCB_LIBRARIES}
|
||||
)
|
||||
|
|
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// KWin
|
||||
#include "../client_machine.h"
|
||||
#include "../utils.h"
|
||||
#include "../xcbutils.h"
|
||||
// Qt
|
||||
#include <QApplication>
|
||||
#include <QtTest/QtTest>
|
||||
|
@ -62,15 +63,12 @@ class TestClientMachine : public QObject
|
|||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
void hostName_data();
|
||||
void hostName();
|
||||
void emptyHostName();
|
||||
|
||||
private:
|
||||
void setClientMachineProperty(xcb_window_t window, const QByteArray &hostname);
|
||||
xcb_window_t m_testWindow;
|
||||
QByteArray m_hostName;
|
||||
QByteArray m_fqdn;
|
||||
};
|
||||
|
@ -111,18 +109,6 @@ void TestClientMachine::cleanupTestCase()
|
|||
{
|
||||
}
|
||||
|
||||
void TestClientMachine::init()
|
||||
{
|
||||
m_testWindow = XCB_WINDOW_NONE;
|
||||
}
|
||||
|
||||
void TestClientMachine::cleanup()
|
||||
{
|
||||
if (m_testWindow != XCB_WINDOW_NONE) {
|
||||
xcb_destroy_window(connection(), m_testWindow);
|
||||
}
|
||||
}
|
||||
|
||||
void TestClientMachine::hostName_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("hostName");
|
||||
|
@ -147,14 +133,16 @@ void TestClientMachine::hostName_data()
|
|||
|
||||
void TestClientMachine::hostName()
|
||||
{
|
||||
m_testWindow = createWindow();
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = { true };
|
||||
Xcb::Window window(geometry, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
QFETCH(QByteArray, hostName);
|
||||
QFETCH(bool, local);
|
||||
setClientMachineProperty(m_testWindow, hostName);
|
||||
setClientMachineProperty(window, hostName);
|
||||
|
||||
ClientMachine clientMachine;
|
||||
QSignalSpy spy(&clientMachine, SIGNAL(localhostChanged()));
|
||||
clientMachine.resolve(m_testWindow, XCB_WINDOW_NONE);
|
||||
clientMachine.resolve(window, XCB_WINDOW_NONE);
|
||||
QTEST(clientMachine.hostName(), "expectedHost");
|
||||
|
||||
int i=0;
|
||||
|
@ -169,10 +157,12 @@ void TestClientMachine::hostName()
|
|||
|
||||
void TestClientMachine::emptyHostName()
|
||||
{
|
||||
m_testWindow = createWindow();
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = { true };
|
||||
Xcb::Window window(geometry, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
ClientMachine clientMachine;
|
||||
QSignalSpy spy(&clientMachine, SIGNAL(localhostChanged()));
|
||||
clientMachine.resolve(m_testWindow, XCB_WINDOW_NONE);
|
||||
clientMachine.resolve(window, XCB_WINDOW_NONE);
|
||||
QCOMPARE(clientMachine.hostName(), ClientMachine::localhost());
|
||||
QVERIFY(clientMachine.isLocal());
|
||||
// should be local
|
||||
|
|
174
tests/test_xcb_window.cpp
Normal file
174
tests/test_xcb_window.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "testutils.h"
|
||||
// KWin
|
||||
#include "../xcbutils.h"
|
||||
// Qt
|
||||
#include <QApplication>
|
||||
#include <QtTest/QtTest>
|
||||
// xcb
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
using namespace KWin;
|
||||
|
||||
class TestXcbWindow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void defaultCtor();
|
||||
void ctor();
|
||||
void classCtor();
|
||||
void create();
|
||||
void mapUnmap();
|
||||
void geometry();
|
||||
void destroy();
|
||||
};
|
||||
|
||||
void TestXcbWindow::defaultCtor()
|
||||
{
|
||||
Xcb::Window window;
|
||||
QCOMPARE(window.isValid(), false);
|
||||
xcb_window_t wId = window;
|
||||
QCOMPARE(wId, noneWindow());
|
||||
|
||||
xcb_window_t nativeWindow = createWindow();
|
||||
Xcb::Window window2(nativeWindow);
|
||||
QCOMPARE(window2.isValid(), true);
|
||||
wId = window2;
|
||||
QCOMPARE(wId, nativeWindow);
|
||||
}
|
||||
|
||||
void TestXcbWindow::ctor()
|
||||
{
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = {true};
|
||||
Xcb::Window window(geometry, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
QCOMPARE(window.isValid(), true);
|
||||
QVERIFY(window != XCB_WINDOW_NONE);
|
||||
Xcb::WindowGeometry windowGeometry(window);
|
||||
QCOMPARE(windowGeometry.isNull(), false);
|
||||
QCOMPARE(windowGeometry.rect(), geometry);
|
||||
}
|
||||
|
||||
void TestXcbWindow::classCtor()
|
||||
{
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = {true};
|
||||
Xcb::Window window(geometry, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
QCOMPARE(window.isValid(), true);
|
||||
QVERIFY(window != XCB_WINDOW_NONE);
|
||||
Xcb::WindowGeometry windowGeometry(window);
|
||||
QCOMPARE(windowGeometry.isNull(), false);
|
||||
QCOMPARE(windowGeometry.rect(), geometry);
|
||||
|
||||
Xcb::WindowAttributes attribs(window);
|
||||
QCOMPARE(attribs.isNull(), false);
|
||||
QVERIFY(attribs->_class == XCB_WINDOW_CLASS_INPUT_ONLY);
|
||||
}
|
||||
|
||||
void TestXcbWindow::create()
|
||||
{
|
||||
Xcb::Window window;
|
||||
QCOMPARE(window.isValid(), false);
|
||||
xcb_window_t wId = window;
|
||||
QCOMPARE(wId, noneWindow());
|
||||
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = {true};
|
||||
window.create(geometry, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
QCOMPARE(window.isValid(), true);
|
||||
QVERIFY(window != XCB_WINDOW_NONE);
|
||||
}
|
||||
|
||||
void TestXcbWindow::mapUnmap()
|
||||
{
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = {true};
|
||||
Xcb::Window window(geometry, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
Xcb::WindowAttributes attribs(window);
|
||||
QCOMPARE(attribs.isNull(), false);
|
||||
QVERIFY(attribs->map_state == XCB_MAP_STATE_UNMAPPED);
|
||||
|
||||
window.map();
|
||||
Xcb::WindowAttributes attribs2(window);
|
||||
QCOMPARE(attribs2.isNull(), false);
|
||||
QVERIFY(attribs2->map_state != XCB_MAP_STATE_UNMAPPED);
|
||||
|
||||
window.unmap();
|
||||
Xcb::WindowAttributes attribs3(window);
|
||||
QCOMPARE(attribs3.isNull(), false);
|
||||
QVERIFY(attribs3->map_state == XCB_MAP_STATE_UNMAPPED);
|
||||
}
|
||||
|
||||
void TestXcbWindow::geometry()
|
||||
{
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = {true};
|
||||
Xcb::Window window(geometry, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
Xcb::WindowGeometry windowGeometry(window);
|
||||
QCOMPARE(windowGeometry.isNull(), false);
|
||||
QCOMPARE(windowGeometry.rect(), geometry);
|
||||
|
||||
const QRect geometry2(10, 20, 100, 200);
|
||||
window.setGeometry(geometry2);
|
||||
Xcb::WindowGeometry windowGeometry2(window);
|
||||
QCOMPARE(windowGeometry2.isNull(), false);
|
||||
QCOMPARE(windowGeometry2.rect(), geometry2);
|
||||
}
|
||||
|
||||
void TestXcbWindow::destroy()
|
||||
{
|
||||
const QRect geometry(0, 0, 10, 10);
|
||||
const uint32_t values[] = {true};
|
||||
Xcb::Window window(geometry, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
QCOMPARE(window.isValid(), true);
|
||||
xcb_window_t wId = window;
|
||||
|
||||
window.create(geometry, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
// wId should now be invalid
|
||||
xcb_generic_error_t *error = NULL;
|
||||
ScopedCPointer<xcb_get_window_attributes_reply_t> attribs(xcb_get_window_attributes_reply(
|
||||
connection(),
|
||||
xcb_get_window_attributes(connection(), wId),
|
||||
&error));
|
||||
QVERIFY(attribs.isNull());
|
||||
QCOMPARE(error->error_code, uint8_t(3));
|
||||
QCOMPARE(error->resource_id, wId);
|
||||
free(error);
|
||||
|
||||
// test the same for the dtor
|
||||
{
|
||||
Xcb::Window scopedWindow(geometry, XCB_CW_OVERRIDE_REDIRECT, values);
|
||||
QVERIFY(scopedWindow.isValid());
|
||||
wId = scopedWindow;
|
||||
}
|
||||
error = NULL;
|
||||
ScopedCPointer<xcb_get_window_attributes_reply_t> attribs2(xcb_get_window_attributes_reply(
|
||||
connection(),
|
||||
xcb_get_window_attributes(connection(), wId),
|
||||
&error));
|
||||
QVERIFY(attribs2.isNull());
|
||||
QCOMPARE(error->error_code, uint8_t(3));
|
||||
QCOMPARE(error->resource_id, wId);
|
||||
free(error);
|
||||
}
|
||||
|
||||
KWIN_TEST_MAIN(TestXcbWindow)
|
||||
#include "test_xcb_window.moc"
|
207
xcbutils.h
207
xcbutils.h
|
@ -245,6 +245,213 @@ private:
|
|||
static Extensions *s_self;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is an RAII wrapper for an xcb_window_t. An xcb_window_t hold by an instance of this class
|
||||
* will be freed when the instance gets destroyed.
|
||||
*
|
||||
* Furthermore the class provides wrappers around some xcb methods operating on an xcb_window_t.
|
||||
**/
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Takes over responsibility of @p window. If @p window is not provided an invalid Window is
|
||||
* created. Use @link create to set an xcb_window_t later on.
|
||||
* @param window The window to manage.
|
||||
**/
|
||||
Window(xcb_window_t window = XCB_WINDOW_NONE);
|
||||
/**
|
||||
* Creates an xcb_window_t and manages it. It's a convenient method to create a window with
|
||||
* depth, class and visual being copied from parent and border being @c 0.
|
||||
* @param geometry The geometry for the window to be created
|
||||
* @param mask The mask for the values
|
||||
* @param values The values to be passed to xcb_create_window
|
||||
* @param parent The parent window
|
||||
**/
|
||||
Window(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
|
||||
/**
|
||||
* Creates an xcb_window_t and manages it. It's a convenient method to create a window with
|
||||
* depth and visual being copied from parent and border being @c 0.
|
||||
* @param geometry The geometry for the window to be created
|
||||
* @param class The window class
|
||||
* @param mask The mask for the values
|
||||
* @param values The values to be passed to xcb_create_window
|
||||
* @param parent The parent window
|
||||
**/
|
||||
Window(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
|
||||
~Window();
|
||||
|
||||
/**
|
||||
* Creates a new window for which the responsibility is taken over. If a window had been managed
|
||||
* before it is freed.
|
||||
*
|
||||
* Depth, class and visual are being copied from parent and border is @c 0.
|
||||
* @param geometry The geometry for the window to be created
|
||||
* @param mask The mask for the values
|
||||
* @param values The values to be passed to xcb_create_window
|
||||
* @param parent The parent window
|
||||
**/
|
||||
void create(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
|
||||
/**
|
||||
* Creates a new window for which the responsibility is taken over. If a window had been managed
|
||||
* before it is freed.
|
||||
*
|
||||
* Depth and visual are being copied from parent and border is @c 0.
|
||||
* @param geometry The geometry for the window to be created
|
||||
* @param class The window class
|
||||
* @param mask The mask for the values
|
||||
* @param values The values to be passed to xcb_create_window
|
||||
* @param parent The parent window
|
||||
**/
|
||||
void create(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
|
||||
/**
|
||||
* @returns @c true if a window is managed, @c false otherwise.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Configures the window with a new geometry.
|
||||
* @param geometry The new window geometry to be used
|
||||
**/
|
||||
void setGeometry(const QRect &geometry);
|
||||
void setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||
void map();
|
||||
void unmap();
|
||||
/**
|
||||
* Clears the window area. Same as xcb_clear_area with x, y, width, height being @c 0.
|
||||
**/
|
||||
void clear();
|
||||
void setBackgroundPixmap(xcb_pixmap_t pixmap);
|
||||
operator xcb_window_t() const;
|
||||
private:
|
||||
Window(const Window &other);
|
||||
xcb_window_t doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow());
|
||||
void destroy();
|
||||
xcb_window_t m_window;
|
||||
};
|
||||
|
||||
inline
|
||||
Window::Window(xcb_window_t window)
|
||||
: m_window(window)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
Window::Window(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
||||
: m_window(doCreate(geometry, XCB_COPY_FROM_PARENT, mask, values, parent))
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
Window::Window(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
||||
: m_window(doCreate(geometry, windowClass, mask, values, parent))
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
Window::~Window()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::destroy()
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
xcb_destroy_window(connection(), m_window);
|
||||
m_window = XCB_WINDOW_NONE;
|
||||
}
|
||||
|
||||
inline
|
||||
bool Window::isValid() const
|
||||
{
|
||||
return m_window != XCB_WINDOW_NONE;
|
||||
}
|
||||
|
||||
inline
|
||||
Window::operator xcb_window_t() const
|
||||
{
|
||||
return m_window;
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::create(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
||||
{
|
||||
destroy();
|
||||
m_window = doCreate(geometry, windowClass, mask, values, parent);
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::create(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
||||
{
|
||||
create(geometry, XCB_COPY_FROM_PARENT, mask, values, parent);
|
||||
}
|
||||
|
||||
inline
|
||||
xcb_window_t Window::doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
||||
{
|
||||
xcb_window_t w = xcb_generate_id(connection());
|
||||
xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent,
|
||||
geometry.x(), geometry.y(), geometry.width(), geometry.height(),
|
||||
0, windowClass, XCB_COPY_FROM_PARENT, mask, values);
|
||||
return w;
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::setGeometry(const QRect &geometry)
|
||||
{
|
||||
setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height());
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||
const uint32_t values[] = { x, y, width, height };
|
||||
xcb_configure_window(connection(), m_window, mask, values);
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::map()
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
xcb_map_window(connection(), m_window);
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::unmap()
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
xcb_unmap_window(connection(), m_window);
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::clear()
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
xcb_clear_area(connection(), false, m_window, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
inline
|
||||
void Window::setBackgroundPixmap(xcb_pixmap_t pixmap)
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
const uint32_t values[] = {pixmap};
|
||||
xcb_change_window_attributes(connection(), m_window, XCB_CW_BACK_PIXMAP, values);
|
||||
}
|
||||
|
||||
} // namespace X11
|
||||
|
||||
} // namespace KWin
|
||||
|
|
Loading…
Reference in a new issue