File indexing completed on 2024-05-19 05:32:31

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 &region)
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