File indexing completed on 2025-03-16 08:15:02
0001 /* 0002 KWin - 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 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #pragma once 0010 0011 #include "effect/globals.h" 0012 #include "effect/xcb.h" 0013 #include "main.h" 0014 #include "utils/c_ptr.h" 0015 #include "utils/version.h" 0016 0017 #include <QList> 0018 #include <QRect> 0019 #include <QRegion> 0020 0021 #include <xcb/composite.h> 0022 #include <xcb/randr.h> 0023 #include <xcb/xcb.h> 0024 0025 #include <xcb/shm.h> 0026 0027 class TestXcbSizeHints; 0028 0029 namespace KWin 0030 { 0031 0032 namespace Xcb 0033 { 0034 0035 typedef xcb_window_t WindowId; 0036 0037 uint32_t KWIN_EXPORT toXNative(qreal value); 0038 QRect KWIN_EXPORT toXNative(const QRectF &value); 0039 qreal KWIN_EXPORT fromXNative(int value); 0040 QRectF KWIN_EXPORT fromXNative(const QRect &value); 0041 QSizeF KWIN_EXPORT fromXNative(const QSize &value); 0042 0043 /** Floors a given value to using the scale as a base 0044 * Use when flooring to ints from Xwayland 0045 * i.e floor(a/scale) * scale 0046 */ 0047 QRectF KWIN_EXPORT nativeFloor(const QRectF &value); 0048 0049 // forward declaration of methods 0050 static void defineCursor(xcb_window_t window, xcb_cursor_t cursor); 0051 static void setInputFocus(xcb_window_t window, uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = xTime()); 0052 static void moveWindow(xcb_window_t window, const QPoint &pos); 0053 static void moveWindow(xcb_window_t window, uint32_t x, uint32_t y); 0054 static void lowerWindow(xcb_window_t window); 0055 static void selectInput(xcb_window_t window, uint32_t events); 0056 0057 /** 0058 * @brief Variadic template to wrap an xcb request. 0059 * 0060 * This struct is part of the generic implementation to wrap xcb requests 0061 * and fetching their reply. Each request is represented by two templated 0062 * elements: WrapperData and Wrapper. 0063 * 0064 * The WrapperData defines the following types: 0065 * @li reply_type of the xcb request 0066 * @li cookie_type of the xcb request 0067 * @li function pointer type for the xcb request 0068 * @li function pointer type for the reply 0069 * This uses variadic template arguments thus it can be used to specify any 0070 * xcb request. 0071 * 0072 * As the WrapperData does not specify the actual function pointers one needs 0073 * to derive another struct which specifies the function pointer requestFunc and 0074 * the function pointer replyFunc as static constexpr of type reply_func and 0075 * reply_type respectively. E.g. for the command xcb_get_geometry: 0076 * @code 0077 * struct GeometryData : public WrapperData< xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, xcb_drawable_t > 0078 * { 0079 * static constexpr request_func requestFunc = &xcb_get_geometry_unchecked; 0080 * static constexpr reply_func replyFunc = &xcb_get_geometry_reply; 0081 * }; 0082 * @endcode 0083 * 0084 * To simplify this definition the macro XCB_WRAPPER_DATA is provided. 0085 * For the same xcb command this looks like this: 0086 * @code 0087 * XCB_WRAPPER_DATA(GeometryData, xcb_get_geometry, xcb_drawable_t) 0088 * @endcode 0089 * 0090 * The derived WrapperData has to be passed as first template argument to Wrapper. The other 0091 * template arguments of Wrapper are the same variadic template arguments as passed into 0092 * WrapperData. This is ensured at compile time and will cause a compile error in case there 0093 * is a mismatch of the variadic template arguments passed to WrapperData and Wrapper. 0094 * Passing another type than a struct derived from WrapperData to Wrapper will result in a 0095 * compile error. The following code snippets won't compile: 0096 * @code 0097 * XCB_WRAPPER_DATA(GeometryData, xcb_get_geometry, xcb_drawable_t) 0098 * // fails with "static assertion failed: Argument miss-match between Wrapper and WrapperData" 0099 * class IncorrectArguments : public Wrapper<GeometryData, uint8_t> 0100 * { 0101 * public: 0102 * IncorrectArguments() = default; 0103 * IncorrectArguments(xcb_window_t window) : Wrapper<GeometryData, uint8_t>(window) {} 0104 * }; 0105 * 0106 * // fails with "static assertion failed: Data template argument must be derived from WrapperData" 0107 * class WrapperDataDirectly : public Wrapper<WrapperData<xcb_get_geometry_reply_t, xcb_get_geometry_request_t, xcb_drawable_t>, xcb_drawable_t> 0108 * { 0109 * public: 0110 * WrapperDataDirectly() = default; 0111 * WrapperDataDirectly(xcb_window_t window) : Wrapper<WrapperData<xcb_get_geometry_reply_t, xcb_get_geometry_request_t, xcb_drawable_t>, xcb_drawable_t>(window) {} 0112 * }; 0113 * 0114 * // fails with "static assertion failed: Data template argument must be derived from WrapperData" 0115 * struct FakeWrapperData 0116 * { 0117 * typedef xcb_get_geometry_reply_t reply_type; 0118 * typedef xcb_get_geometry_cookie_t cookie_type; 0119 * typedef std::tuple<xcb_drawable_t> argument_types; 0120 * typedef cookie_type (*request_func)(xcb_connection_t*, xcb_drawable_t); 0121 * typedef reply_type *(*reply_func)(xcb_connection_t*, cookie_type, xcb_generic_error_t**); 0122 * static constexpr std::size_t argumentCount = 1; 0123 * static constexpr request_func requestFunc = &xcb_get_geometry_unchecked; 0124 * static constexpr reply_func replyFunc = &xcb_get_geometry_reply; 0125 * }; 0126 * class NotDerivedFromWrapperData : public Wrapper<FakeWrapperData, xcb_drawable_t> 0127 * { 0128 * public: 0129 * NotDerivedFromWrapperData() = default; 0130 * NotDerivedFromWrapperData(xcb_window_t window) : Wrapper<FakeWrapperData, xcb_drawable_t>(window) {} 0131 * }; 0132 * @endcode 0133 * 0134 * The Wrapper provides an easy to use RAII API which calls the WrapperData's requestFunc in 0135 * the ctor and fetches the reply the first time it is used. In addition the dtor takes care 0136 * of freeing the reply if it got fetched, otherwise it discards the reply. The Wrapper can 0137 * be used as if it were the reply_type directly. 0138 * 0139 * There are several command wrappers defined which either subclass Wrapper to add methods to 0140 * simplify the usage of the result_type or use a typedef. To add a new typedef one can use the 0141 * macro XCB_WRAPPER which creates the WrapperData struct as XCB_WRAPPER_DATA does and the 0142 * typedef. E.g: 0143 * @code 0144 * XCB_WRAPPER(Geometry, xcb_get_geometry, xcb_drawable_t) 0145 * @endcode 0146 * 0147 * creates a typedef Geometry and the struct GeometryData. 0148 * 0149 * Overall this allows to simplify the Xcb usage. For example consider the 0150 * following xcb code snippet: 0151 * @code 0152 * xcb_window_t w; // some window 0153 * xcb_connection_t *c = connection(); 0154 * const xcb_get_geometry_cookie_t cookie = xcb_get_geometry_unchecked(c, w); 0155 * // do other stuff 0156 * xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(c, cookie, nullptr); 0157 * if (reply) { 0158 * reply->x; // do something with the geometry 0159 * } 0160 * free(reply); 0161 * @endcode 0162 * 0163 * With the help of the Wrapper class this can be simplified to: 0164 * @code 0165 * xcb_window_t w; // some window 0166 * Xcb::Geometry geo(w); 0167 * if (!geo.isNull()) { 0168 * geo->x; // do something with the geometry 0169 * } 0170 * @endcode 0171 * 0172 * @see XCB_WRAPPER_DATA 0173 * @see XCB_WRAPPER 0174 * @see Wrapper 0175 * @see WindowAttributes 0176 * @see OverlayWindow 0177 * @see WindowGeometry 0178 * @see Tree 0179 * @see CurrentInput 0180 * @see TransientFor 0181 */ 0182 template<typename Reply, 0183 typename Cookie, 0184 typename... Args> 0185 struct WrapperData 0186 { 0187 /** 0188 * @brief The type returned by the xcb reply function. 0189 */ 0190 typedef Reply reply_type; 0191 /** 0192 * @brief The type returned by the xcb request function. 0193 */ 0194 typedef Cookie cookie_type; 0195 /** 0196 * @brief Variadic arguments combined as a std::tuple. 0197 * @internal Used for verifying the arguments. 0198 */ 0199 typedef std::tuple<Args...> argument_types; 0200 /** 0201 * @brief The function pointer definition for the xcb request function. 0202 */ 0203 typedef Cookie (*request_func)(xcb_connection_t *, Args...); 0204 /** 0205 * @brief The function pointer definition for the xcb reply function. 0206 */ 0207 typedef Reply *(*reply_func)(xcb_connection_t *, Cookie, xcb_generic_error_t **); 0208 /** 0209 * @brief Number of variadic arguments. 0210 * @internal Used for verifying the arguments. 0211 */ 0212 static constexpr std::size_t argumentCount = sizeof...(Args); 0213 }; 0214 0215 /** 0216 * @brief Partial template specialization for WrapperData with no further arguments. 0217 * 0218 * This will be used for xcb requests just taking the xcb_connection_t* argument. 0219 */ 0220 template<typename Reply, 0221 typename Cookie> 0222 struct WrapperData<Reply, Cookie> 0223 { 0224 typedef Reply reply_type; 0225 typedef Cookie cookie_type; 0226 typedef std::tuple<> argument_types; 0227 typedef Cookie (*request_func)(xcb_connection_t *); 0228 typedef Reply *(*reply_func)(xcb_connection_t *, Cookie, xcb_generic_error_t **); 0229 static constexpr std::size_t argumentCount = 0; 0230 }; 0231 0232 /** 0233 * @brief Abstract base class for the wrapper. 0234 * 0235 * This class contains the complete functionality of the Wrapper. It's only an abstract 0236 * base class to provide partial template specialization for more specific constructors. 0237 */ 0238 template<typename Data> 0239 class AbstractWrapper 0240 { 0241 public: 0242 typedef typename Data::cookie_type Cookie; 0243 typedef typename Data::reply_type Reply; 0244 virtual ~AbstractWrapper() 0245 { 0246 cleanup(); 0247 } 0248 inline AbstractWrapper &operator=(const AbstractWrapper &other) 0249 { 0250 if (this != &other) { 0251 // if we had managed a reply, free it 0252 cleanup(); 0253 // copy members 0254 m_retrieved = other.m_retrieved; 0255 m_cookie = other.m_cookie; 0256 m_window = other.m_window; 0257 m_reply = other.m_reply; 0258 // take over the responsibility for the reply pointer 0259 takeFromOther(const_cast<AbstractWrapper &>(other)); 0260 } 0261 return *this; 0262 } 0263 0264 inline const Reply *operator->() 0265 { 0266 getReply(); 0267 return m_reply; 0268 } 0269 inline bool isNull() 0270 { 0271 getReply(); 0272 return m_reply == nullptr; 0273 } 0274 inline bool isNull() const 0275 { 0276 const_cast<AbstractWrapper *>(this)->getReply(); 0277 return m_reply == NULL; 0278 } 0279 inline operator bool() 0280 { 0281 return !isNull(); 0282 } 0283 inline operator bool() const 0284 { 0285 return !isNull(); 0286 } 0287 inline const Reply *data() 0288 { 0289 getReply(); 0290 return m_reply; 0291 } 0292 inline const Reply *data() const 0293 { 0294 const_cast<AbstractWrapper *>(this)->getReply(); 0295 return m_reply; 0296 } 0297 inline WindowId window() const 0298 { 0299 return m_window; 0300 } 0301 inline bool isRetrieved() const 0302 { 0303 return m_retrieved; 0304 } 0305 /** 0306 * Returns the value of the reply pointer referenced by this object. The reply pointer of 0307 * this object will be reset to null. Calling any method which requires the reply to be valid 0308 * will crash. 0309 * 0310 * Callers of this function take ownership of the pointer. 0311 */ 0312 inline Reply *take() 0313 { 0314 getReply(); 0315 Reply *ret = m_reply; 0316 m_reply = nullptr; 0317 m_window = XCB_WINDOW_NONE; 0318 return ret; 0319 } 0320 0321 protected: 0322 AbstractWrapper() 0323 : m_retrieved(false) 0324 , m_window(XCB_WINDOW_NONE) 0325 , m_reply(nullptr) 0326 { 0327 m_cookie.sequence = 0; 0328 } 0329 explicit AbstractWrapper(WindowId window, Cookie cookie) 0330 : m_retrieved(false) 0331 , m_cookie(cookie) 0332 , m_window(window) 0333 , m_reply(nullptr) 0334 { 0335 } 0336 explicit AbstractWrapper(const AbstractWrapper &other) 0337 : m_retrieved(other.m_retrieved) 0338 , m_cookie(other.m_cookie) 0339 , m_window(other.m_window) 0340 , m_reply(nullptr) 0341 { 0342 takeFromOther(const_cast<AbstractWrapper &>(other)); 0343 } 0344 void getReply() 0345 { 0346 if (m_retrieved || !m_cookie.sequence) { 0347 return; 0348 } 0349 m_reply = Data::replyFunc(connection(), m_cookie, nullptr); 0350 m_retrieved = true; 0351 } 0352 0353 private: 0354 inline void cleanup() 0355 { 0356 if (!m_retrieved && m_cookie.sequence) { 0357 xcb_discard_reply(connection(), m_cookie.sequence); 0358 } else if (m_reply) { 0359 free(m_reply); 0360 } 0361 } 0362 inline void takeFromOther(AbstractWrapper &other) 0363 { 0364 if (m_retrieved) { 0365 m_reply = other.take(); 0366 } else { 0367 // ensure that other object doesn't try to get the reply or discards it in the dtor 0368 other.m_retrieved = true; 0369 other.m_window = XCB_WINDOW_NONE; 0370 } 0371 } 0372 bool m_retrieved; 0373 Cookie m_cookie; 0374 WindowId m_window; 0375 Reply *m_reply; 0376 }; 0377 0378 /** 0379 * @brief Template to compare the arguments of two std::tuple. 0380 * 0381 * @internal Used by static_assert in Wrapper 0382 */ 0383 template<typename T1, typename T2, std::size_t I> 0384 struct tupleCompare 0385 { 0386 typedef typename std::tuple_element<I, T1>::type tuple1Type; 0387 typedef typename std::tuple_element<I, T2>::type tuple2Type; 0388 /** 0389 * @c true if both tuple have the same arguments, @c false otherwise. 0390 */ 0391 static constexpr bool value = std::is_same<tuple1Type, tuple2Type>::value && tupleCompare<T1, T2, I - 1>::value; 0392 }; 0393 0394 /** 0395 * @brief Recursive template case for first tuple element. 0396 */ 0397 template<typename T1, typename T2> 0398 struct tupleCompare<T1, T2, 0> 0399 { 0400 typedef typename std::tuple_element<0, T1>::type tuple1Type; 0401 typedef typename std::tuple_element<0, T2>::type tuple2Type; 0402 static constexpr bool value = std::is_same<tuple1Type, tuple2Type>::value; 0403 }; 0404 0405 /** 0406 * @brief Wrapper taking a WrapperData as first template argument and xcb request args as variadic args. 0407 */ 0408 template<typename Data, typename... Args> 0409 class Wrapper : public AbstractWrapper<Data> 0410 { 0411 public: 0412 static_assert(!std::is_same<Data, Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, Args...>>::value, 0413 "Data template argument must be derived from WrapperData"); 0414 static_assert(std::is_base_of<Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, Args...>, Data>::value, 0415 "Data template argument must be derived from WrapperData"); 0416 static_assert(sizeof...(Args) == Data::argumentCount, 0417 "Wrapper and WrapperData need to have same template argument count"); 0418 static_assert(tupleCompare<std::tuple<Args...>, typename Data::argument_types, sizeof...(Args) - 1>::value, 0419 "Argument miss-match between Wrapper and WrapperData"); 0420 Wrapper() = default; 0421 explicit Wrapper(Args... args) 0422 : AbstractWrapper<Data>(XCB_WINDOW_NONE, Data::requestFunc(connection(), args...)) 0423 { 0424 } 0425 explicit Wrapper(xcb_window_t w, Args... args) 0426 : AbstractWrapper<Data>(w, Data::requestFunc(connection(), args...)) 0427 { 0428 } 0429 }; 0430 0431 /** 0432 * @brief Template specialization for xcb_window_t being first variadic argument. 0433 */ 0434 template<typename Data, typename... Args> 0435 class Wrapper<Data, xcb_window_t, Args...> : public AbstractWrapper<Data> 0436 { 0437 public: 0438 static_assert(!std::is_same<Data, Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, xcb_window_t, Args...>>::value, 0439 "Data template argument must be derived from WrapperData"); 0440 static_assert(std::is_base_of<Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, xcb_window_t, Args...>, Data>::value, 0441 "Data template argument must be derived from WrapperData"); 0442 static_assert(sizeof...(Args) + 1 == Data::argumentCount, 0443 "Wrapper and WrapperData need to have same template argument count"); 0444 static_assert(tupleCompare<std::tuple<xcb_window_t, Args...>, typename Data::argument_types, sizeof...(Args)>::value, 0445 "Argument miss-match between Wrapper and WrapperData"); 0446 Wrapper() = default; 0447 explicit Wrapper(xcb_window_t w, Args... args) 0448 : AbstractWrapper<Data>(w, Data::requestFunc(connection(), w, args...)) 0449 { 0450 } 0451 }; 0452 0453 /** 0454 * @brief Template specialization for no variadic arguments. 0455 * 0456 * It's needed to prevent ambiguous constructors being generated. 0457 */ 0458 template<typename Data> 0459 class Wrapper<Data> : public AbstractWrapper<Data> 0460 { 0461 public: 0462 static_assert(!std::is_same<Data, Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type>>::value, 0463 "Data template argument must be derived from WrapperData"); 0464 static_assert(std::is_base_of<Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type>, Data>::value, 0465 "Data template argument must be derived from WrapperData"); 0466 static_assert(Data::argumentCount == 0, "Wrapper for no arguments constructed with WrapperData with arguments"); 0467 explicit Wrapper() 0468 : AbstractWrapper<Data>(XCB_WINDOW_NONE, Data::requestFunc(connection())) 0469 { 0470 } 0471 }; 0472 0473 class Atom 0474 { 0475 public: 0476 explicit Atom(const QByteArray &name, bool onlyIfExists = false, xcb_connection_t *c = connection()) 0477 : m_connection(c) 0478 , m_retrieved(false) 0479 , m_cookie(xcb_intern_atom_unchecked(m_connection, onlyIfExists, name.length(), name.constData())) 0480 , m_atom(XCB_ATOM_NONE) 0481 , m_name(name) 0482 { 0483 } 0484 Atom() = delete; 0485 Atom(const Atom &) = delete; 0486 0487 ~Atom() 0488 { 0489 if (!m_retrieved && m_cookie.sequence) { 0490 xcb_discard_reply(m_connection, m_cookie.sequence); 0491 } 0492 } 0493 0494 operator xcb_atom_t() const 0495 { 0496 (const_cast<Atom *>(this))->getReply(); 0497 return m_atom; 0498 } 0499 bool isValid() 0500 { 0501 getReply(); 0502 return m_atom != XCB_ATOM_NONE; 0503 } 0504 bool isValid() const 0505 { 0506 (const_cast<Atom *>(this))->getReply(); 0507 return m_atom != XCB_ATOM_NONE; 0508 } 0509 0510 inline const QByteArray &name() const 0511 { 0512 return m_name; 0513 } 0514 0515 void getReply() 0516 { 0517 if (m_retrieved || !m_cookie.sequence) { 0518 return; 0519 } 0520 UniqueCPtr<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr)); 0521 if (reply) { 0522 m_atom = reply->atom; 0523 } 0524 m_retrieved = true; 0525 } 0526 0527 private: 0528 xcb_connection_t *m_connection; 0529 bool m_retrieved; 0530 xcb_intern_atom_cookie_t m_cookie; 0531 xcb_atom_t m_atom; 0532 QByteArray m_name; 0533 }; 0534 0535 /** 0536 * @brief Macro to create the WrapperData subclass. 0537 * 0538 * Creates a struct with name @p __NAME__ for the xcb request identified by @p __REQUEST__. 0539 * The variadic arguments are used to pass as template arguments to the WrapperData. 0540 * 0541 * The @p __REQUEST__ is the common prefix of the cookie type, reply type, request function and 0542 * reply function. E.g. "xcb_get_geometry" is used to create: 0543 * @li cookie type xcb_get_geometry_cookie_t 0544 * @li reply type xcb_get_geometry_reply_t 0545 * @li request function pointer xcb_get_geometry_unchecked 0546 * @li reply function pointer xcb_get_geometry_reply 0547 * 0548 * @param __NAME__ The name of the WrapperData subclass 0549 * @param __REQUEST__ The name of the xcb request, e.g. xcb_get_geometry 0550 * @param __VA_ARGS__ The variadic template arguments, e.g. xcb_drawable_t 0551 * @see XCB_WRAPPER 0552 */ 0553 #define XCB_WRAPPER_DATA(__NAME__, __REQUEST__, ...) \ 0554 struct __NAME__ : public WrapperData<__REQUEST__##_reply_t, __REQUEST__##_cookie_t, __VA_ARGS__> \ 0555 { \ 0556 static constexpr request_func requestFunc = &__REQUEST__##_unchecked; \ 0557 static constexpr reply_func replyFunc = &__REQUEST__##_reply; \ 0558 }; 0559 0560 /** 0561 * @brief Macro to create Wrapper typedef and WrapperData. 0562 * 0563 * This macro expands the XCB_WRAPPER_DATA macro and creates an additional 0564 * typedef for Wrapper with name @p __NAME__. The created WrapperData is also derived 0565 * from @p __NAME__ with "Data" as suffix. 0566 * 0567 * @param __NAME__ The name for the Wrapper typedef 0568 * @param __REQUEST__ The name of the xcb request, passed to XCB_WRAPPER_DATA 0569 * @param __VA_ARGS__ The variadic template arguments for Wrapper and WrapperData 0570 * @see XCB_WRAPPER_DATA 0571 */ 0572 #define XCB_WRAPPER(__NAME__, __REQUEST__, ...) \ 0573 XCB_WRAPPER_DATA(__NAME__##Data, __REQUEST__, __VA_ARGS__) \ 0574 typedef Wrapper<__NAME__##Data, __VA_ARGS__> __NAME__; 0575 0576 XCB_WRAPPER(WindowAttributes, xcb_get_window_attributes, xcb_window_t) 0577 XCB_WRAPPER(OverlayWindow, xcb_composite_get_overlay_window, xcb_window_t) 0578 0579 XCB_WRAPPER_DATA(GeometryData, xcb_get_geometry, xcb_drawable_t) 0580 class WindowGeometry : public Wrapper<GeometryData, xcb_window_t> 0581 { 0582 public: 0583 WindowGeometry() 0584 : Wrapper<GeometryData, xcb_window_t>() 0585 { 0586 } 0587 explicit WindowGeometry(xcb_window_t window) 0588 : Wrapper<GeometryData, xcb_window_t>(window) 0589 { 0590 } 0591 0592 inline QRectF rect() 0593 { 0594 const xcb_get_geometry_reply_t *geometry = data(); 0595 if (!geometry) { 0596 return QRect(); 0597 } 0598 return QRectF(Xcb::fromXNative(geometry->x), Xcb::fromXNative(geometry->y), Xcb::fromXNative(geometry->width), Xcb::fromXNative(geometry->height)); 0599 } 0600 0601 inline QSizeF size() 0602 { 0603 const xcb_get_geometry_reply_t *geometry = data(); 0604 if (!geometry) { 0605 return QSize(); 0606 } 0607 return QSizeF(Xcb::fromXNative(geometry->width), Xcb::fromXNative(geometry->height)); 0608 } 0609 }; 0610 0611 XCB_WRAPPER_DATA(TreeData, xcb_query_tree, xcb_window_t) 0612 class Tree : public Wrapper<TreeData, xcb_window_t> 0613 { 0614 public: 0615 explicit Tree(WindowId window) 0616 : Wrapper<TreeData, xcb_window_t>(window) 0617 { 0618 } 0619 0620 inline WindowId *children() 0621 { 0622 if (isNull() || data()->children_len == 0) { 0623 return nullptr; 0624 } 0625 return xcb_query_tree_children(data()); 0626 } 0627 inline xcb_window_t parent() 0628 { 0629 if (isNull()) { 0630 return XCB_WINDOW_NONE; 0631 } 0632 return (*this)->parent; 0633 } 0634 }; 0635 0636 XCB_WRAPPER(Pointer, xcb_query_pointer, xcb_window_t) 0637 0638 struct CurrentInputData : public WrapperData<xcb_get_input_focus_reply_t, xcb_get_input_focus_cookie_t> 0639 { 0640 static constexpr request_func requestFunc = &xcb_get_input_focus_unchecked; 0641 static constexpr reply_func replyFunc = &xcb_get_input_focus_reply; 0642 }; 0643 0644 class CurrentInput : public Wrapper<CurrentInputData> 0645 { 0646 public: 0647 CurrentInput() 0648 : Wrapper<CurrentInputData>() 0649 { 0650 } 0651 0652 inline xcb_window_t window() 0653 { 0654 if (isNull()) { 0655 return XCB_WINDOW_NONE; 0656 } 0657 return (*this)->focus; 0658 } 0659 }; 0660 0661 struct QueryKeymapData : public WrapperData<xcb_query_keymap_reply_t, xcb_query_keymap_cookie_t> 0662 { 0663 static constexpr request_func requestFunc = &xcb_query_keymap_unchecked; 0664 static constexpr reply_func replyFunc = &xcb_query_keymap_reply; 0665 }; 0666 0667 class QueryKeymap : public Wrapper<QueryKeymapData> 0668 { 0669 public: 0670 QueryKeymap() 0671 : Wrapper<QueryKeymapData>() 0672 { 0673 } 0674 }; 0675 0676 struct ModifierMappingData : public WrapperData<xcb_get_modifier_mapping_reply_t, xcb_get_modifier_mapping_cookie_t> 0677 { 0678 static constexpr request_func requestFunc = &xcb_get_modifier_mapping_unchecked; 0679 static constexpr reply_func replyFunc = &xcb_get_modifier_mapping_reply; 0680 }; 0681 0682 class ModifierMapping : public Wrapper<ModifierMappingData> 0683 { 0684 public: 0685 ModifierMapping() 0686 : Wrapper<ModifierMappingData>() 0687 { 0688 } 0689 0690 inline xcb_keycode_t *keycodes() 0691 { 0692 if (isNull()) { 0693 return nullptr; 0694 } 0695 return xcb_get_modifier_mapping_keycodes(data()); 0696 } 0697 inline int size() 0698 { 0699 if (isNull()) { 0700 return 0; 0701 } 0702 return xcb_get_modifier_mapping_keycodes_length(data()); 0703 } 0704 }; 0705 0706 XCB_WRAPPER_DATA(PropertyData, xcb_get_property, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t) 0707 class Property : public Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t> 0708 { 0709 public: 0710 Property() 0711 : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>() 0712 , m_type(XCB_ATOM_NONE) 0713 { 0714 } 0715 Property(const Property &other) 0716 : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>(other) 0717 , m_type(other.m_type) 0718 { 0719 } 0720 explicit Property(uint8_t _delete, xcb_window_t window, xcb_atom_t property, xcb_atom_t type, uint32_t long_offset, uint32_t long_length) 0721 : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>(window, _delete, window, property, type, long_offset, long_length) 0722 , m_type(type) 0723 { 0724 } 0725 Property &operator=(const Property &other) 0726 { 0727 Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>::operator=(other); 0728 m_type = other.m_type; 0729 return *this; 0730 } 0731 0732 /** 0733 * @brief Overloaded method for convenience. 0734 * 0735 * Uses the type which got passed into the ctor and derives the format from the sizeof(T). 0736 * Note: for the automatic format detection the size of the type T may not vary between 0737 * architectures. Thus one needs to use e.g. uint32_t instead of long. In general all xcb 0738 * data types can be used, all Xlib data types can not be used. 0739 * 0740 * @param defaultValue The default value to return in case of error 0741 * @param ok Set to @c false in case of error, @c true in case of success 0742 * @return The read value or @p defaultValue in error case 0743 */ 0744 template<typename T> 0745 inline typename std::enable_if<!std::is_pointer<T>::value, T>::type value(T defaultValue = T(), bool *ok = nullptr) 0746 { 0747 return value<T>(sizeof(T) * 8, m_type, defaultValue, ok); 0748 } 0749 /** 0750 * @brief Reads the property as a POD type. 0751 * 0752 * Returns the first value of the property data. In case of @p format or @p type mismatch 0753 * the @p defaultValue is returned. The optional argument @p ok is set 0754 * to @c false in case of error and to @c true in case of successful reading of 0755 * the property. 0756 * 0757 * @param format The expected format of the property value, e.g. 32 for XCB_ATOM_CARDINAL 0758 * @param type The expected type of the property value, e.g. XCB_ATOM_CARDINAL 0759 * @param defaultValue The default value to return in case of error 0760 * @param ok Set to @c false in case of error, @c true in case of success 0761 * @return The read value or @p defaultValue in error case 0762 */ 0763 template<typename T> 0764 inline typename std::enable_if<!std::is_pointer<T>::value, T>::type value(uint8_t format, xcb_atom_t type, T defaultValue = T(), bool *ok = nullptr) 0765 { 0766 T *reply = value<T *>(format, type, nullptr, ok); 0767 if (!reply) { 0768 return defaultValue; 0769 } 0770 return reply[0]; 0771 } 0772 /** 0773 * @brief Overloaded method for convenience. 0774 * 0775 * Uses the type which got passed into the ctor and derives the format from the sizeof(T). 0776 * Note: for the automatic format detection the size of the type T may not vary between 0777 * architectures. Thus one needs to use e.g. uint32_t instead of long. In general all xcb 0778 * data types can be used, all Xlib data types can not be used. 0779 * 0780 * @param defaultValue The default value to return in case of error 0781 * @param ok Set to @c false in case of error, @c true in case of success 0782 * @return The read value or @p defaultValue in error case 0783 */ 0784 template<typename T> 0785 inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(T defaultValue = nullptr, bool *ok = nullptr) 0786 { 0787 return value<T>(sizeof(typename std::remove_pointer<T>::type) * 8, m_type, defaultValue, ok); 0788 } 0789 /** 0790 * @brief Reads the property as an array of T. 0791 * 0792 * This method is an overload for the case that T is a pointer type. 0793 * 0794 * Return the property value casted to the pointer type T. In case of @p format 0795 * or @p type mismatch the @p defaultValue is returned. Also if the value length 0796 * is @c 0 the @p defaultValue is returned. The optional argument @p ok is set 0797 * to @c false in case of error and to @c true in case of successful reading of 0798 * the property. Ok will always be true if the property exists and has been 0799 * successfully read, even in the case the property is empty and its length is 0 0800 * 0801 * @param format The expected format of the property value, e.g. 32 for XCB_ATOM_CARDINAL 0802 * @param type The expected type of the property value, e.g. XCB_ATOM_CARDINAL 0803 * @param defaultValue The default value to return in case of error 0804 * @param ok Set to @c false in case of error, @c true in case of success 0805 * @return The read value or @p defaultValue in error case 0806 */ 0807 template<typename T> 0808 inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(uint8_t format, xcb_atom_t type, T defaultValue = nullptr, bool *ok = nullptr) 0809 { 0810 if (ok) { 0811 *ok = false; 0812 } 0813 const PropertyData::reply_type *reply = data(); 0814 if (!reply) { 0815 return defaultValue; 0816 } 0817 if (reply->type != type) { 0818 return defaultValue; 0819 } 0820 if (reply->format != format) { 0821 return defaultValue; 0822 } 0823 0824 if (ok) { 0825 *ok = true; 0826 } 0827 if (xcb_get_property_value_length(reply) == 0) { 0828 return defaultValue; 0829 } 0830 0831 return reinterpret_cast<T>(xcb_get_property_value(reply)); 0832 } 0833 /** 0834 * @brief Reads the property as string and returns a QByteArray. 0835 * 0836 * In case of error this method returns a null QByteArray. 0837 */ 0838 inline QByteArray toByteArray(uint8_t format = 8, xcb_atom_t type = XCB_ATOM_STRING, bool *ok = nullptr) 0839 { 0840 bool valueOk = false; 0841 const char *reply = value<const char *>(format, type, nullptr, &valueOk); 0842 if (ok) { 0843 *ok = valueOk; 0844 } 0845 0846 if (valueOk && !reply) { 0847 return QByteArray("", 0); // valid, not null, but empty data 0848 } else if (!valueOk) { 0849 return QByteArray(); // Property not found, data empty and null 0850 } 0851 return QByteArray(reply, xcb_get_property_value_length(data())); 0852 } 0853 /** 0854 * @brief Overloaded method for convenience. 0855 */ 0856 inline QByteArray toByteArray(bool *ok) 0857 { 0858 return toByteArray(8, m_type, ok); 0859 } 0860 /** 0861 * @brief Reads the property as a boolean value. 0862 * 0863 * If the property reply length is @c 1 the first element is interpreted as a boolean 0864 * value returning @c true for any value unequal to @c 0 and @c false otherwise. 0865 * 0866 * In case of error this method returns @c false. Thus it is not possible to distinguish 0867 * between error case and a read @c false value. Use the optional argument @p ok to 0868 * distinguish the error case. 0869 * 0870 * @param format Expected format. Defaults to 32. 0871 * @param type Expected type Defaults to XCB_ATOM_CARDINAL. 0872 * @param ok Set to @c false in case of error, @c true in case of success 0873 * @return bool The first element interpreted as a boolean value or @c false in error case 0874 * @see value 0875 */ 0876 inline bool toBool(uint8_t format = 32, xcb_atom_t type = XCB_ATOM_CARDINAL, bool *ok = nullptr) 0877 { 0878 bool *reply = value<bool *>(format, type, nullptr, ok); 0879 if (!reply) { 0880 return false; 0881 } 0882 if (data()->value_len != 1) { 0883 if (ok) { 0884 *ok = false; 0885 } 0886 return false; 0887 } 0888 return reply[0] != 0; 0889 } 0890 /** 0891 * @brief Overloaded method for convenience. 0892 */ 0893 inline bool toBool(bool *ok) 0894 { 0895 return toBool(32, m_type, ok); 0896 } 0897 0898 private: 0899 xcb_atom_t m_type; 0900 }; 0901 0902 class StringProperty : public Property 0903 { 0904 public: 0905 StringProperty() = default; 0906 explicit StringProperty(xcb_window_t w, xcb_atom_t p) 0907 : Property(false, w, p, XCB_ATOM_STRING, 0, 10000) 0908 { 0909 } 0910 operator QByteArray() 0911 { 0912 return toByteArray(); 0913 } 0914 }; 0915 0916 class TransientFor : public Property 0917 { 0918 public: 0919 explicit TransientFor(WindowId window) 0920 : Property(0, window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, 1) 0921 { 0922 } 0923 0924 /** 0925 * @brief Fill given window pointer with the WM_TRANSIENT_FOR property of a window. 0926 * @param prop WM_TRANSIENT_FOR property value. 0927 * @returns @c true on success, @c false otherwise 0928 */ 0929 inline bool getTransientFor(WindowId *prop) 0930 { 0931 WindowId *windows = value<WindowId *>(); 0932 if (!windows) { 0933 return false; 0934 } 0935 0936 *prop = *windows; 0937 return true; 0938 } 0939 }; 0940 0941 class GeometryHints 0942 { 0943 public: 0944 GeometryHints() = default; 0945 void init(xcb_window_t window) 0946 { 0947 Q_ASSERT(window); 0948 if (m_window) { 0949 // already initialized 0950 return; 0951 } 0952 m_window = window; 0953 fetch(); 0954 } 0955 void fetch() 0956 { 0957 if (!m_window) { 0958 return; 0959 } 0960 m_sizeHints = nullptr; 0961 m_hints = NormalHints(m_window); 0962 } 0963 void read() 0964 { 0965 m_sizeHints = m_hints.sizeHints(); 0966 } 0967 0968 bool hasPosition() const 0969 { 0970 return testFlag(NormalHints::SizeHints::UserPosition) || testFlag(NormalHints::SizeHints::ProgramPosition); 0971 } 0972 bool hasSize() const 0973 { 0974 return testFlag(NormalHints::SizeHints::UserSize) || testFlag(NormalHints::SizeHints::ProgramSize); 0975 } 0976 bool hasMinSize() const 0977 { 0978 return testFlag(NormalHints::SizeHints::MinSize); 0979 } 0980 bool hasMaxSize() const 0981 { 0982 return testFlag(NormalHints::SizeHints::MaxSize); 0983 } 0984 bool hasResizeIncrements() const 0985 { 0986 return testFlag(NormalHints::SizeHints::ResizeIncrements); 0987 } 0988 bool hasAspect() const 0989 { 0990 return testFlag(NormalHints::SizeHints::Aspect); 0991 } 0992 bool hasBaseSize() const 0993 { 0994 return testFlag(NormalHints::SizeHints::BaseSize); 0995 } 0996 bool hasWindowGravity() const 0997 { 0998 return testFlag(NormalHints::SizeHints::WindowGravity); 0999 } 1000 QSizeF maxSize() const 1001 { 1002 if (!hasMaxSize()) { 1003 return QSize(INT_MAX, INT_MAX); 1004 } 1005 const QSize size(std::max(m_sizeHints->maxWidth, 1), std::max(m_sizeHints->maxHeight, 1)); 1006 return fromXNative(size); 1007 } 1008 QSizeF minSize() const 1009 { 1010 if (!hasMinSize()) { 1011 // according to ICCCM 4.1.23 base size should be used as a fallback 1012 return baseSize(); 1013 } 1014 const QSize size(m_sizeHints->minWidth, m_sizeHints->minHeight); 1015 return fromXNative(size); 1016 } 1017 QSizeF baseSize() const 1018 { 1019 // Note: not using minSize as fallback 1020 if (!hasBaseSize()) { 1021 return QSize(0, 0); 1022 } 1023 const QSize size(m_sizeHints->baseWidth, m_sizeHints->baseHeight); 1024 return fromXNative(size); 1025 } 1026 QSizeF resizeIncrements() const 1027 { 1028 if (!hasResizeIncrements()) { 1029 return fromXNative(QSize(1, 1)); 1030 } 1031 return Xcb::fromXNative(QSize(std::max(m_sizeHints->widthInc, 1), std::max(m_sizeHints->heightInc, 1))); 1032 } 1033 xcb_gravity_t windowGravity() const 1034 { 1035 if (!hasWindowGravity()) { 1036 return XCB_GRAVITY_NORTH_WEST; 1037 } 1038 return xcb_gravity_t(m_sizeHints->winGravity); 1039 } 1040 QSize minAspect() const 1041 { 1042 if (!hasAspect()) { 1043 return QSize(1, INT_MAX); 1044 } 1045 // prevent division by zero 1046 return QSize(m_sizeHints->minAspect[0], std::max(m_sizeHints->minAspect[1], 1)); 1047 } 1048 QSize maxAspect() const 1049 { 1050 if (!hasAspect()) { 1051 return QSize(INT_MAX, 1); 1052 } 1053 // prevent division by zero 1054 return QSize(m_sizeHints->maxAspect[0], std::max(m_sizeHints->maxAspect[1], 1)); 1055 } 1056 1057 private: 1058 /** 1059 * NormalHints as specified in ICCCM 4.1.2.3. 1060 */ 1061 class NormalHints : public Property 1062 { 1063 public: 1064 struct SizeHints 1065 { 1066 enum Flags { 1067 UserPosition = 1, 1068 UserSize = 2, 1069 ProgramPosition = 4, 1070 ProgramSize = 8, 1071 MinSize = 16, 1072 MaxSize = 32, 1073 ResizeIncrements = 64, 1074 Aspect = 128, 1075 BaseSize = 256, 1076 WindowGravity = 512 1077 }; 1078 qint32 flags = 0; 1079 qint32 pad[4] = {0, 0, 0, 0}; 1080 qint32 minWidth = 0; 1081 qint32 minHeight = 0; 1082 qint32 maxWidth = 0; 1083 qint32 maxHeight = 0; 1084 qint32 widthInc = 0; 1085 qint32 heightInc = 0; 1086 qint32 minAspect[2] = {0, 0}; 1087 qint32 maxAspect[2] = {0, 0}; 1088 qint32 baseWidth = 0; 1089 qint32 baseHeight = 0; 1090 qint32 winGravity = 0; 1091 }; 1092 explicit NormalHints() 1093 : Property(){}; 1094 explicit NormalHints(WindowId window) 1095 : Property(0, window, XCB_ATOM_WM_NORMAL_HINTS, XCB_ATOM_WM_SIZE_HINTS, 0, 18) 1096 { 1097 } 1098 inline SizeHints *sizeHints() 1099 { 1100 return value<SizeHints *>(32, XCB_ATOM_WM_SIZE_HINTS, nullptr); 1101 } 1102 }; 1103 friend TestXcbSizeHints; 1104 bool testFlag(NormalHints::SizeHints::Flags flag) const 1105 { 1106 if (!m_window || !m_sizeHints) { 1107 return false; 1108 } 1109 return m_sizeHints->flags & flag; 1110 } 1111 xcb_window_t m_window = XCB_WINDOW_NONE; 1112 NormalHints m_hints; 1113 NormalHints::SizeHints *m_sizeHints = nullptr; 1114 }; 1115 1116 class MotifHints 1117 { 1118 public: 1119 MotifHints(xcb_atom_t atom) 1120 : m_atom(atom) 1121 { 1122 } 1123 void init(xcb_window_t window) 1124 { 1125 Q_ASSERT(window); 1126 if (m_window) { 1127 // already initialized 1128 return; 1129 } 1130 m_window = window; 1131 fetch(); 1132 } 1133 void fetch() 1134 { 1135 if (!m_window) { 1136 return; 1137 } 1138 m_hints = nullptr; 1139 m_prop = Property(0, m_window, m_atom, m_atom, 0, 5); 1140 } 1141 void read() 1142 { 1143 m_hints = m_prop.value<MwmHints *>(32, m_atom, nullptr); 1144 } 1145 bool hasDecoration() const 1146 { 1147 if (!m_window || !m_hints) { 1148 return false; 1149 } 1150 return m_hints->flags & uint32_t(Hints::Decorations); 1151 } 1152 bool noBorder() const 1153 { 1154 if (!hasDecoration()) { 1155 return false; 1156 } 1157 return !m_hints->decorations; 1158 } 1159 bool resize() const 1160 { 1161 return testFunction(Functions::Resize); 1162 } 1163 bool move() const 1164 { 1165 return testFunction(Functions::Move); 1166 } 1167 bool minimize() const 1168 { 1169 return testFunction(Functions::Minimize); 1170 } 1171 bool maximize() const 1172 { 1173 return testFunction(Functions::Maximize); 1174 } 1175 bool close() const 1176 { 1177 return testFunction(Functions::Close); 1178 } 1179 1180 private: 1181 struct MwmHints 1182 { 1183 uint32_t flags; 1184 uint32_t functions; 1185 uint32_t decorations; 1186 int32_t input_mode; 1187 uint32_t status; 1188 }; 1189 enum class Hints { 1190 Functions = (1L << 0), 1191 Decorations = (1L << 1) 1192 }; 1193 enum class Functions { 1194 All = (1L << 0), 1195 Resize = (1L << 1), 1196 Move = (1L << 2), 1197 Minimize = (1L << 3), 1198 Maximize = (1L << 4), 1199 Close = (1L << 5) 1200 }; 1201 bool testFunction(Functions flag) const 1202 { 1203 if (!m_window || !m_hints) { 1204 return true; 1205 } 1206 if (!(m_hints->flags & uint32_t(Hints::Functions))) { 1207 return true; 1208 } 1209 // if MWM_FUNC_ALL is set, other flags say what to turn _off_ 1210 const bool set_value = ((m_hints->functions & uint32_t(Functions::All)) == 0); 1211 if (m_hints->functions & uint32_t(flag)) { 1212 return set_value; 1213 } 1214 return !set_value; 1215 } 1216 xcb_window_t m_window = XCB_WINDOW_NONE; 1217 Property m_prop; 1218 xcb_atom_t m_atom; 1219 MwmHints *m_hints = nullptr; 1220 }; 1221 1222 namespace RandR 1223 { 1224 XCB_WRAPPER(ScreenInfo, xcb_randr_get_screen_info, xcb_window_t) 1225 1226 XCB_WRAPPER_DATA(ScreenResourcesData, xcb_randr_get_screen_resources, xcb_window_t) 1227 class ScreenResources : public Wrapper<ScreenResourcesData, xcb_window_t> 1228 { 1229 public: 1230 explicit ScreenResources(WindowId window) 1231 : Wrapper<ScreenResourcesData, xcb_window_t>(window) 1232 { 1233 } 1234 1235 inline xcb_randr_crtc_t *crtcs() 1236 { 1237 if (isNull()) { 1238 return nullptr; 1239 } 1240 return xcb_randr_get_screen_resources_crtcs(data()); 1241 } 1242 inline xcb_randr_mode_info_t *modes() 1243 { 1244 if (isNull()) { 1245 return nullptr; 1246 } 1247 return xcb_randr_get_screen_resources_modes(data()); 1248 } 1249 inline uint8_t *names() 1250 { 1251 if (isNull()) { 1252 return nullptr; 1253 } 1254 return xcb_randr_get_screen_resources_names(data()); 1255 } 1256 }; 1257 1258 XCB_WRAPPER_DATA(CrtcGammaData, xcb_randr_get_crtc_gamma, xcb_randr_crtc_t) 1259 class CrtcGamma : public Wrapper<CrtcGammaData, xcb_randr_crtc_t> 1260 { 1261 public: 1262 explicit CrtcGamma(xcb_randr_crtc_t c) 1263 : Wrapper<CrtcGammaData, xcb_randr_crtc_t>(c) 1264 { 1265 } 1266 1267 inline uint16_t *red() 1268 { 1269 return xcb_randr_get_crtc_gamma_red(data()); 1270 } 1271 inline uint16_t *green() 1272 { 1273 return xcb_randr_get_crtc_gamma_green(data()); 1274 } 1275 inline uint16_t *blue() 1276 { 1277 return xcb_randr_get_crtc_gamma_blue(data()); 1278 } 1279 }; 1280 1281 XCB_WRAPPER_DATA(CrtcInfoData, xcb_randr_get_crtc_info, xcb_randr_crtc_t, xcb_timestamp_t) 1282 class CrtcInfo : public Wrapper<CrtcInfoData, xcb_randr_crtc_t, xcb_timestamp_t> 1283 { 1284 public: 1285 CrtcInfo() = default; 1286 CrtcInfo(const CrtcInfo &) = default; 1287 explicit CrtcInfo(xcb_randr_crtc_t c, xcb_timestamp_t t) 1288 : Wrapper<CrtcInfoData, xcb_randr_crtc_t, xcb_timestamp_t>(c, t) 1289 { 1290 } 1291 1292 inline QRect rect() 1293 { 1294 const CrtcInfoData::reply_type *info = data(); 1295 if (!info || info->num_outputs == 0 || info->mode == XCB_NONE || info->status != XCB_RANDR_SET_CONFIG_SUCCESS) { 1296 return QRect(); 1297 } 1298 return QRect(info->x, info->y, info->width, info->height); 1299 } 1300 inline xcb_randr_output_t *outputs() 1301 { 1302 const CrtcInfoData::reply_type *info = data(); 1303 if (!info || info->num_outputs == 0 || info->mode == XCB_NONE || info->status != XCB_RANDR_SET_CONFIG_SUCCESS) { 1304 return nullptr; 1305 } 1306 return xcb_randr_get_crtc_info_outputs(info); 1307 } 1308 }; 1309 1310 XCB_WRAPPER_DATA(OutputInfoData, xcb_randr_get_output_info, xcb_randr_output_t, xcb_timestamp_t) 1311 class OutputInfo : public Wrapper<OutputInfoData, xcb_randr_output_t, xcb_timestamp_t> 1312 { 1313 public: 1314 OutputInfo() = default; 1315 OutputInfo(const OutputInfo &) = default; 1316 explicit OutputInfo(xcb_randr_output_t c, xcb_timestamp_t t) 1317 : Wrapper<OutputInfoData, xcb_randr_output_t, xcb_timestamp_t>(c, t) 1318 { 1319 } 1320 1321 inline QString name() 1322 { 1323 const OutputInfoData::reply_type *info = data(); 1324 if (!info || info->num_crtcs == 0 || info->num_modes == 0 || info->status != XCB_RANDR_SET_CONFIG_SUCCESS) { 1325 return QString(); 1326 } 1327 return QString::fromUtf8(reinterpret_cast<char *>(xcb_randr_get_output_info_name(info)), info->name_len); 1328 } 1329 }; 1330 1331 XCB_WRAPPER_DATA(CurrentResourcesData, xcb_randr_get_screen_resources_current, xcb_window_t) 1332 class CurrentResources : public Wrapper<CurrentResourcesData, xcb_window_t> 1333 { 1334 public: 1335 explicit CurrentResources(WindowId window) 1336 : Wrapper<CurrentResourcesData, xcb_window_t>(window) 1337 { 1338 } 1339 1340 inline xcb_randr_crtc_t *crtcs() 1341 { 1342 if (isNull()) { 1343 return nullptr; 1344 } 1345 return xcb_randr_get_screen_resources_current_crtcs(data()); 1346 } 1347 inline xcb_randr_mode_info_t *modes() 1348 { 1349 if (isNull()) { 1350 return nullptr; 1351 } 1352 return xcb_randr_get_screen_resources_current_modes(data()); 1353 } 1354 }; 1355 1356 XCB_WRAPPER(SetCrtcConfig, xcb_randr_set_crtc_config, xcb_randr_crtc_t, xcb_timestamp_t, xcb_timestamp_t, int16_t, int16_t, xcb_randr_mode_t, uint16_t, uint32_t, const xcb_randr_output_t *) 1357 1358 XCB_WRAPPER_DATA(OutputPropertyData, xcb_randr_get_output_property, xcb_randr_output_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t, uint8_t, uint8_t) 1359 /** 1360 * Get an output property. 1361 * @see Property for documentation of member functions 1362 */ 1363 class OutputProperty : public Wrapper<OutputPropertyData, xcb_randr_output_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t, uint8_t, uint8_t> 1364 { 1365 public: 1366 OutputProperty() = default; 1367 explicit OutputProperty(xcb_randr_output_t output, xcb_atom_t property, xcb_atom_t type, uint32_t offset, uint32_t length, uint8_t _delete, uint8_t pending) 1368 : Wrapper(output, property, type, offset, length, _delete, pending) 1369 , m_type(type) 1370 { 1371 } 1372 template<typename T> 1373 inline typename std::enable_if<!std::is_pointer<T>::value, T>::type value(T defaultValue = T(), bool *ok = nullptr) 1374 { 1375 T *reply = value<T *>(sizeof(T) * 8, m_type, nullptr, ok); 1376 if (!reply) { 1377 return defaultValue; 1378 } 1379 return reply[0]; 1380 } 1381 template<typename T> 1382 inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(T defaultValue = nullptr, bool *ok = nullptr) 1383 { 1384 return value<T>(sizeof(typename std::remove_pointer<T>::type) * 8, m_type, defaultValue, ok); 1385 } 1386 template<typename T> 1387 inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(uint8_t format, xcb_atom_t type, T defaultValue = nullptr, bool *ok = nullptr) 1388 { 1389 if (ok) { 1390 *ok = false; 1391 } 1392 const OutputPropertyData::reply_type *reply = data(); 1393 if (!reply) { 1394 return defaultValue; 1395 } 1396 if (reply->type != type) { 1397 return defaultValue; 1398 } 1399 if (reply->format != format) { 1400 return defaultValue; 1401 } 1402 1403 if (ok) { 1404 *ok = true; 1405 } 1406 if (xcb_randr_get_output_property_data_length(reply) == 0) { 1407 return defaultValue; 1408 } 1409 1410 return reinterpret_cast<T>(xcb_randr_get_output_property_data(reply)); 1411 } 1412 inline QByteArray toByteArray(uint8_t format = 8, xcb_atom_t type = XCB_ATOM_STRING, bool *ok = nullptr) 1413 { 1414 bool valueOk = false; 1415 const char *reply = value<const char *>(format, type, nullptr, &valueOk); 1416 if (ok) { 1417 *ok = valueOk; 1418 } 1419 1420 if (valueOk && !reply) { 1421 return QByteArray("", 0); // valid, not null, but empty data 1422 } else if (!valueOk) { 1423 return QByteArray(); // Property not found, data empty and null 1424 } 1425 return QByteArray(reply, xcb_randr_get_output_property_data_length(data())); 1426 } 1427 inline QByteArray toByteArray(bool *ok) 1428 { 1429 return toByteArray(8, m_type, ok); 1430 } 1431 inline bool toBool(uint8_t format = 32, xcb_atom_t type = XCB_ATOM_CARDINAL, bool *ok = nullptr) 1432 { 1433 bool *reply = value<bool *>(format, type, nullptr, ok); 1434 if (!reply) { 1435 return false; 1436 } 1437 if (data()->length != 1) { 1438 if (ok) { 1439 *ok = false; 1440 } 1441 return false; 1442 } 1443 return reply[0] != 0; 1444 } 1445 inline bool toBool(bool *ok) 1446 { 1447 return toBool(32, m_type, ok); 1448 } 1449 1450 private: 1451 xcb_atom_t m_type; 1452 }; 1453 } 1454 1455 class ExtensionData 1456 { 1457 public: 1458 ExtensionData(); 1459 int version; 1460 int eventBase; 1461 int errorBase; 1462 int majorOpcode; 1463 bool present; 1464 QByteArray name; 1465 QList<QByteArray> opCodes; 1466 QList<QByteArray> errorCodes; 1467 }; 1468 1469 class KWIN_EXPORT Extensions 1470 { 1471 public: 1472 bool isShapeAvailable() const 1473 { 1474 return m_shape.version > 0; 1475 } 1476 bool isShapeInputAvailable() const; 1477 int shapeNotifyEvent() const; 1478 bool hasShape(xcb_window_t w) const; 1479 bool isRandrAvailable() const 1480 { 1481 return m_randr.present; 1482 } 1483 int randrNotifyEvent() const; 1484 bool isDamageAvailable() const 1485 { 1486 return m_damage.present; 1487 } 1488 int damageNotifyEvent() const; 1489 bool isCompositeAvailable() const 1490 { 1491 return m_composite.version > 0; 1492 } 1493 bool isCompositeOverlayAvailable() const; 1494 bool isRenderAvailable() const 1495 { 1496 return m_render.version > 0; 1497 } 1498 bool isFixesAvailable() const 1499 { 1500 return m_fixes.version > 0; 1501 } 1502 int fixesCursorNotifyEvent() const; 1503 int fixesSelectionNotifyEvent() const; 1504 bool isFixesRegionAvailable() const; 1505 bool isSyncAvailable() const 1506 { 1507 return m_sync.present; 1508 } 1509 int syncAlarmNotifyEvent() const; 1510 QList<ExtensionData> extensions() const; 1511 bool hasGlx() const 1512 { 1513 return m_glx.present; 1514 } 1515 int glxEventBase() const 1516 { 1517 return m_glx.eventBase; 1518 } 1519 int glxMajorOpcode() const 1520 { 1521 return m_glx.majorOpcode; 1522 } 1523 1524 static Extensions *self(); 1525 static void destroy(); 1526 1527 private: 1528 Extensions(); 1529 ~Extensions(); 1530 void init(); 1531 template<typename reply, typename T, typename F> 1532 void initVersion(T cookie, F f, ExtensionData *dataToFill); 1533 void extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill); 1534 1535 ExtensionData m_shape; 1536 ExtensionData m_randr; 1537 ExtensionData m_damage; 1538 ExtensionData m_composite; 1539 ExtensionData m_render; 1540 ExtensionData m_fixes; 1541 ExtensionData m_sync; 1542 ExtensionData m_glx; 1543 1544 static Extensions *s_self; 1545 }; 1546 1547 /** 1548 * This class is an RAII wrapper for an xcb_window_t. An xcb_window_t hold by an instance of this class 1549 * will be freed when the instance gets destroyed. 1550 * 1551 * Furthermore the class provides wrappers around some xcb methods operating on an xcb_window_t. 1552 * 1553 * For the cases that one is more interested in wrapping the xcb methods the constructor which takes 1554 * an existing window and the @ref reset method allow to disable the RAII functionality. 1555 */ 1556 class Window 1557 { 1558 public: 1559 /** 1560 * Takes over responsibility of @p window. If @p window is not provided an invalid Window is 1561 * created. Use @ref create to set an xcb_window_t later on. 1562 * 1563 * If @p destroy is @c true the window will be destroyed together with this object, if @c false 1564 * the window will be kept around. This is useful if you are not interested in the RAII capabilities 1565 * but still want to use a window like an object. 1566 * 1567 * @param window The window to manage. 1568 * @param destroy Whether the window should be destroyed together with the object. 1569 * @see reset 1570 */ 1571 Window(xcb_window_t window = XCB_WINDOW_NONE, bool destroy = true); 1572 /** 1573 * Creates an xcb_window_t and manages it. It's a convenient method to create a window with 1574 * depth, class and visual being copied from parent and border being @c 0. 1575 * @param geometry The geometry for the window to be created 1576 * @param mask The mask for the values 1577 * @param values The values to be passed to xcb_create_window 1578 * @param parent The parent window 1579 */ 1580 Window(const QRectF &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow()); 1581 /** 1582 * Creates an xcb_window_t and manages it. It's a convenient method to create a window with 1583 * depth and visual being copied from parent and border being @c 0. 1584 * @param geometry The geometry for the window to be created 1585 * @param windowClass The window class 1586 * @param mask The mask for the values 1587 * @param values The values to be passed to xcb_create_window 1588 * @param parent The parent window 1589 */ 1590 Window(const QRectF &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow()); 1591 Window(const Window &other) = delete; 1592 ~Window(); 1593 1594 /** 1595 * Creates a new window for which the responsibility is taken over. If a window had been managed 1596 * before it is freed. 1597 * 1598 * Depth, class and visual are being copied from parent and border is @c 0. 1599 * @param geometry The geometry for the window to be created 1600 * @param mask The mask for the values 1601 * @param values The values to be passed to xcb_create_window 1602 * @param parent The parent window 1603 */ 1604 void create(const QRectF &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow()); 1605 /** 1606 * Creates a new window for which the responsibility is taken over. If a window had been managed 1607 * before it is freed. 1608 * 1609 * Depth and visual are being copied from parent and border is @c 0. 1610 * @param geometry The geometry for the window to be created 1611 * @param windowClass The window class 1612 * @param mask The mask for the values 1613 * @param values The values to be passed to xcb_create_window 1614 * @param parent The parent window 1615 */ 1616 void create(const QRectF &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow()); 1617 /** 1618 * Frees the existing window and starts to manage the new @p window. 1619 * If @p destroy is @c true the new managed window will be destroyed together with this 1620 * object or when reset is called again. If @p destroy is @c false the window will not 1621 * be destroyed. It is then the responsibility of the caller to destroy the window. 1622 */ 1623 void reset(xcb_window_t window = XCB_WINDOW_NONE, bool destroy = true); 1624 /** 1625 * @returns @c true if a window is managed, @c false otherwise. 1626 */ 1627 bool isValid() const; 1628 inline const QRectF &geometry() const 1629 { 1630 return m_logicGeometry; 1631 } 1632 /** 1633 * Configures the window with a new geometry. 1634 * @param geometry The new window geometry to be used 1635 */ 1636 void setGeometry(const QRectF &geometry); 1637 void setGeometry(qreal x, qreal y, qreal width, qreal height); 1638 void move(const QPointF &pos); 1639 void move(qreal x, qreal y); 1640 void resize(const QSizeF &size); 1641 void resize(qreal width, qreal height); 1642 void raise(); 1643 void lower(); 1644 void map(); 1645 void unmap(); 1646 void reparent(xcb_window_t parent, qreal x = 0, qreal y = 0); 1647 void changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, 1648 const void *data, uint8_t mode = XCB_PROP_MODE_REPLACE); 1649 void deleteProperty(xcb_atom_t property); 1650 void setBorderWidth(uint32_t width); 1651 void grabButton(uint8_t pointerMode, uint8_t keyboardmode, 1652 uint16_t modifiers = XCB_MOD_MASK_ANY, 1653 uint8_t button = XCB_BUTTON_INDEX_ANY, 1654 uint16_t eventMask = XCB_EVENT_MASK_BUTTON_PRESS, 1655 xcb_window_t confineTo = XCB_WINDOW_NONE, 1656 xcb_cursor_t cursor = XCB_CURSOR_NONE, 1657 bool ownerEvents = false); 1658 void ungrabButton(uint16_t modifiers = XCB_MOD_MASK_ANY, uint8_t button = XCB_BUTTON_INDEX_ANY); 1659 /** 1660 * Clears the window area. Same as xcb_clear_area with x, y, width, height being @c 0. 1661 */ 1662 void clear(); 1663 void setBackgroundPixmap(xcb_pixmap_t pixmap); 1664 void defineCursor(xcb_cursor_t cursor); 1665 void focus(uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = XCB_TIME_CURRENT_TIME); 1666 void selectInput(uint32_t events); 1667 void kill(); 1668 operator xcb_window_t() const; 1669 1670 private: 1671 xcb_window_t doCreate(const QRectF &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow()); 1672 void destroy(); 1673 xcb_window_t m_window; 1674 bool m_destroy; 1675 QRectF m_logicGeometry; 1676 }; 1677 1678 inline Window::Window(xcb_window_t window, bool destroy) 1679 : m_window(window) 1680 , m_destroy(destroy) 1681 { 1682 } 1683 1684 inline Window::Window(const QRectF &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent) 1685 : m_window(doCreate(geometry, XCB_COPY_FROM_PARENT, mask, values, parent)) 1686 , m_destroy(true) 1687 { 1688 } 1689 1690 inline Window::Window(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent) 1691 : m_window(doCreate(geometry, windowClass, mask, values, parent)) 1692 , m_destroy(true) 1693 { 1694 } 1695 1696 inline Window::~Window() 1697 { 1698 destroy(); 1699 } 1700 1701 inline void Window::destroy() 1702 { 1703 if (!isValid() || !m_destroy) { 1704 return; 1705 } 1706 xcb_destroy_window(connection(), m_window); 1707 m_window = XCB_WINDOW_NONE; 1708 } 1709 1710 inline bool Window::isValid() const 1711 { 1712 return m_window != XCB_WINDOW_NONE; 1713 } 1714 1715 inline Window::operator xcb_window_t() const 1716 { 1717 return m_window; 1718 } 1719 1720 inline void Window::create(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent) 1721 { 1722 destroy(); 1723 m_window = doCreate(geometry, windowClass, mask, values, parent); 1724 } 1725 1726 inline void Window::create(const QRectF &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent) 1727 { 1728 create(geometry, XCB_COPY_FROM_PARENT, mask, values, parent); 1729 } 1730 1731 inline xcb_window_t Window::doCreate(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent) 1732 { 1733 m_logicGeometry = geometry; 1734 xcb_window_t w = xcb_generate_id(connection()); 1735 xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent, 1736 Xcb::toXNative(geometry.x()), Xcb::toXNative(geometry.y()), Xcb::toXNative(geometry.width()), Xcb::toXNative(geometry.height()), 1737 0, windowClass, XCB_COPY_FROM_PARENT, mask, values); 1738 return w; 1739 } 1740 1741 inline void Window::reset(xcb_window_t window, bool shouldDestroy) 1742 { 1743 destroy(); 1744 m_window = window; 1745 m_destroy = shouldDestroy; 1746 } 1747 1748 inline void Window::setGeometry(const QRectF &geometry) 1749 { 1750 setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height()); 1751 } 1752 1753 inline void Window::setGeometry(qreal x, qreal y, qreal width, qreal height) 1754 { 1755 m_logicGeometry.setRect(x, y, width, height); 1756 if (!isValid()) { 1757 return; 1758 } 1759 const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; 1760 const uint32_t values[] = {Xcb::toXNative(x), Xcb::toXNative(y), Xcb::toXNative(width), Xcb::toXNative(height)}; 1761 xcb_configure_window(connection(), m_window, mask, values); 1762 } 1763 1764 inline void Window::move(const QPointF &pos) 1765 { 1766 move(pos.x(), pos.y()); 1767 } 1768 1769 inline void Window::move(qreal x, qreal y) 1770 { 1771 m_logicGeometry.moveTo(x, y); 1772 if (!isValid()) { 1773 return; 1774 } 1775 moveWindow(m_window, x, y); 1776 } 1777 1778 inline void Window::resize(const QSizeF &size) 1779 { 1780 resize(size.width(), size.height()); 1781 } 1782 1783 inline void Window::resize(qreal width, qreal height) 1784 { 1785 m_logicGeometry.setSize(QSizeF(width, height)); 1786 if (!isValid()) { 1787 return; 1788 } 1789 const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; 1790 const uint32_t values[] = {Xcb::toXNative(width), Xcb::toXNative(height)}; 1791 xcb_configure_window(connection(), m_window, mask, values); 1792 } 1793 1794 inline void Window::raise() 1795 { 1796 const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; 1797 xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_STACK_MODE, values); 1798 } 1799 1800 inline void Window::lower() 1801 { 1802 lowerWindow(m_window); 1803 } 1804 1805 inline void Window::map() 1806 { 1807 if (!isValid()) { 1808 return; 1809 } 1810 xcb_map_window(connection(), m_window); 1811 } 1812 1813 inline void Window::unmap() 1814 { 1815 if (!isValid()) { 1816 return; 1817 } 1818 xcb_unmap_window(connection(), m_window); 1819 } 1820 1821 inline void Window::reparent(xcb_window_t parent, qreal x, qreal y) 1822 { 1823 if (!isValid()) { 1824 return; 1825 } 1826 xcb_reparent_window(connection(), m_window, parent, Xcb::toXNative(x), Xcb::toXNative(y)); 1827 } 1828 1829 inline void Window::changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void *data, uint8_t mode) 1830 { 1831 if (!isValid()) { 1832 return; 1833 } 1834 xcb_change_property(connection(), mode, m_window, property, type, format, length, data); 1835 } 1836 1837 inline void Window::deleteProperty(xcb_atom_t property) 1838 { 1839 if (!isValid()) { 1840 return; 1841 } 1842 xcb_delete_property(connection(), m_window, property); 1843 } 1844 1845 inline void Window::setBorderWidth(uint32_t width) 1846 { 1847 if (!isValid()) { 1848 return; 1849 } 1850 uint32_t _width = Xcb::toXNative(width); 1851 xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_BORDER_WIDTH, &_width); 1852 } 1853 1854 inline void Window::grabButton(uint8_t pointerMode, uint8_t keyboardmode, uint16_t modifiers, 1855 uint8_t button, uint16_t eventMask, xcb_window_t confineTo, 1856 xcb_cursor_t cursor, bool ownerEvents) 1857 { 1858 if (!isValid()) { 1859 return; 1860 } 1861 xcb_grab_button(connection(), ownerEvents, m_window, eventMask, 1862 pointerMode, keyboardmode, confineTo, cursor, button, modifiers); 1863 } 1864 1865 inline void Window::ungrabButton(uint16_t modifiers, uint8_t button) 1866 { 1867 if (!isValid()) { 1868 return; 1869 } 1870 xcb_ungrab_button(connection(), button, m_window, modifiers); 1871 } 1872 1873 inline void Window::clear() 1874 { 1875 if (!isValid()) { 1876 return; 1877 } 1878 xcb_clear_area(connection(), false, m_window, 0, 0, 0, 0); 1879 } 1880 1881 inline void Window::setBackgroundPixmap(xcb_pixmap_t pixmap) 1882 { 1883 if (!isValid()) { 1884 return; 1885 } 1886 const uint32_t values[] = {pixmap}; 1887 xcb_change_window_attributes(connection(), m_window, XCB_CW_BACK_PIXMAP, values); 1888 } 1889 1890 inline void Window::defineCursor(xcb_cursor_t cursor) 1891 { 1892 Xcb::defineCursor(m_window, cursor); 1893 } 1894 1895 inline void Window::focus(uint8_t revertTo, xcb_timestamp_t time) 1896 { 1897 setInputFocus(m_window, revertTo, time); 1898 } 1899 1900 inline void Window::selectInput(uint32_t events) 1901 { 1902 Xcb::selectInput(m_window, events); 1903 } 1904 1905 inline void Window::kill() 1906 { 1907 xcb_kill_client(connection(), m_window); 1908 } 1909 1910 // helper functions 1911 static inline void moveResizeWindow(WindowId window, const QRect &geometry) 1912 { 1913 const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; 1914 1915 const uint32_t values[] = {Xcb::toXNative(geometry.x()), Xcb::toXNative(geometry.y()), Xcb::toXNative(geometry.width()), Xcb::toXNative(geometry.height())}; 1916 xcb_configure_window(connection(), window, mask, values); 1917 } 1918 1919 static inline void moveWindow(xcb_window_t window, const QPoint &pos) 1920 { 1921 moveWindow(window, pos.x(), pos.y()); 1922 } 1923 1924 static inline void moveWindow(xcb_window_t window, uint32_t x, uint32_t y) 1925 { 1926 const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y; 1927 const uint32_t values[] = {Xcb::toXNative(x), Xcb::toXNative(y)}; 1928 xcb_configure_window(connection(), window, mask, values); 1929 } 1930 1931 static inline void lowerWindow(xcb_window_t window) 1932 { 1933 const uint32_t values[] = {XCB_STACK_MODE_BELOW}; 1934 xcb_configure_window(connection(), window, XCB_CONFIG_WINDOW_STACK_MODE, values); 1935 } 1936 1937 static inline WindowId createInputWindow(const QRect &geometry, uint32_t mask, const uint32_t *values) 1938 { 1939 WindowId window = xcb_generate_id(connection()); 1940 xcb_create_window(connection(), 0, window, rootWindow(), 1941 geometry.x(), geometry.y(), geometry.width(), geometry.height(), 1942 0, XCB_WINDOW_CLASS_INPUT_ONLY, 1943 XCB_COPY_FROM_PARENT, mask, values); 1944 return window; 1945 } 1946 1947 static inline void restackWindows(const QList<xcb_window_t> &windows) 1948 { 1949 if (windows.count() < 2) { 1950 // only one window, nothing to do 1951 return; 1952 } 1953 for (int i = 1; i < windows.count(); ++i) { 1954 const uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; 1955 const uint32_t stackingValues[] = { 1956 windows.at(i - 1), 1957 XCB_STACK_MODE_BELOW}; 1958 xcb_configure_window(connection(), windows.at(i), mask, stackingValues); 1959 } 1960 } 1961 1962 static inline void restackWindowsWithRaise(const QList<xcb_window_t> &windows) 1963 { 1964 if (windows.isEmpty()) { 1965 return; 1966 } 1967 const uint32_t values[] = {XCB_STACK_MODE_ABOVE}; 1968 xcb_configure_window(connection(), windows.first(), XCB_CONFIG_WINDOW_STACK_MODE, values); 1969 restackWindows(windows); 1970 } 1971 1972 static xcb_screen_t *defaultScreen() 1973 { 1974 return xcb_setup_roots_iterator(xcb_get_setup(connection())).data; 1975 } 1976 1977 static inline int defaultDepth() 1978 { 1979 return defaultScreen()->root_depth; 1980 } 1981 1982 static inline xcb_rectangle_t fromQt(const QRect &rect) 1983 { 1984 const QRect nativeRect = toXNative(rect); 1985 xcb_rectangle_t rectangle; 1986 rectangle.x = nativeRect.x(); 1987 rectangle.y = nativeRect.y(); 1988 rectangle.width = nativeRect.width(); 1989 rectangle.height = nativeRect.height(); 1990 return rectangle; 1991 } 1992 1993 static inline QList<xcb_rectangle_t> regionToRects(const QRegion ®ion) 1994 { 1995 QList<xcb_rectangle_t> rects; 1996 rects.reserve(region.rectCount()); 1997 for (const QRect &rect : region) { 1998 rects.append(Xcb::fromQt(rect)); 1999 } 2000 return rects; 2001 } 2002 2003 static inline void defineCursor(xcb_window_t window, xcb_cursor_t cursor) 2004 { 2005 xcb_change_window_attributes(connection(), window, XCB_CW_CURSOR, &cursor); 2006 } 2007 2008 static inline void setInputFocus(xcb_window_t window, uint8_t revertTo, xcb_timestamp_t time) 2009 { 2010 xcb_set_input_focus(connection(), revertTo, window, time); 2011 } 2012 2013 static inline void setTransientFor(xcb_window_t window, xcb_window_t transient_for_window) 2014 { 2015 xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_TRANSIENT_FOR, 2016 XCB_ATOM_WINDOW, 32, 1, &transient_for_window); 2017 } 2018 2019 static inline void sync() 2020 { 2021 auto *c = connection(); 2022 const auto cookie = xcb_get_input_focus(c); 2023 xcb_generic_error_t *error = nullptr; 2024 UniqueCPtr<xcb_get_input_focus_reply_t> sync(xcb_get_input_focus_reply(c, cookie, &error)); 2025 if (error) { 2026 free(error); 2027 } 2028 } 2029 2030 void selectInput(xcb_window_t window, uint32_t events) 2031 { 2032 xcb_change_window_attributes(connection(), window, XCB_CW_EVENT_MASK, &events); 2033 } 2034 2035 /** 2036 * @brief Small helper class to encapsulate SHM related functionality. 2037 */ 2038 class Shm 2039 { 2040 public: 2041 Shm(); 2042 ~Shm(); 2043 int shmId() const; 2044 void *buffer() const; 2045 xcb_shm_seg_t segment() const; 2046 bool isValid() const; 2047 uint8_t pixmapFormat() const; 2048 2049 private: 2050 bool init(); 2051 int m_shmId; 2052 void *m_buffer; 2053 xcb_shm_seg_t m_segment; 2054 bool m_valid; 2055 uint8_t m_pixmapFormat; 2056 }; 2057 2058 inline void *Shm::buffer() const 2059 { 2060 return m_buffer; 2061 } 2062 2063 inline bool Shm::isValid() const 2064 { 2065 return m_valid; 2066 } 2067 2068 inline xcb_shm_seg_t Shm::segment() const 2069 { 2070 return m_segment; 2071 } 2072 2073 inline int Shm::shmId() const 2074 { 2075 return m_shmId; 2076 } 2077 2078 inline uint8_t Shm::pixmapFormat() const 2079 { 2080 return m_pixmapFormat; 2081 } 2082 2083 inline static Version xServerVersion() 2084 { 2085 if (xcb_connection_t *c = connection()) { 2086 auto setup = xcb_get_setup(c); 2087 const QByteArray vendorName(xcb_setup_vendor(setup), xcb_setup_vendor_length(setup)); 2088 if (vendorName.contains("X.Org")) { 2089 const int release = setup->release_number; 2090 return Version(release / 10000000, (release / 100000) % 100, (release / 1000) % 100); 2091 } 2092 } 2093 return Version(0, 0, 0); 2094 } 2095 2096 } // namespace X11 2097 2098 } // namespace KWin