[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kwin] /: [Xcb::Wrapper] Introduce a Property and StringProperty Wrapper subclass
From:       Martin_Gräßlin <mgraesslin () kde ! org>
Date:       2014-04-17 5:47:36
Message-ID: E1WafAe-0006wd-L4 () scm ! kde ! org
[Download RAW message or body]

Git commit b45eeae3526de4308ce1f8f6a53fd0cb44d828ef by Martin Gräßlin.
Committed on 15/04/2014 at 08:09.
Pushed by graesslin into branch 'master'.

[Xcb::Wrapper] Introduce a Property and StringProperty Wrapper subclass

The Xcb::Property can wrap the xcb_get_property call and provides
convenient access methods to read the value of the reply with checks
applied. For this it provides a templated ::value method for reading a
single value or reading an array. There's also a ::toBool and
> > toByteArray which performs the conversion directly with default values
for the type and format checks.

Xcb::TransientFor is changed to be derived from Property instead of
Wrapper directly, so that the reading of the property value can be
shared.

Xcb::StringProperty is a convenient wrapper derived from Property to
handle the reading of a string property providing a cast to QByteArray
operator. This replaces the ::getStringProperty from utils. Though the
separator functionality from ::getStringProperty is not provided as that
is only used in one function and handled there.

All the custom usages of xcb_get_property or getStringProperty are
replaced to use this new wrapper. That simplifies the code and ensures
that all properties are read in the same way.

REVIEW: 117574

M  +2    -7    activation.cpp
M  +93   -0    autotests/test_xcb_wrapper.cpp
M  +32   -61   client.cpp
M  +2    -9    effects.cpp
M  +3    -6    shadow.cpp
M  +9    -30   toplevel.cpp
M  +0    -1    toplevel.h
M  +0    -22   utils.cpp
M  +0    -1    utils.h
M  +193  -8    xcbutils.h

http://commits.kde.org/kwin/b45eeae3526de4308ce1f8f6a53fd0cb44d828ef

diff --git a/activation.cpp b/activation.cpp
index f8a9414..d98c7d9 100644
--- a/activation.cpp
+++ b/activation.cpp
@@ -674,13 +674,8 @@ void Client::updateUserTime(xcb_timestamp_t time)
 
 xcb_timestamp_t Client::readUserCreationTime() const
 {
-    const xcb_get_property_cookie_t cookie = \
                xcb_get_property_unchecked(connection(), false, window(),
-        atoms->kde_net_wm_user_creation_time, XCB_ATOM_CARDINAL, 0, 10000);
-    ScopedCPointer<xcb_get_property_reply_t> \
                property(xcb_get_property_reply(connection(), cookie, NULL));
-    if (property.isNull() || xcb_get_property_value_length(property.data()) == 0) {
-        return -1;
-    }
-    return *(reinterpret_cast<xcb_timestamp_t*>(xcb_get_property_value(property.data())));
 +    Xcb::Property prop(false, window(), atoms->kde_net_wm_user_creation_time, \
XCB_ATOM_CARDINAL, 0, 1); +    return prop.value<xcb_timestamp_t>(-1);
 }
 
 void Client::demandAttention(bool set)
diff --git a/autotests/test_xcb_wrapper.cpp b/autotests/test_xcb_wrapper.cpp
index 769cd17..2ade4b0 100644
--- a/autotests/test_xcb_wrapper.cpp
+++ b/autotests/test_xcb_wrapper.cpp
@@ -23,6 +23,7 @@ along with this program.  If not, see \
<http://www.gnu.org/licenses/>.  // Qt
 #include <QApplication>
 #include <QtTest/QtTest>
+#include <netwm.h>
 // xcb
 #include <xcb/xcb.h>
 
@@ -47,6 +48,8 @@ private Q_SLOTS:
     void testQueryTree();
     void testCurrentInput();
     void testTransientFor();
+    void testPropertyByteArray();
+    void testPropertyBool();
 private:
     void testEmpty(WindowGeometry &geometry);
     void testGeometry(WindowGeometry &geometry, const QRect &rect);
