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 }