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
* ...
icc-effect-5.14.5
Martin Gräßlin 2013-01-29 14:03:05 +01:00
parent e68f7f960b
commit f238cbc3f5
4 changed files with 407 additions and 20 deletions

View File

@ -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}
)

View File

@ -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
View 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"

View File

@ -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