@@ -275,6 +278,12 @@ void TestXcbWrapper::testTransientFor()
     xcb_window_t compareWindow = XCB_WINDOW_NONE;
     QVERIFY(!transient.getTransientFor(&compareWindow));
     QCOMPARE(compareWindow, xcb_window_t(XCB_WINDOW_NONE));
+    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);
 
     // Create a Window with a transient for hint
     Window transientWindow(createWindow());
@@ -284,11 +293,95 @@ void TestXcbWrapper::testTransientFor()
     TransientFor realTransient(transientWindow);
     QVERIFY(realTransient.getTransientFor(&compareWindow));
     QCOMPARE(compareWindow, m_testWindow);
+    ok = false;
+    QCOMPARE(realTransient.value<xcb_window_t>(32, XCB_ATOM_WINDOW, XCB_WINDOW_NONE, \
&ok), m_testWindow); +    QVERIFY(ok);
+    ok = false;
+    QCOMPARE(realTransient.value<xcb_window_t>(XCB_WINDOW_NONE, &ok), m_testWindow);
+    QVERIFY(ok);
+    ok = false;
+    QCOMPARE(realTransient.value<xcb_window_t>(), m_testWindow);
+    QCOMPARE(realTransient.value<xcb_window_t*>(nullptr, &ok)[0], m_testWindow);
+    QVERIFY(ok);
+    QCOMPARE(realTransient.value<xcb_window_t*>()[0], m_testWindow);
 
     // test for a not existing window
     TransientFor doesntExist(XCB_WINDOW_NONE);
     QVERIFY(!doesntExist.getTransientFor(&compareWindow));
 }
 
+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;
+    QVERIFY(!prop.value<const char*>());
+    QCOMPARE(prop.value<const char*>("bar", &ok), "bar");
+    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);
+    QCOMPARE(prop.value<const char*>(nullptr, &ok), "foo");
+    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());
+    QVERIFY(!ok);
+    QVERIFY(!prop.value<const char*>());
+    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);
+}
+
 KWIN_TEST_MAIN(TestXcbWrapper)
 #include "test_xcb_wrapper.moc"
