/* SPDX-FileCopyrightText: 2013 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef NETTESTHELPER_H #define NETTESTHELPER_H #include #include #include #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(this))->getReply(); return m_atom; } const QByteArray &name() const { return m_name; } private: void getReply() { if (m_retrieved || !m_cookie.sequence) { return; } UniqueCPointer 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