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