/* K Win - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2012, 2013 Martin Gräßlin SPDX-FileCopyrightText: 2015 Daniel Vrátil SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include #include namespace XCB { template using ScopedPointer = QScopedPointer; xcb_connection_t *connection(); void closeConnection(); xcb_screen_t *screenOfDisplay(xcb_connection_t *c, int screen); struct GrabServer { GrabServer(); ~GrabServer(); }; template class Wrapper { public: Wrapper() : m_retrieved(false) , m_window(XCB_WINDOW_NONE) , m_reply(nullptr) { m_cookie.sequence = 0; } explicit Wrapper(const RequestFuncArgs &... args) : m_retrieved(false) , m_cookie(requestFunc(connection(), args...)) , m_window(requestWindow(args...)) , m_reply(nullptr) { } explicit Wrapper(const Wrapper &other) : m_retrieved(other.m_retrieved) , m_cookie(other.m_cookie) , m_window(other.m_window) , m_reply(nullptr) { takeFromOther(const_cast(other)); } virtual ~Wrapper() { cleanup(); } inline Wrapper &operator=(const Wrapper &other) { if (this != &other) { // if we had managed a reply, free it cleanup(); // copy members m_retrieved = other.m_retrieved; m_cookie = other.m_cookie; m_window = other.m_window; m_reply = other.m_reply; // take over the responsibility for the reply pointer takeFromOther(const_cast(other)); } return *this; } inline operator const Reply *() const { getReply(); return m_reply; } inline const Reply *operator->() const { getReply(); return m_reply; } inline bool isNull() const { getReply(); return m_reply == nullptr; } inline operator bool() const { return !isNull(); } inline const Reply *data() const { getReply(); return m_reply; } inline xcb_window_t window() const { return m_window; } inline bool isRetrieved() const { return m_retrieved; } /** * Returns the value of the reply pointer referenced by this object. The reply pointer of * this object will be reset to null. Calling any method which requires the reply to be valid * will crash. * * Callers of this function take ownership of the pointer. **/ inline Reply *take() { getReply(); Reply *ret = m_reply; m_reply = nullptr; m_window = XCB_WINDOW_NONE; return ret; } protected: void getReply() const { if (m_retrieved || !m_cookie.sequence) { return; } m_reply = replyFunc(connection(), m_cookie, nullptr); m_retrieved = true; } private: inline void cleanup() { if (!m_retrieved && m_cookie.sequence) { xcb_discard_reply(connection(), m_cookie.sequence); } else if (m_reply) { free(m_reply); } } inline void takeFromOther(Wrapper &other) { if (m_retrieved) { m_reply = other.take(); } else { // ensure that other object doesn't try to get the reply or discards it in the dtor other.m_retrieved = true; other.m_window = XCB_WINDOW_NONE; } } template constexpr xcb_window_t requestWindow(const Args &... args) const { return std::is_same>::type, xcb_window_t>::value ? std::get<0>(std::tuple(args...)) : static_cast(XCB_WINDOW_NONE); } mutable bool m_retrieved; Cookie m_cookie; xcb_window_t m_window; mutable Reply *m_reply; }; #define XCB_DECLARE_TYPE(name, xcb_request, ...) \ typedef Wrapper \ name XCB_DECLARE_TYPE(ScreenInfo, xcb_randr_get_screen_info, xcb_window_t); XCB_DECLARE_TYPE(ScreenSize, xcb_randr_get_screen_size_range, xcb_window_t); XCB_DECLARE_TYPE(PrimaryOutput, xcb_randr_get_output_primary, xcb_window_t); XCB_DECLARE_TYPE(InternAtom, xcb_intern_atom, uint8_t, uint16_t, const char *); XCB_DECLARE_TYPE(OutputInfo, xcb_randr_get_output_info, xcb_randr_output_t, xcb_timestamp_t); XCB_DECLARE_TYPE(CRTCInfo, xcb_randr_get_crtc_info, xcb_randr_crtc_t, xcb_timestamp_t); XCB_DECLARE_TYPE(AtomName, xcb_get_atom_name, xcb_atom_t); }