[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
This commit is contained in:
parent
8d3b12b928
commit
b45eeae352
10 changed files with 334 additions and 145 deletions
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
93
client.cpp
93
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
effects.cpp
11
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
39
toplevel.cpp
39
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
|
||||
|
|
|
@ -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;
|
||||
|
|
22
utils.cpp
22
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,
|
||||
|
|
1
utils.h
1
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();
|
||||
|
|
201
xcbutils.h
201
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;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue