File indexing completed on 2024-04-28 05:31:26

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