1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
/*
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef NETTESTHELPER_H
#define NETTESTHELPER_H
#include <QByteArray>
#include <memory>
#include <xcb/xcb.h>
#include "cptr_p.h"
namespace KXUtils
{
/**
* @brief Small helper class to fetch an intern atom through XCB.
*
* This class allows to request an intern atom and delay the retrieval of the reply
* till it is needed. In case the reply is never retrieved the reply gets discarded
* in the dtor. So there is no need to keep track manually about which atoms have been
* retrieved.
*
* This class can be used as a drop-in replacement for everywhere where a xcb_atom_t is
* needed as it implements the cast operator. The first time this operator is invoked it
* will retrieve the reply. If the xcb request failed the value is @c XCB_ATOM_NONE, which
* can be used to check whether the returned value is valid.
*
* This class has two modes of operations: a direct one which performs the request directly
* during construction, and an indirect one which needs an explicit call to {@link fetch}.
*
* @code
* Atom direct(QX11Info::connection(), QByteArrayLiteral("myAtomName"));
* Atom indirect(QByteArrayLiteral("myAtomName"));
* indirect.setConnection(QX11Info::connection());
* indirect.fetch();
*
* if (direct == XCB_ATOM_NONE) {
* qWarning() << "Request failed";
* }
* if (indirect == XCB_ATOM_NONE) {
* qWarning() << "Request failed";
* }
* @endcode
*/
class Atom
{
public:
explicit Atom(const QByteArray &name)
: m_connection(nullptr)
, m_retrieved(false)
, m_atom(XCB_ATOM_NONE)
, m_name(name)
{
m_cookie.sequence = 0;
}
explicit Atom(xcb_connection_t *c, const QByteArray &name, bool onlyIfExists = false)
: m_connection(c)
, m_retrieved(false)
, m_cookie(xcb_intern_atom_unchecked(m_connection, onlyIfExists, name.length(), name.constData()))
, m_atom(XCB_ATOM_NONE)
, m_name(name)
{
}
Atom() Q_DECL_EQ_DELETE;
Atom(const Atom &) Q_DECL_EQ_DELETE;
~Atom()
{
if (!m_retrieved && m_cookie.sequence) {
xcb_discard_reply(m_connection, m_cookie.sequence);
}
}
void setConnection(xcb_connection_t *c)
{
m_connection = c;
}
void fetch(bool onlyIfExists = false)
{
if (!m_connection) {
// set connection first!
return;
}
if (m_retrieved || m_cookie.sequence) {
// already fetched, don't fetch again
return;
}
m_cookie = xcb_intern_atom_unchecked(m_connection, onlyIfExists, m_name.length(), m_name.constData());
}
operator xcb_atom_t() const
{
(const_cast<Atom *>(this))->getReply();
return m_atom;
}
const QByteArray &name() const
{
return m_name;
}
private:
void getReply()
{
if (m_retrieved || !m_cookie.sequence) {
return;
}
UniqueCPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr));
if (reply) {
m_atom = reply->atom;
}
m_retrieved = true;
}
xcb_connection_t *m_connection;
bool m_retrieved;
xcb_intern_atom_cookie_t m_cookie;
xcb_atom_t m_atom;
QByteArray m_name;
};
inline xcb_window_t rootWindow(xcb_connection_t *c, int screen)
{
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(c));
for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(c)); it.rem; --screen, xcb_screen_next(&it)) {
if (screen == 0) {
return iter.data->root;
}
}
return XCB_WINDOW_NONE;
}
}
#endif
|