File indexing completed on 2024-03-24 17:07:40

0001 /*
0002     K Win - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2012, 2013 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2015 Daniel Vrátil <dvratil@redhat.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #ifndef XCB_WRAPPER_H
0012 #define XCB_WRAPPER_H
0013 
0014 #include <functional>
0015 #include <type_traits>
0016 
0017 #include <QScopedPointer>
0018 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0019 #include <private/qtx11extras_p.h>
0020 #else
0021 #include <QX11Info>
0022 #endif
0023 
0024 #include <xcb/randr.h>
0025 #include <xcb/xcb.h>
0026 
0027 namespace XCB
0028 {
0029 template<typename T> using ScopedPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
0030 
0031 xcb_connection_t *connection();
0032 void closeConnection();
0033 xcb_screen_t *screenOfDisplay(xcb_connection_t *c, int screen);
0034 
0035 struct GrabServer {
0036     GrabServer();
0037     ~GrabServer();
0038 };
0039 
0040 template<typename Reply, typename Cookie, typename ReplyFunc, ReplyFunc replyFunc, typename RequestFunc, RequestFunc requestFunc, typename... RequestFuncArgs>
0041 class Wrapper
0042 {
0043 public:
0044     Wrapper()
0045         : m_retrieved(false)
0046         , m_window(XCB_WINDOW_NONE)
0047         , m_reply(nullptr)
0048     {
0049         m_cookie.sequence = 0;
0050     }
0051 
0052     explicit Wrapper(const RequestFuncArgs &... args)
0053         : m_retrieved(false)
0054         , m_cookie(requestFunc(connection(), args...))
0055         , m_window(requestWindow<RequestFuncArgs...>(args...))
0056         , m_reply(nullptr)
0057     {
0058     }
0059 
0060     explicit Wrapper(const Wrapper &other)
0061         : m_retrieved(other.m_retrieved)
0062         , m_cookie(other.m_cookie)
0063         , m_window(other.m_window)
0064         , m_reply(nullptr)
0065     {
0066         takeFromOther(const_cast<Wrapper &>(other));
0067     }
0068 
0069     virtual ~Wrapper()
0070     {
0071         cleanup();
0072     }
0073 
0074     inline Wrapper &operator=(const Wrapper &other)
0075     {
0076         if (this != &other) {
0077             // if we had managed a reply, free it
0078             cleanup();
0079             // copy members
0080             m_retrieved = other.m_retrieved;
0081             m_cookie = other.m_cookie;
0082             m_window = other.m_window;
0083             m_reply = other.m_reply;
0084             // take over the responsibility for the reply pointer
0085             takeFromOther(const_cast<Wrapper &>(other));
0086         }
0087         return *this;
0088     }
0089 
0090     inline operator const Reply *() const
0091     {
0092         getReply();
0093         return m_reply;
0094     }
0095 
0096     inline const Reply *operator->() const
0097     {
0098         getReply();
0099         return m_reply;
0100     }
0101 
0102     inline bool isNull() const
0103     {
0104         getReply();
0105         return m_reply == nullptr;
0106     }
0107 
0108     inline operator bool() const
0109     {
0110         return !isNull();
0111     }
0112 
0113     inline const Reply *data() const
0114     {
0115         getReply();
0116         return m_reply;
0117     }
0118 
0119     inline xcb_window_t window() const
0120     {
0121         return m_window;
0122     }
0123 
0124     inline bool isRetrieved() const
0125     {
0126         return m_retrieved;
0127     }
0128     /**
0129      * Returns the value of the reply pointer referenced by this object. The reply pointer of
0130      * this object will be reset to null. Calling any method which requires the reply to be valid
0131      * will crash.
0132      *
0133      * Callers of this function take ownership of the pointer.
0134      **/
0135     inline Reply *take()
0136     {
0137         getReply();
0138         Reply *ret = m_reply;
0139         m_reply = nullptr;
0140         m_window = XCB_WINDOW_NONE;
0141         return ret;
0142     }
0143 
0144 protected:
0145     void getReply() const
0146     {
0147         if (m_retrieved || !m_cookie.sequence) {
0148             return;
0149         }
0150         m_reply = replyFunc(connection(), m_cookie, nullptr);
0151         m_retrieved = true;
0152     }
0153 
0154 private:
0155     inline void cleanup()
0156     {
0157         if (!m_retrieved && m_cookie.sequence) {
0158             xcb_discard_reply(connection(), m_cookie.sequence);
0159         } else if (m_reply) {
0160             free(m_reply);
0161         }
0162     }
0163 
0164     inline void takeFromOther(Wrapper &other)
0165     {
0166         if (m_retrieved) {
0167             m_reply = other.take();
0168         } else {
0169             // ensure that other object doesn't try to get the reply or discards it in the dtor
0170             other.m_retrieved = true;
0171             other.m_window = XCB_WINDOW_NONE;
0172         }
0173     }
0174 
0175     template<typename... Args> constexpr xcb_window_t requestWindow(const Args &... args) const
0176     {
0177         return std::is_same<typename std::tuple_element<0, std::tuple<Args...>>::type, xcb_window_t>::value ? std::get<0>(std::tuple<Args...>(args...))
0178                                                                                                             : static_cast<xcb_window_t>(XCB_WINDOW_NONE);
0179     }
0180 
0181     mutable bool m_retrieved;
0182     Cookie m_cookie;
0183     xcb_window_t m_window;
0184     mutable Reply *m_reply;
0185 };
0186 
0187 #define XCB_DECLARE_TYPE(name, xcb_request, ...)                                                                                                               \
0188     typedef Wrapper<xcb_request##_reply_t,                                                                                                                     \
0189                     xcb_request##_cookie_t,                                                                                                                    \
0190                     decltype(&xcb_request##_reply),                                                                                                            \
0191                     xcb_request##_reply,                                                                                                                       \
0192                     decltype(&xcb_request),                                                                                                                    \
0193                     xcb_request,                                                                                                                               \
0194                     ##__VA_ARGS__>                                                                                                                             \
0195         name
0196 
0197 XCB_DECLARE_TYPE(ScreenInfo, xcb_randr_get_screen_info, xcb_window_t);
0198 
0199 XCB_DECLARE_TYPE(ScreenSize, xcb_randr_get_screen_size_range, xcb_window_t);
0200 
0201 XCB_DECLARE_TYPE(PrimaryOutput, xcb_randr_get_output_primary, xcb_window_t);
0202 
0203 XCB_DECLARE_TYPE(InternAtom, xcb_intern_atom, uint8_t, uint16_t, const char *);
0204 
0205 XCB_DECLARE_TYPE(OutputInfo, xcb_randr_get_output_info, xcb_randr_output_t, xcb_timestamp_t);
0206 
0207 XCB_DECLARE_TYPE(CRTCInfo, xcb_randr_get_crtc_info, xcb_randr_crtc_t, xcb_timestamp_t);
0208 
0209 XCB_DECLARE_TYPE(AtomName, xcb_get_atom_name, xcb_atom_t);
0210 
0211 }
0212 
0213 #endif