diff --git a/client.cpp b/client.cpp
index dedffbe..0eb4086 100644
--- a/client.cpp
+++ b/client.cpp
@@ -2388,7 +2388,7 @@ void Client::checkActivities()
 {
 #ifdef KWIN_BUILD_ACTIVITIES
     QStringList newActivitiesList;
-    QByteArray prop = getStringProperty(window(), atoms->activities);
+    QByteArray prop = Xcb::StringProperty(window(), atoms->activities);
     activitiesDefined = !prop.isEmpty();
     if (QString::fromUtf8(prop) == Activities::nullUuid()) {
         //copied from setOnAllActivities to avoid a redundant XChangeProperty.
@@ -2456,36 +2456,20 @@ KDecorationDefines::Position Client::titlebarPosition() const
 void Client::updateFirstInTabBox()
 {
     // TODO: move into KWindowInfo
-    xcb_connection_t *c = connection();
-    const auto cookie = xcb_get_property_unchecked(c, false, m_client, \
                atoms->kde_first_in_window_list,
-                                                   atoms->kde_first_in_window_list, \
                0, 1);
-    ScopedCPointer<xcb_get_property_reply_t> prop(xcb_get_property_reply(c, cookie, \
                nullptr));
-    if (!prop.isNull() && prop->format == 32 && prop->value_len == 1) {
-        setFirstInTabBox(true);
-    } else {
-        setFirstInTabBox(false);
-    }
+    Xcb::Property property(false, m_client, atoms->kde_first_in_window_list,
+                           atoms->kde_first_in_window_list, 0, 1);
+    setFirstInTabBox(property.toBool(32, atoms->kde_first_in_window_list));
 }
 
 void Client::updateColorScheme()
 {
     // TODO: move into KWindowInfo
-    xcb_connection_t *c = connection();
-    const auto cookie = xcb_get_property_unchecked(c, false, m_client, \
                atoms->kde_color_sheme,
-                                                   XCB_ATOM_STRING, 0, 10000);
-    ScopedCPointer<xcb_get_property_reply_t> prop(xcb_get_property_reply(c, cookie, \
                nullptr));
-    auto resetToDefault = [this]() {
-        m_palette = QApplication::palette();
-    };
-    QString path;
-    if (!prop.isNull() && prop->format == 8 && prop->value_len > 0) {
-        path = QString::fromUtf8(static_cast<const \
                char*>(xcb_get_property_value(prop.data())));
-    }
+    QString path = QString::fromUtf8(Xcb::StringProperty(m_client, \
atoms->kde_color_sheme));  path = rules()->checkDecoColor(path);
     if (!path.isNull()) {
         m_palette = \
KColorScheme::createApplicationPalette(KSharedConfig::openConfig(path));  } else {
-        resetToDefault();
+        m_palette = QApplication::palette();
     }
     triggerDecorationRepaint();
 }
@@ -2563,48 +2547,35 @@ xcb_window_t Client::frameId() const
 
 void Client::updateShowOnScreenEdge()
 {
-    auto cookie = xcb_get_property_unchecked(connection(), false, window(), \
                atoms->kde_screen_edge_show, XCB_ATOM_CARDINAL, 0, 1);
-    ScopedCPointer<xcb_get_property_reply_t> \
                reply(xcb_get_property_reply(connection(), cookie, nullptr));
-
-    auto restore = [this]() {
+    Xcb::Property property(false, window(), atoms->kde_screen_edge_show, \
XCB_ATOM_CARDINAL, 0, 1); +    const uint32_t value = \
property.value<uint32_t>(ElectricNone); +    ElectricBorder border = ElectricNone;
+    switch (value) {
+    case 0:
+        border = ElectricTop;
+        break;
+    case 1:
+        border = ElectricRight;
+        break;
+    case 2:
+        border = ElectricBottom;
+        break;
+    case 3:
+        border = ElectricLeft;
+        break;
+    }
+    if (border != ElectricNone) {
+        hideClient(true);
+        ScreenEdges::self()->reserve(this, border);
+    } else if (!property.isNull() && property->type != XCB_ATOM_NONE) {
+        // property value is incorrect, delete the property
+        // so that the client knows that it is not hidden
+        xcb_delete_property(connection(), window(), atoms->kde_screen_edge_show);
+    } else {
+        // restore
         // TODO: add proper unreserve
         ScreenEdges::self()->reserve(this, ElectricNone);
         hideClient(false);
-    };
-
-    if (!reply.isNull()) {
-        if (reply->format == 32 && reply->type == XCB_ATOM_CARDINAL && \
                reply->value_len == 1) {
-            const uint32_t value = \
                *reinterpret_cast<uint32_t*>(xcb_get_property_value(reply.data()));
-            ElectricBorder border = ElectricNone;
-            switch (value) {
-            case 0:
-                border = ElectricTop;
-                break;
-            case 1:
-                border = ElectricRight;
-                break;
-            case 2:
-                border = ElectricBottom;
-                break;
-            case 3:
-                border = ElectricLeft;
-                break;
-            }
-            if (border != ElectricNone) {
-                hideClient(true);
-                ScreenEdges::self()->reserve(this, border);
-            } else {
-                // property value is incorrect, delete the property
-                // so that the client knows that it is not hidden
-                xcb_delete_property(connection(), window(), \
                atoms->kde_screen_edge_show);
-            }
-
-        } else if (reply->type == XCB_ATOM_NONE) {
-            // the property got deleted, show the client again
-            restore();
-        }
-    } else {
-        restore();
     }
 }
 
diff --git a/effects.cpp b/effects.cpp
index 1963c48..4d88208 100644
--- a/effects.cpp
+++ b/effects.cpp
@@ -166,10 +166,8 @@ void ScreenLockerWatcher::setLocked(bool activated)
 static QByteArray readWindowProperty(xcb_window_t win, xcb_atom_t atom, xcb_atom_t \
type, int format)  {
     uint32_t len = 32768;
-    xcb_connection_t *c = connection();
     for (;;) {
-        const auto cookie = xcb_get_property_unchecked(c, false, win, atom, \
                XCB_ATOM_ANY, 0, len);
-        ScopedCPointer<xcb_get_property_reply_t> prop(xcb_get_property_reply(c, \
cookie, nullptr)); +        Xcb::Property prop(false, win, atom, XCB_ATOM_ANY, 0, \
len);  if (prop.isNull()) {
             // get property failed
             return QByteArray();
@@ -178,12 +176,7 @@ static QByteArray readWindowProperty(xcb_window_t win, \
xcb_atom_t atom, xcb_atom  len *= 2;
             continue;
         }
-        if (prop->type == type && prop->format == format) {
-            return QByteArray(reinterpret_cast< const char* \
                >(xcb_get_property_value(prop.data())),
-                              xcb_get_property_value_length(prop.data()));
-        } else {
-            return QByteArray();
-        }
+        return prop.toByteArray(format, type);
     }
 }
 
diff --git a/shadow.cpp b/shadow.cpp
index 10c9594..ca13947 100644
--- a/shadow.cpp
+++ b/shadow.cpp
@@ -63,12 +63,9 @@ Shadow *Shadow::createShadow(Toplevel *toplevel)
 QVector< uint32_t > Shadow::readX11ShadowProperty(xcb_window_t id)
 {
     QVector<uint32_t> ret;
-    xcb_connection_t *c = connection();
-    const auto cookie = xcb_get_property_unchecked(c, false, id, \
                atoms->kde_net_wm_shadow,
-                                                   XCB_ATOM_CARDINAL, 0, 12);
-    ScopedCPointer<xcb_get_property_reply_t> prop(xcb_get_property_reply(c, cookie, \
                nullptr));
-    if (!prop.isNull() && prop->type == XCB_ATOM_CARDINAL && prop->format == 32 ) {
-        uint32_t* shadow = reinterpret_cast< uint32_t* \
>(xcb_get_property_value(prop.data())); +    Xcb::Property property(false, id, \
> atoms->kde_net_wm_shadow, XCB_ATOM_CARDINAL, 0, 12);
+    uint32_t *shadow = property.value<uint32_t*>();
+    if (shadow) {
         ret.reserve(12);
         for (int i=0; i<12; ++i) {
             ret << shadow[i];
diff --git a/toplevel.cpp b/toplevel.cpp
index a945757..b88ef04 100644
--- a/toplevel.cpp
+++ b/toplevel.cpp
@@ -145,24 +145,10 @@ QRect Toplevel::visibleRect() const
     return r.translated(geometry().topLeft());
 }
 
-/*!
-  Returns WM_CLIENT_LEADER property for a given window.
- */
-xcb_window_t Toplevel::staticWmClientLeader(xcb_window_t w)
-{
-    xcb_connection_t *c = connection();
-    auto cookie = xcb_get_property_unchecked(c, false, w, atoms->wm_client_leader, \
                XCB_ATOM_WINDOW, 0, 10000);
-    ScopedCPointer<xcb_get_property_reply_t> prop(xcb_get_property_reply(c, cookie, \
                nullptr));
-    if (prop.isNull() || prop->value_len <= 0) {
-        return w;
-    }
-    return static_cast<xcb_window_t*>(xcb_get_property_value(prop.data()))[0];
-}
-
-
 void Toplevel::getWmClientLeader()
 {
-    wmClientLeaderWin = staticWmClientLeader(window());
+    Xcb::Property prop(false, window(), atoms->wm_client_leader, XCB_ATOM_WINDOW, 0, \
10000); +    wmClientLeaderWin = prop.value<xcb_window_t>(window());
 }
 
 /*!
@@ -171,9 +157,9 @@ void Toplevel::getWmClientLeader()
  */
 QByteArray Toplevel::sessionId() const
 {
-    QByteArray result = getStringProperty(window(), atoms->sm_client_id);
+    QByteArray result = Xcb::StringProperty(window(), atoms->sm_client_id);
     if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin != window())
-        result = getStringProperty(wmClientLeaderWin, atoms->sm_client_id);
+        result = Xcb::StringProperty(wmClientLeaderWin, atoms->sm_client_id);
     return result;
 }
 
@@ -183,9 +169,10 @@ QByteArray Toplevel::sessionId() const
  */
 QByteArray Toplevel::wmCommand()
 {
-    QByteArray result = getStringProperty(window(), XCB_ATOM_WM_COMMAND, ' ');
+    QByteArray result = Xcb::StringProperty(window(), XCB_ATOM_WM_COMMAND);
     if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin != window())
-        result = getStringProperty(wmClientLeaderWin, XCB_ATOM_WM_COMMAND, ' ');
+        result = Xcb::StringProperty(wmClientLeaderWin, XCB_ATOM_WM_COMMAND);
+    result.replace(0, ' ');
     return result;
 }
 
@@ -438,16 +425,8 @@ xcb_window_t Toplevel::frameId() const
 
 void Toplevel::getSkipCloseAnimation()
 {
-    auto cookie = xcb_get_property_unchecked(connection(), false, window(), \
                atoms->kde_skip_close_animation, XCB_ATOM_CARDINAL, 0, 1);
-    ScopedCPointer<xcb_get_property_reply_t> \
                reply(xcb_get_property_reply(connection(), cookie, nullptr));
-    bool newValue = false;
-    if (!reply.isNull()) {
-        if (reply->format == 32 && reply->type == XCB_ATOM_CARDINAL && \
                reply->value_len == 1) {
-            const uint32_t value = \
                *reinterpret_cast<uint32_t*>(xcb_get_property_value(reply.data()));
-            newValue = (value != 0);
-        }
-    }
-    setSkipCloseAnimation(newValue);
+    Xcb::Property property(false, window(), atoms->kde_skip_close_animation, \
XCB_ATOM_CARDINAL, 0, 1); +    setSkipCloseAnimation(property.toBool());
 }
 
 bool Toplevel::skipsCloseAnimation() const
diff --git a/toplevel.h b/toplevel.h
index 305f667..2fce2c1 100644
--- a/toplevel.h
+++ b/toplevel.h
@@ -438,7 +438,6 @@ protected:
     bool m_isDamaged;
 
 private:
-    static xcb_window_t staticWmClientLeader(xcb_window_t);
     // when adding new data members, check also copyToDeleted()
     Xcb::Window m_client;
     xcb_damage_damage_t damage_handle;
diff --git a/utils.cpp b/utils.cpp
index 88ab2d8..856818d 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -67,28 +67,6 @@ StrutRect::StrutRect(const StrutRect& other)
 
 #endif
 
-QByteArray getStringProperty(xcb_window_t w, xcb_atom_t prop, char separator)
-{
-    const xcb_get_property_cookie_t c = xcb_get_property_unchecked(connection(), \
                false, w, prop,
-                                                                   XCB_ATOM_STRING, \
                0, 10000);
-    ScopedCPointer<xcb_get_property_reply_t> \
                property(xcb_get_property_reply(connection(), c, NULL));
-    if (property.isNull() || property->type == XCB_ATOM_NONE) {
-        return QByteArray();
-    }
-    char *data = static_cast<char*>(xcb_get_property_value(property.data()));
-    int length = property->value_len;
-    if (data && separator) {
-        for (uint32_t i = 0; i < property->value_len; ++i) {
-            if (!data[i] && i + 1 < property->value_len) {
-                data[i] = separator;
-            } else {
-                length = i;
-            }
-        }
-    }
-    return QByteArray(data, length);
-}
-
 #ifndef KCMRULES
 /*
  Updates xTime(). This used to simply fetch current timestamp from the server,
diff --git a/utils.h b/utils.h
index 198db92..e96adbf 100644
--- a/utils.h
+++ b/utils.h
@@ -122,7 +122,6 @@ enum ShadeMode {
 
 template <typename T> using ScopedCPointer = QScopedPointer<T, \
QScopedPointerPodDeleter>;  
-QByteArray getStringProperty(xcb_window_t w, xcb_atom_t prop, char separator = 0);
 void updateXTime();
 void grabXServer();
 void ungrabXServer();
diff --git a/xcbutils.h b/xcbutils.h
index 61611b7..2762f2e 100644
--- a/xcbutils.h
+++ b/xcbutils.h
@@ -592,11 +592,199 @@ public:
 };
 
 XCB_WRAPPER_DATA(PropertyData, xcb_get_property, uint8_t, xcb_window_t, xcb_atom_t, \
                xcb_atom_t, uint32_t, uint32_t)
-class TransientFor : public Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, \
xcb_atom_t, uint32_t, uint32_t> +class Property : public Wrapper<PropertyData, \
uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t> +{
+public:
+    Property()
+        : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, \
uint32_t, uint32_t>() +        , m_type(XCB_ATOM_NONE)
+    {
+    }
+    Property(const Property &other)
+        : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, \
uint32_t, uint32_t>(other) +        , m_type(other.m_type)
+    {
+    }
+    explicit Property(uint8_t _delete, xcb_window_t window, xcb_atom_t property, \
xcb_atom_t type, uint32_t long_offset, uint32_t long_length) +        : \
Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, \
uint32_t>(window, _delete, window, property, type, long_offset, long_length) +        \
, m_type(type) +    {
+    }
+    Property &operator=(const Property &other) {
+        Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, \
uint32_t, uint32_t>::operator=(other); +        m_type = other.m_type;
+        return *this;
+    }
+
+    /**
+     * @brief Overloaded method for convenience.
+     *
+     * Uses the type which got passed into the ctor and derives the format from the \
sizeof(T). +     * Note: for the automatic format detection the size of the type T \
may not vary between +     * architectures. Thus one needs to use e.g. uint32_t \
instead of long. In general all xcb +     * data types can be used, all Xlib data \
types can not be used. +     *
+     * @param defaultValue The default value to return in case of error
+     * @param ok Set to @c false in case of error, @c true in case of success
+     * @return The read value or @p defaultValue in error case
+     */
+    template <typename T>
+    inline typename std::enable_if<!std::is_pointer<T>::value, T>::type value(T \
defaultValue = T(), bool *ok = nullptr) { +        return value<T>(sizeof(T) * 8, \
m_type, defaultValue, ok); +    }
+    /**
+     * @brief Reads the property as a POD type.
+     *
+     * Returns the first value of the property data. In case of @p format or @p type \
mismatch +     * the @p defaultValue is returned. The optional argument @p ok is set
+     * to @c false in case of error and to @c true in case of successful reading of
+     * the property.
+     *
+     * @param format The expected format of the property value, e.g. 32 for \
XCB_ATOM_CARDINAL +     * @param type The expected type of the property value, e.g. \
XCB_ATOM_CARDINAL +     * @param defaultValue The default value to return in case of \
error +     * @param ok Set to @c false in case of error, @c true in case of success
+     * @return The read value or @p defaultValue in error case
+     **/
+    template <typename T>
+    inline typename std::enable_if<!std::is_pointer<T>::value, T>::type \
value(uint8_t format, xcb_atom_t type, T defaultValue = T(), bool *ok = nullptr) { +  \
T *reply = value<T*>(format, type, nullptr, ok); +        if (!reply) {
+            return defaultValue;
+        }
+        return reply[0];
+    }
+    /**
+     * @brief Overloaded method for convenience.
+     *
+     * Uses the type which got passed into the ctor and derives the format from the \
sizeof(T). +     * Note: for the automatic format detection the size of the type T \
may not vary between +     * architectures. Thus one needs to use e.g. uint32_t \
instead of long. In general all xcb +     * data types can be used, all Xlib data \
types can not be used. +     *
+     * @param defaultValue The default value to return in case of error
+     * @param ok Set to @c false in case of error, @c true in case of success
+     * @return The read value or @p defaultValue in error case
+     */
+    template <typename T>
+    inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(T \
defaultValue = nullptr, bool *ok = nullptr) { +        return \
value<T>(sizeof(typename std::remove_pointer<T>::type) * 8, m_type, defaultValue, \
ok); +    }
+    /**
+     * @brief Reads the property as an array of T.
+     *
+     * This method is an overload for the case that T is a pointer type.
+     *
+     * Return the property value casted to the pointer type T. In case of @p format
+     * or @p type mismatch the @p defaultValue is returned. Also if the value length
+     * is @c 0 the @p defaultValue is returned. The optional argument @p ok is set
+     * to @c false in case of error and to @c true in case of successful reading of
+     * the property.
+     *
+     * @param format The expected format of the property value, e.g. 32 for \
XCB_ATOM_CARDINAL +     * @param type The expected type of the property value, e.g. \
XCB_ATOM_CARDINAL +     * @param defaultValue The default value to return in case of \
error +     * @param ok Set to @c false in case of error, @c true in case of success
+     * @return The read value or @p defaultValue in error case
+     **/
+    template <typename T>
+    inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(uint8_t \
format, xcb_atom_t type, T defaultValue = nullptr, bool *ok = nullptr) { +        if \
(ok) { +            *ok = false;
+        }
+        const PropertyData::reply_type *reply = data();
+        if (!reply) {
+            return defaultValue;
+        }
+        if (reply->type != type) {
+            return defaultValue;
+        }
+        if (reply->format != format) {
+            return defaultValue;
+        }
+        if (xcb_get_property_value_length(reply) == 0) {
+            return defaultValue;
+        }
+        if (ok) {
+            *ok = true;
+        }
+        return reinterpret_cast<T>(xcb_get_property_value(reply));
+    }
+    /**
+     * @brief Reads the property as string and returns a QByteArray.
+     *
+     * In case of error this method returns a null QByteArray.
+     **/
+    inline QByteArray toByteArray(uint8_t format = 8, xcb_atom_t type = \
XCB_ATOM_STRING, bool *ok = nullptr) { +        const char *reply = value<const \
char*>(format, type, nullptr, ok); +        if (!reply) {
+            return QByteArray();
+        }
+        return QByteArray(reply, xcb_get_property_value_length(data()));
+    }
+    /**
+     * @brief Overloaded method for convenience.
+     **/
+    inline QByteArray toByteArray(bool *ok) {
+        return toByteArray(8, m_type, ok);
+    }
+    /**
+     * @brief Reads the property as a boolean value.
+     *
+     * If the property reply length is @c 1 the first element is interpreted as a \
boolean +     * value returning @c true for any value unequal to @c 0 and @c false \
otherwise. +     *
+     * In case of error this method returns @c false. Thus it is not possible to \
distinguish +     * between error case and a read @c false value. Use the optional \
argument @p ok to +     * distinguish the error case.
+     *
+     * @param format Expected format. Defaults to 32.
+     * @param type Expected type Defaults to XCB_ATOM_CARDINAL.
+     * @param ok Set to @c false in case of error, @c true in case of success
+     * @return bool The first element interpreted as a boolean value or @c false in \
error case +     * @see value
+     */
+    inline bool toBool(uint8_t format = 32, xcb_atom_t type = XCB_ATOM_CARDINAL, \
bool *ok = nullptr) { +        bool *reply = value<bool*>(format, type, nullptr, ok);
+        if (!reply) {
+            return false;
+        }
+        if (data()->value_len != 1) {
+            if (ok) {
+                *ok = false;
+            }
+            return false;
+        }
+        return reply[0] != 0;
+    }
+    /**
+     * @brief Overloaded method for convenience.
+     **/
+    inline bool toBool(bool *ok) {
+        return toBool(32, m_type, ok);
+    }
+private:
+    xcb_atom_t m_type;
+};
+
+class StringProperty : public Property
+{
+public:
+    StringProperty() = default;
+    explicit StringProperty(xcb_window_t w, xcb_atom_t p)
+        : Property(false, w, p, XCB_ATOM_STRING, 0, 10000)
+    {
+    }
+    operator QByteArray() {
+        return toByteArray();
+    }
+};
+
+class TransientFor : public Property
 {
 public:
     explicit TransientFor(WindowId window)
-        : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, \
uint32_t, uint32_t>(window, 0, window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, \
1) +        : Property(0, window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, 1)
     {
     }
 
@@ -606,15 +794,12 @@ public:
      * @returns @c true on success, @c false otherwise
      **/
     inline bool getTransientFor(WindowId *prop) {
-        if (isNull()) {
+        WindowId *windows = value<WindowId*>();
+        if (!windows) {
             return false;
         }
 
-        const xcb_get_property_reply_t *reply = data();
-        if (!reply || reply->type != XCB_ATOM_WINDOW || reply->format != 32 || \
                reply->length == 0)
-            return false;
-
-        *prop = *reinterpret_cast<WindowId *>(xcb_get_property_value(reply));
+        *prop = *windows;
         return true;
     }
 };


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic