File indexing completed on 2024-05-19 16:34:59

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