1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2012, 2013 Martin Gräßlin <mgraesslin@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #ifndef KWIN_XCB_UTILS_H
10 #define KWIN_XCB_UTILS_H
11 
12 #include <kwinglobals.h>
13 #include "main.h"
14 
15 #include <QRect>
16 #include <QRegion>
17 #include <QScopedPointer>
18 #include <QVector>
19 
20 #include <xcb/xcb.h>
21 #include <xcb/composite.h>
22 #include <xcb/randr.h>
23 
24 #include <xcb/shm.h>
25 
26 class TestXcbSizeHints;
27 
28 namespace KWin {
29 
30 template <typename T> using ScopedCPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
31 
32 namespace Xcb {
33 
34 typedef xcb_window_t WindowId;
35 
36 // forward declaration of methods
37 static void defineCursor(xcb_window_t window, xcb_cursor_t cursor);
38 static void setInputFocus(xcb_window_t window, uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = xTime());
39 static void moveWindow(xcb_window_t window, const QPoint &pos);
40 static void moveWindow(xcb_window_t window, uint32_t x, uint32_t y);
41 static void lowerWindow(xcb_window_t window);
42 static void selectInput(xcb_window_t window, uint32_t events);
43 
44 /**
45  * @brief Variadic template to wrap an xcb request.
46  *
47  * This struct is part of the generic implementation to wrap xcb requests
48  * and fetching their reply. Each request is represented by two templated
49  * elements: WrapperData and Wrapper.
50  *
51  * The WrapperData defines the following types:
52  * @li reply_type of the xcb request
53  * @li cookie_type of the xcb request
54  * @li function pointer type for the xcb request
55  * @li function pointer type for the reply
56  * This uses variadic template arguments thus it can be used to specify any
57  * xcb request.
58  *
59  * As the WrapperData does not specify the actual function pointers one needs
60  * to derive another struct which specifies the function pointer requestFunc and
61  * the function pointer replyFunc as static constexpr of type reply_func and
62  * reply_type respectively. E.g. for the command xcb_get_geometry:
63  * @code
64  * struct GeometryData : public WrapperData< xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, xcb_drawable_t >
65  * {
66  *    static constexpr request_func requestFunc = &xcb_get_geometry_unchecked;
67  *    static constexpr reply_func replyFunc = &xcb_get_geometry_reply;
68  * };
69  * @endcode
70  *
71  * To simplify this definition the macro XCB_WRAPPER_DATA is provided.
72  * For the same xcb command this looks like this:
73  * @code
74  * XCB_WRAPPER_DATA(GeometryData, xcb_get_geometry, xcb_drawable_t)
75  * @endcode
76  *
77  * The derived WrapperData has to be passed as first template argument to Wrapper. The other
78  * template arguments of Wrapper are the same variadic template arguments as passed into
79  * WrapperData. This is ensured at compile time and will cause a compile error in case there
80  * is a mismatch of the variadic template arguments passed to WrapperData and Wrapper.
81  * Passing another type than a struct derived from WrapperData to Wrapper will result in a
82  * compile error. The following code snippets won't compile:
83  * @code
84  * XCB_WRAPPER_DATA(GeometryData, xcb_get_geometry, xcb_drawable_t)
85  * // fails with "static assertion failed: Argument miss-match between Wrapper and WrapperData"
86  * class IncorrectArguments : public Wrapper<GeometryData, uint8_t>
87  * {
88  * public:
89  *     IncorrectArguments() = default;
90  *     IncorrectArguments(xcb_window_t window) : Wrapper<GeometryData, uint8_t>(window) {}
91  * };
92  *
93  * // fails with "static assertion failed: Data template argument must be derived from WrapperData"
94  * class WrapperDataDirectly : public Wrapper<WrapperData<xcb_get_geometry_reply_t, xcb_get_geometry_request_t, xcb_drawable_t>, xcb_drawable_t>
95  * {
96  * public:
97  *     WrapperDataDirectly() = default;
98  *     WrapperDataDirectly(xcb_window_t window) : Wrapper<WrapperData<xcb_get_geometry_reply_t, xcb_get_geometry_request_t, xcb_drawable_t>, xcb_drawable_t>(window) {}
99  * };
100  *
101  * // fails with "static assertion failed: Data template argument must be derived from WrapperData"
102  * struct FakeWrapperData
103  * {
104  *     typedef xcb_get_geometry_reply_t reply_type;
105  *     typedef xcb_get_geometry_cookie_t cookie_type;
106  *     typedef std::tuple<xcb_drawable_t> argument_types;
107  *     typedef cookie_type (*request_func)(xcb_connection_t*, xcb_drawable_t);
108  *     typedef reply_type *(*reply_func)(xcb_connection_t*, cookie_type, xcb_generic_error_t**);
109  *     static constexpr std::size_t argumentCount = 1;
110  *     static constexpr request_func requestFunc = &xcb_get_geometry_unchecked;
111  *     static constexpr reply_func replyFunc = &xcb_get_geometry_reply;
112  * };
113  * class NotDerivedFromWrapperData : public Wrapper<FakeWrapperData, xcb_drawable_t>
114  * {
115  * public:
116  *     NotDerivedFromWrapperData() = default;
117  *     NotDerivedFromWrapperData(xcb_window_t window) : Wrapper<FakeWrapperData, xcb_drawable_t>(window) {}
118  * };
119  * @endcode
120  *
121  * The Wrapper provides an easy to use RAII API which calls the WrapperData's requestFunc in
122  * the ctor and fetches the reply the first time it is used. In addition the dtor takes care
123  * of freeing the reply if it got fetched, otherwise it discards the reply. The Wrapper can
124  * be used as if it were the reply_type directly.
125  *
126  * There are several command wrappers defined which either subclass Wrapper to add methods to
127  * simplify the usage of the result_type or use a typedef. To add a new typedef one can use the
128  * macro XCB_WRAPPER which creates the WrapperData struct as XCB_WRAPPER_DATA does and the
129  * typedef. E.g:
130  * @code
131  * XCB_WRAPPER(Geometry, xcb_get_geometry, xcb_drawable_t)
132  * @endcode
133  *
134  * creates a typedef Geometry and the struct GeometryData.
135  *
136  * Overall this allows to simplify the Xcb usage. For example consider the
137  * following xcb code snippet:
138  * @code
139  * xcb_window_t w; // some window
140  * xcb_connection_t *c = connection();
141  * const xcb_get_geometry_cookie_t cookie = xcb_get_geometry_unchecked(c, w);
142  * // do other stuff
143  * xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(c, cookie, nullptr);
144  * if (reply) {
145  *     reply->x; // do something with the geometry
146  * }
147  * free(reply);
148  * @endcode
149  *
150  * With the help of the Wrapper class this can be simplified to:
151  * @code
152  * xcb_window_t w; // some window
153  * Xcb::Geometry geo(w);
154  * if (!geo.isNull()) {
155  *     geo->x; // do something with the geometry
156  * }
157  * @endcode
158  *
159  * @see XCB_WRAPPER_DATA
160  * @see XCB_WRAPPER
161  * @see Wrapper
162  * @see WindowAttributes
163  * @see OverlayWindow
164  * @see WindowGeometry
165  * @see Tree
166  * @see CurrentInput
167  * @see TransientFor
168  */
169 template <typename Reply,
170           typename Cookie,
171           typename... Args>
172 struct WrapperData
173 {
174     /**
175      * @brief The type returned by the xcb reply function.
176      */
177     typedef Reply reply_type;
178     /**
179      * @brief The type returned by the xcb request function.
180      */
181     typedef Cookie cookie_type;
182     /**
183      * @brief Variadic arguments combined as a std::tuple.
184      * @internal Used for verifying the arguments.
185      */
186     typedef std::tuple<Args...> argument_types;
187     /**
188      * @brief The function pointer definition for the xcb request function.
189      */
190     typedef Cookie (*request_func)(xcb_connection_t*, Args...);
191     /**
192      * @brief The function pointer definition for the xcb reply function.
193      */
194     typedef Reply *(*reply_func)(xcb_connection_t*, Cookie, xcb_generic_error_t**);
195     /**
196      * @brief Number of variadic arguments.
197      * @internal Used for verifying the arguments.
198      */
199     static constexpr std::size_t argumentCount = sizeof...(Args);
200 };
201 
202 /**
203  * @brief Partial template specialization for WrapperData with no further arguments.
204  *
205  * This will be used for xcb requests just taking the xcb_connection_t* argument.
206  */
207 template <typename Reply,
208           typename Cookie>
209 struct WrapperData<Reply, Cookie>
210 {
211     typedef Reply reply_type;
212     typedef Cookie cookie_type;
213     typedef std::tuple<> argument_types;
214     typedef Cookie (*request_func)(xcb_connection_t*);
215     typedef Reply *(*reply_func)(xcb_connection_t*, Cookie, xcb_generic_error_t**);
216     static constexpr std::size_t argumentCount = 0;
217 };
218 
219 /**
220  * @brief Abstract base class for the wrapper.
221  *
222  * This class contains the complete functionality of the Wrapper. It's only an abstract
223  * base class to provide partial template specialization for more specific constructors.
224  */
225 template<typename Data>
226 class AbstractWrapper
227 {
228 public:
229     typedef typename Data::cookie_type Cookie;
230     typedef typename Data::reply_type Reply;
231     virtual ~AbstractWrapper() {
232         cleanup();
233     }
234     inline AbstractWrapper &operator=(const AbstractWrapper &other) {
235         if (this != &other) {
236             // if we had managed a reply, free it
237             cleanup();
238             // copy members
239             m_retrieved = other.m_retrieved;
240             m_cookie = other.m_cookie;
241             m_window = other.m_window;
242             m_reply = other.m_reply;
243             // take over the responsibility for the reply pointer
244             takeFromOther(const_cast<AbstractWrapper&>(other));
245         }
246         return *this;
247     }
248 
249     inline const Reply *operator->() {
250         getReply();
251         return m_reply;
252     }
253     inline bool isNull() {
254         getReply();
255         return m_reply == nullptr;
256     }
257     inline bool isNull() const {
258         const_cast<AbstractWrapper*>(this)->getReply();
259         return m_reply == NULL;
260     }
261     inline operator bool() {
262         return !isNull();
263     }
264     inline operator bool() const {
265         return !isNull();
266     }
267     inline const Reply *data() {
268         getReply();
269         return m_reply;
270     }
271     inline const Reply *data() const {
272         const_cast<AbstractWrapper*>(this)->getReply();
273         return m_reply;
274     }
275     inline WindowId window() const {
276         return m_window;
277     }
278     inline bool isRetrieved() const {
279         return m_retrieved;
280     }
281     /**
282      * Returns the value of the reply pointer referenced by this object. The reply pointer of
283      * this object will be reset to null. Calling any method which requires the reply to be valid
284      * will crash.
285      *
286      * Callers of this function take ownership of the pointer.
287      */
288     inline Reply *take() {
289         getReply();
290         Reply *ret = m_reply;
291         m_reply = nullptr;
292         m_window = XCB_WINDOW_NONE;
293         return ret;
294     }
295 
296 protected:
297     AbstractWrapper()
298         : m_retrieved(false)
299         , m_window(XCB_WINDOW_NONE)
300         , m_reply(nullptr)
301     {
302         m_cookie.sequence = 0;
303     }
304     explicit AbstractWrapper(WindowId window, Cookie cookie)
305         : m_retrieved(false)
306         , m_cookie(cookie)
307         , m_window(window)
308         , m_reply(nullptr)
309     {
310     }
311     explicit AbstractWrapper(const AbstractWrapper &other)
312         : m_retrieved(other.m_retrieved)
313         , m_cookie(other.m_cookie)
314         , m_window(other.m_window)
315         , m_reply(nullptr)
316     {
317         takeFromOther(const_cast<AbstractWrapper&>(other));
318     }
319     void getReply() {
320         if (m_retrieved || !m_cookie.sequence) {
321             return;
322         }
323         m_reply = Data::replyFunc(connection(), m_cookie, nullptr);
324         m_retrieved = true;
325     }
326 
327 private:
328     inline void cleanup() {
329         if (!m_retrieved && m_cookie.sequence) {
330             xcb_discard_reply(connection(), m_cookie.sequence);
331         } else if (m_reply) {
332             free(m_reply);
333         }
334     }
335     inline void takeFromOther(AbstractWrapper &other) {
336         if (m_retrieved) {
337             m_reply = other.take();
338         } else {
339             //ensure that other object doesn't try to get the reply or discards it in the dtor
340             other.m_retrieved = true;
341             other.m_window = XCB_WINDOW_NONE;
342         }
343     }
344     bool m_retrieved;
345     Cookie m_cookie;
346     WindowId m_window;
347     Reply *m_reply;
348 };
349 
350 /**
351  * @brief Template to compare the arguments of two std::tuple.
352  *
353  * @internal Used by static_assert in Wrapper
354  */
355 template <typename T1, typename T2, std::size_t I>
356 struct tupleCompare
357 {
358     typedef typename std::tuple_element<I, T1>::type tuple1Type;
359     typedef typename std::tuple_element<I, T2>::type tuple2Type;
360     /**
361      * @c true if both tuple have the same arguments, @c false otherwise.
362      */
363     static constexpr bool value = std::is_same< tuple1Type, tuple2Type >::value && tupleCompare<T1, T2, I-1>::value;
364 };
365 
366 /**
367  * @brief Recursive template case for first tuple element.
368  */
369 template <typename T1, typename T2>
370 struct tupleCompare<T1, T2, 0>
371 {
372     typedef typename std::tuple_element<0, T1>::type tuple1Type;
373     typedef typename std::tuple_element<0, T2>::type tuple2Type;
374     static constexpr bool value = std::is_same< tuple1Type, tuple2Type >::value;
375 };
376 
377 /**
378  * @brief Wrapper taking a WrapperData as first template argument and xcb request args as variadic args.
379  */
380 template<typename Data, typename... Args>
381 class Wrapper : public AbstractWrapper<Data>
382 {
383 public:
384     static_assert(!std::is_same<Data, Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, Args...> >::value,
385                   "Data template argument must be derived from WrapperData");
386     static_assert(std::is_base_of<Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, Args...>, Data>::value,
387                   "Data template argument must be derived from WrapperData");
388     static_assert(sizeof...(Args) == Data::argumentCount,
389                     "Wrapper and WrapperData need to have same template argument count");
390     static_assert(tupleCompare<std::tuple<Args...>, typename Data::argument_types, sizeof...(Args) - 1>::value,
391                     "Argument miss-match between Wrapper and WrapperData");
392     Wrapper() = default;
393     explicit Wrapper(Args... args)
394         : AbstractWrapper<Data>(XCB_WINDOW_NONE, Data::requestFunc(connection(), args...))
395     {
396     }
397     explicit Wrapper(xcb_window_t w, Args... args)
398         : AbstractWrapper<Data>(w, Data::requestFunc(connection(), args...))
399     {
400     }
401 };
402 
403 /**
404  * @brief Template specialization for xcb_window_t being first variadic argument.
405  */
406 template<typename Data, typename... Args>
407 class Wrapper<Data, xcb_window_t, Args...> : public AbstractWrapper<Data>
408 {
409 public:
410     static_assert(!std::is_same<Data, Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, xcb_window_t, Args...> >::value,
411                   "Data template argument must be derived from WrapperData");
412     static_assert(std::is_base_of<Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type, xcb_window_t, Args...>, Data>::value,
413                   "Data template argument must be derived from WrapperData");
414     static_assert(sizeof...(Args) + 1 == Data::argumentCount,
415                     "Wrapper and WrapperData need to have same template argument count");
416     static_assert(tupleCompare<std::tuple<xcb_window_t, Args...>, typename Data::argument_types, sizeof...(Args)>::value,
417                     "Argument miss-match between Wrapper and WrapperData");
418     Wrapper() = default;
419     explicit Wrapper(xcb_window_t w, Args... args)
420         : AbstractWrapper<Data>(w, Data::requestFunc(connection(), w, args...))
421     {
422     }
423 };
424 
425 /**
426  * @brief Template specialization for no variadic arguments.
427  *
428  * It's needed to prevent ambiguous constructors being generated.
429  */
430 template<typename Data>
431 class Wrapper<Data> : public AbstractWrapper<Data>
432 {
433 public:
434     static_assert(!std::is_same<Data, Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type> >::value,
435                   "Data template argument must be derived from WrapperData");
436     static_assert(std::is_base_of<Xcb::WrapperData<typename Data::reply_type, typename Data::cookie_type>, Data>::value,
437                   "Data template argument must be derived from WrapperData");
438     static_assert(Data::argumentCount == 0, "Wrapper for no arguments constructed with WrapperData with arguments");
439     explicit Wrapper()
440         : AbstractWrapper<Data>(XCB_WINDOW_NONE, Data::requestFunc(connection()))
441     {
442     }
443 };
444 
445 class Atom
446 {
447 public:
448     explicit Atom(const QByteArray &name, bool onlyIfExists = false, xcb_connection_t *c = connection())
449         : m_connection(c)
450         , m_retrieved(false)
451         , m_cookie(xcb_intern_atom_unchecked(m_connection, onlyIfExists, name.length(), name.constData()))
452         , m_atom(XCB_ATOM_NONE)
453         , m_name(name)
454         {
455         }
456     Atom() = delete;
457     Atom(const Atom &) = delete;
458 
459     ~Atom() {
460         if (!m_retrieved && m_cookie.sequence) {
461             xcb_discard_reply(m_connection, m_cookie.sequence);
462         }
463     }
464 
465     operator xcb_atom_t() const {
466         (const_cast<Atom*>(this))->getReply();
467         return m_atom;
468     }
469     bool isValid() {
470         getReply();
471         return m_atom != XCB_ATOM_NONE;
472     }
473     bool isValid() const {
474         (const_cast<Atom*>(this))->getReply();
475         return m_atom != XCB_ATOM_NONE;
476     }
477 
478     inline const QByteArray &name() const {
479         return m_name;
480     }
481 
482 private:
483     void getReply() {
484         if (m_retrieved || !m_cookie.sequence) {
485             return;
486         }
487         ScopedCPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr));
488         if (!reply.isNull()) {
489             m_atom = reply->atom;
490         }
491         m_retrieved = true;
492     }
493     xcb_connection_t *m_connection;
494     bool m_retrieved;
495     xcb_intern_atom_cookie_t m_cookie;
496     xcb_atom_t m_atom;
497     QByteArray m_name;
498 };
499 
500 /**
501  * @brief Macro to create the WrapperData subclass.
502  *
503  * Creates a struct with name @p __NAME__ for the xcb request identified by @p __REQUEST__.
504  * The variadic arguments are used to pass as template arguments to the WrapperData.
505  *
506  * The @p __REQUEST__ is the common prefix of the cookie type, reply type, request function and
507  * reply function. E.g. "xcb_get_geometry" is used to create:
508  * @li cookie type xcb_get_geometry_cookie_t
509  * @li reply type xcb_get_geometry_reply_t
510  * @li request function pointer xcb_get_geometry_unchecked
511  * @li reply function pointer xcb_get_geometry_reply
512  *
513  * @param __NAME__ The name of the WrapperData subclass
514  * @param __REQUEST__ The name of the xcb request, e.g. xcb_get_geometry
515  * @param __VA_ARGS__ The variadic template arguments, e.g. xcb_drawable_t
516  * @see XCB_WRAPPER
517  */
518 #define XCB_WRAPPER_DATA( __NAME__, __REQUEST__, ... ) \
519     struct __NAME__ : public WrapperData< __REQUEST__##_reply_t, __REQUEST__##_cookie_t, __VA_ARGS__ > \
520     { \
521         static constexpr request_func requestFunc = &__REQUEST__##_unchecked; \
522         static constexpr reply_func replyFunc = &__REQUEST__##_reply; \
523     };
524 
525 /**
526  * @brief Macro to create Wrapper typedef and WrapperData.
527  *
528  * This macro expands the XCB_WRAPPER_DATA macro and creates an additional
529  * typedef for Wrapper with name @p __NAME__. The created WrapperData is also derived
530  * from @p __NAME__ with "Data" as suffix.
531  *
532  * @param __NAME__ The name for the Wrapper typedef
533  * @param __REQUEST__ The name of the xcb request, passed to XCB_WRAPPER_DATA
534  * @param __VA_ARGS__ The variadic template arguments for Wrapper and WrapperData
535  * @see XCB_WRAPPER_DATA
536  */
537 #define XCB_WRAPPER( __NAME__, __REQUEST__, ... ) \
538     XCB_WRAPPER_DATA( __NAME__##Data, __REQUEST__, __VA_ARGS__ ) \
539     typedef Wrapper< __NAME__##Data, __VA_ARGS__ > __NAME__;
540 
541 XCB_WRAPPER(WindowAttributes, xcb_get_window_attributes, xcb_window_t)
542 XCB_WRAPPER(OverlayWindow, xcb_composite_get_overlay_window, xcb_window_t)
543 
544 XCB_WRAPPER_DATA(GeometryData, xcb_get_geometry, xcb_drawable_t)
545 class WindowGeometry : public Wrapper<GeometryData, xcb_window_t>
546 {
547 public:
548     WindowGeometry() : Wrapper<GeometryData, xcb_window_t>() {}
549     explicit WindowGeometry(xcb_window_t window) : Wrapper<GeometryData, xcb_window_t>(window) {}
550 
551     inline QRect rect() {
552         const xcb_get_geometry_reply_t *geometry = data();
553         if (!geometry) {
554             return QRect();
555         }
556         return QRect(geometry->x, geometry->y, geometry->width, geometry->height);
557     }
558 
559     inline QSize size() {
560         const xcb_get_geometry_reply_t *geometry = data();
561         if (!geometry) {
562             return QSize();
563         }
564         return QSize(geometry->width, geometry->height);
565     }
566 };
567 
568 XCB_WRAPPER_DATA(TreeData, xcb_query_tree, xcb_window_t)
569 class Tree : public Wrapper<TreeData, xcb_window_t>
570 {
571 public:
572     explicit Tree(WindowId window) : Wrapper<TreeData, xcb_window_t>(window) {}
573 
574     inline WindowId *children() {
575         if (isNull() || data()->children_len == 0) {
576             return nullptr;
577         }
578         return xcb_query_tree_children(data());
579     }
580     inline xcb_window_t parent() {
581         if (isNull())
582             return XCB_WINDOW_NONE;
583         return (*this)->parent;
584     }
585 };
586 
587 XCB_WRAPPER(Pointer, xcb_query_pointer, xcb_window_t)
588 
589 struct CurrentInputData : public WrapperData< xcb_get_input_focus_reply_t, xcb_get_input_focus_cookie_t >
590 {
591     static constexpr request_func requestFunc = &xcb_get_input_focus_unchecked;
592     static constexpr reply_func replyFunc = &xcb_get_input_focus_reply;
593 };
594 
595 class CurrentInput : public Wrapper<CurrentInputData>
596 {
597 public:
598     CurrentInput() : Wrapper<CurrentInputData>() {}
599 
600     inline xcb_window_t window() {
601         if (isNull())
602             return XCB_WINDOW_NONE;
603         return (*this)->focus;
604     }
605 };
606 
607 struct QueryKeymapData : public WrapperData< xcb_query_keymap_reply_t, xcb_query_keymap_cookie_t >
608 {
609     static constexpr request_func requestFunc = &xcb_query_keymap_unchecked;
610     static constexpr reply_func replyFunc = &xcb_query_keymap_reply;
611 };
612 
613 class QueryKeymap : public Wrapper<QueryKeymapData>
614 {
615 public:
616     QueryKeymap() : Wrapper<QueryKeymapData>() {}
617 };
618 
619 struct ModifierMappingData : public WrapperData< xcb_get_modifier_mapping_reply_t, xcb_get_modifier_mapping_cookie_t >
620 {
621     static constexpr request_func requestFunc = &xcb_get_modifier_mapping_unchecked;
622     static constexpr reply_func replyFunc = &xcb_get_modifier_mapping_reply;
623 };
624 
625 class ModifierMapping : public Wrapper<ModifierMappingData>
626 {
627 public:
628     ModifierMapping() : Wrapper<ModifierMappingData>() {}
629 
630     inline xcb_keycode_t *keycodes() {
631         if (isNull()) {
632             return nullptr;
633         }
634         return xcb_get_modifier_mapping_keycodes(data());
635     }
636     inline int size() {
637         if (isNull()) {
638             return 0;
639         }
640         return xcb_get_modifier_mapping_keycodes_length(data());
641     }
642 };
643 
644 XCB_WRAPPER_DATA(PropertyData, xcb_get_property, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t)
645 class Property : public Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>
646 {
647 public:
648     Property()
649         : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>()
650         , m_type(XCB_ATOM_NONE)
651     {
652     }
653     Property(const Property &other)
654         : Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>(other)
655         , m_type(other.m_type)
656     {
657     }
658     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)
659         : 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)
660         , m_type(type)
661     {
662     }
663     Property &operator=(const Property &other) {
664         Wrapper<PropertyData, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t>::operator=(other);
665         m_type = other.m_type;
666         return *this;
667     }
668 
669     /**
670      * @brief Overloaded method for convenience.
671      *
672      * Uses the type which got passed into the ctor and derives the format from the sizeof(T).
673      * Note: for the automatic format detection the size of the type T may not vary between
674      * architectures. Thus one needs to use e.g. uint32_t instead of long. In general all xcb
675      * data types can be used, all Xlib data types can not be used.
676      *
677      * @param defaultValue The default value to return in case of error
678      * @param ok Set to @c false in case of error, @c true in case of success
679      * @return The read value or @p defaultValue in error case
680      */
681     template <typename T>
682     inline typename std::enable_if<!std::is_pointer<T>::value, T>::type value(T defaultValue = T(), bool *ok = nullptr) {
683         return value<T>(sizeof(T) * 8, m_type, defaultValue, ok);
684     }
685     /**
686      * @brief Reads the property as a POD type.
687      *
688      * Returns the first value of the property data. In case of @p format or @p type mismatch
689      * the @p defaultValue is returned. The optional argument @p ok is set
690      * to @c false in case of error and to @c true in case of successful reading of
691      * the property.
692      *
693      * @param format The expected format of the property value, e.g. 32 for XCB_ATOM_CARDINAL
694      * @param type The expected type of the property value, e.g. XCB_ATOM_CARDINAL
695      * @param defaultValue The default value to return in case of error
696      * @param ok Set to @c false in case of error, @c true in case of success
697      * @return The read value or @p defaultValue in error case
698      */
699     template <typename T>
700     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) {
701         T *reply = value<T*>(format, type, nullptr, ok);
702         if (!reply) {
703             return defaultValue;
704         }
705         return reply[0];
706     }
707     /**
708      * @brief Overloaded method for convenience.
709      *
710      * Uses the type which got passed into the ctor and derives the format from the sizeof(T).
711      * Note: for the automatic format detection the size of the type T may not vary between
712      * architectures. Thus one needs to use e.g. uint32_t instead of long. In general all xcb
713      * data types can be used, all Xlib data types can not be used.
714      *
715      * @param defaultValue The default value to return in case of error
716      * @param ok Set to @c false in case of error, @c true in case of success
717      * @return The read value or @p defaultValue in error case
718      */
719     template <typename T>
720     inline typename std::enable_if<std::is_pointer<T>::value, T>::type value(T defaultValue = nullptr, bool *ok = nullptr) {
721         return value<T>(sizeof(typename std::remove_pointer<T>::type) * 8, m_type, defaultValue, ok);
722     }
723     /**
724      * @brief Reads the property as an array of T.
725      *
726      * This method is an overload for the case that T is a pointer type.
727      *
728      * Return the property value casted to the pointer type T. In case of @p format
729      * or @p type mismatch the @p defaultValue is returned. Also if the value length
730      * is @c 0 the @p defaultValue is returned. The optional argument @p ok is set
731      * to @c false in case of error and to @c true in case of successful reading of
732      * the property. Ok will always be true if the property exists and has been
733      * successfully read, even in the case the property is empty and its length is 0
734      *
735      * @param format The expected format of the property value, e.g. 32 for XCB_ATOM_CARDINAL
736      * @param type The expected type of the property value, e.g. XCB_ATOM_CARDINAL
737      * @param defaultValue The default value to return in case of error
738      * @param ok Set to @c false in case of error, @c true in case of success
739      * @return The read value or @p defaultValue in error case
740      */
741     template <typename T>
742     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) {
743         if (ok) {
744             *ok = false;
745         }
746         const PropertyData::reply_type *reply = data();
747         if (!reply) {
748             return defaultValue;
749         }
750         if (reply->type != type) {
751             return defaultValue;
752         }
753         if (reply->format != format) {
754             return defaultValue;
755         }
756 
757         if (ok) {
758             *ok = true;
759         }
760         if (xcb_get_property_value_length(reply) == 0) {
761             return defaultValue;
762         }
763 
764         return reinterpret_cast<T>(xcb_get_property_value(reply));
765     }
766     /**
767      * @brief Reads the property as string and returns a QByteArray.
768      *
769      * In case of error this method returns a null QByteArray.
770      */
771     inline QByteArray toByteArray(uint8_t format = 8, xcb_atom_t type = XCB_ATOM_STRING, bool *ok = nullptr) {
772         bool valueOk = false;
773         const char *reply = value<const char*>(format, type, nullptr, &valueOk);
774         if (ok) {
775             *ok = valueOk;
776         }
777 
778         if (valueOk && !reply) {
779             return QByteArray("", 0); // valid, not null, but empty data
780         } else if (!valueOk) {
781             return QByteArray(); // Property not found, data empty and null
782         }
783         return QByteArray(reply, xcb_get_property_value_length(data()));
784     }
785     /**
786      * @brief Overloaded method for convenience.
787      */
788     inline QByteArray toByteArray(bool *ok) {
789         return toByteArray(8, m_type, ok);
790     }
791     /**
792      * @brief Reads the property as a boolean value.
793      *
794      * If the property reply length is @c 1 the first element is interpreted as a boolean
795      * value returning @c true for any value unequal to @c 0 and @c false otherwise.
796      *
797      * In case of error this method returns @c false. Thus it is not possible to distinguish
798      * between error case and a read @c false value. Use the optional argument @p ok to
799      * distinguish the error case.
800      *
801      * @param format Expected format. Defaults to 32.
802      * @param type Expected type Defaults to XCB_ATOM_CARDINAL.
803      * @param ok Set to @c false in case of error, @c true in case of success
804      * @return bool The first element interpreted as a boolean value or @c false in error case
805      * @see value
806      */
807     inline bool toBool(uint8_t format = 32, xcb_atom_t type = XCB_ATOM_CARDINAL, bool *ok = nullptr) {
808         bool *reply = value<bool*>(format, type, nullptr, ok);
809         if (!reply) {
810             return false;
811         }
812         if (data()->value_len != 1) {
813             if (ok) {
814                 *ok = false;
815             }
816             return false;
817         }
818         return reply[0] != 0;
819     }
820     /**
821      * @brief Overloaded method for convenience.
822      */
823     inline bool toBool(bool *ok) {
824         return toBool(32, m_type, ok);
825     }
826 private:
827     xcb_atom_t m_type;
828 };
829 
830 class StringProperty : public Property
831 {
832 public:
833     StringProperty() = default;
834     explicit StringProperty(xcb_window_t w, xcb_atom_t p)
835         : Property(false, w, p, XCB_ATOM_STRING, 0, 10000)
836     {
837     }
838     operator QByteArray() {
839         return toByteArray();
840     }
841 };
842 
843 class TransientFor : public Property
844 {
845 public:
846     explicit TransientFor(WindowId window)
847         : Property(0, window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, 1)
848     {
849     }
850 
851     /**
852      * @brief Fill given window pointer with the WM_TRANSIENT_FOR property of a window.
853      * @param prop WM_TRANSIENT_FOR property value.
854      * @returns @c true on success, @c false otherwise
855      */
856     inline bool getTransientFor(WindowId *prop) {
857         WindowId *windows = value<WindowId*>();
858         if (!windows) {
859             return false;
860         }
861 
862         *prop = *windows;
863         return true;
864     }
865 };
866 
867 class GeometryHints
868 {
869 public:
870     GeometryHints() = default;
871     void init(xcb_window_t window) {
872         Q_ASSERT(window);
873         if (m_window) {
874             // already initialized
875             return;
876         }
877         m_window = window;
878         fetch();
879     }
880     void fetch() {
881         if (!m_window) {
882             return;
883         }
884         m_sizeHints = nullptr;
885         m_hints = NormalHints(m_window);
886     }
887     void read() {
888         m_sizeHints = m_hints.sizeHints();
889     }
890 
891     bool hasPosition() const {
892         return testFlag(NormalHints::SizeHints::UserPosition) || testFlag(NormalHints::SizeHints::ProgramPosition);
893     }
894     bool hasSize() const {
895         return testFlag(NormalHints::SizeHints::UserSize) || testFlag(NormalHints::SizeHints::ProgramSize);
896     }
897     bool hasMinSize() const {
898         return testFlag(NormalHints::SizeHints::MinSize);
899     }
900     bool hasMaxSize() const {
901         return testFlag(NormalHints::SizeHints::MaxSize);
902     }
903     bool hasResizeIncrements() const {
904         return testFlag(NormalHints::SizeHints::ResizeIncrements);
905     }
906     bool hasAspect() const {
907         return testFlag(NormalHints::SizeHints::Aspect);
908     }
909     bool hasBaseSize() const {
910         return testFlag(NormalHints::SizeHints::BaseSize);
911     }
912     bool hasWindowGravity() const {
913         return testFlag(NormalHints::SizeHints::WindowGravity);
914     }
915     QSize maxSize() const {
916         if (!hasMaxSize()) {
917             return QSize(INT_MAX, INT_MAX);
918         }
919         return QSize(qMax(m_sizeHints->maxWidth, 1), qMax(m_sizeHints->maxHeight, 1));
920     }
921     QSize minSize() const {
922         if (!hasMinSize()) {
923             // according to ICCCM 4.1.23 base size should be used as a fallback
924             return baseSize();
925         }
926         return QSize(m_sizeHints->minWidth, m_sizeHints->minHeight);
927     }
928     QSize baseSize() const {
929         // Note: not using minSize as fallback
930         if (!hasBaseSize()) {
931             return QSize(0, 0);
932         }
933         return QSize(m_sizeHints->baseWidth, m_sizeHints->baseHeight);
934     }
935     QSize resizeIncrements() const {
936         if (!hasResizeIncrements()) {
937             return QSize(1, 1);
938         }
939         return QSize(qMax(m_sizeHints->widthInc, 1), qMax(m_sizeHints->heightInc, 1));
940     }
941     xcb_gravity_t windowGravity() const {
942         if (!hasWindowGravity()) {
943             return XCB_GRAVITY_NORTH_WEST;
944         }
945         return xcb_gravity_t(m_sizeHints->winGravity);
946     }
947     QSize minAspect() const {
948         if (!hasAspect()) {
949             return QSize(1, INT_MAX);
950         }
951         // prevent division by zero
952         return QSize(m_sizeHints->minAspect[0], qMax(m_sizeHints->minAspect[1], 1));
953     }
954     QSize maxAspect() const {
955         if (!hasAspect()) {
956             return QSize(INT_MAX, 1);
957         }
958         // prevent division by zero
959         return QSize(m_sizeHints->maxAspect[0], qMax(m_sizeHints->maxAspect[1], 1));
960     }
961 
962 private:
963     /**
964     * NormalHints as specified in ICCCM 4.1.2.3.
965     */
966     class NormalHints : public Property
967     {
968     public:
969         struct SizeHints {
970             enum Flags {
971                 UserPosition = 1,
972                 UserSize = 2,
973                 ProgramPosition = 4,
974                 ProgramSize = 8,
975                 MinSize = 16,
976                 MaxSize = 32,
977                 ResizeIncrements = 64,
978                 Aspect = 128,
979                 BaseSize = 256,
980                 WindowGravity = 512
981             };
982             qint32 flags = 0;
983             qint32 pad[4] = {0, 0, 0, 0};
984             qint32 minWidth = 0;
985             qint32 minHeight = 0;
986             qint32 maxWidth = 0;
987             qint32 maxHeight = 0;
988             qint32 widthInc = 0;
989             qint32 heightInc = 0;
990             qint32 minAspect[2] = {0, 0};
991             qint32 maxAspect[2] = {0, 0};
992             qint32 baseWidth = 0;
993             qint32 baseHeight = 0;
994             qint32 winGravity = 0;
995         };
996         explicit NormalHints() : Property() {};
997         explicit NormalHints(WindowId window)
998             : Property(0, window, XCB_ATOM_WM_NORMAL_HINTS, XCB_ATOM_WM_SIZE_HINTS, 0, 18)
999         {
1000         }
1001         inline SizeHints *sizeHints() {
1002             return value<SizeHints*>(32, XCB_ATOM_WM_SIZE_HINTS, nullptr);
1003         }
1004     };
1005     friend TestXcbSizeHints;
1006     bool testFlag(NormalHints::SizeHints::Flags flag) const {
1007         if (!m_window || !m_sizeHints) {
1008             return false;
1009         }
1010         return m_sizeHints->flags & flag;
1011     }
1012     xcb_window_t m_window = XCB_WINDOW_NONE;
1013     NormalHints m_hints;
1014     NormalHints::SizeHints *m_sizeHints = nullptr;
1015 };
1016 
1017 class MotifHints
1018 {
1019 public:
1020     MotifHints(xcb_atom_t atom) : m_atom(atom) {}
1021     void init(xcb_window_t window) {
1022         Q_ASSERT(window);
1023         if (m_window) {
1024             // already initialized
1025             return;
1026         }
1027         m_window = window;
1028         fetch();
1029     }
1030     void fetch() {
1031         if (!m_window) {
1032             return;
1033         }
1034         m_hints = nullptr;
1035         m_prop = Property(0, m_window, m_atom, m_atom, 0, 5);
1036     }
1037     void read() {
1038         m_hints = m_prop.value<MwmHints*>(32, m_atom, nullptr);
1039     }
1040     bool hasDecoration() const {
1041         if (!m_window || !m_hints) {
1042             return false;
1043         }
1044         return m_hints->flags & uint32_t(Hints::Decorations);
1045     }
1046     bool noBorder() const {
1047         if (!hasDecoration()) {
1048             return false;
1049         }
1050         return !m_hints->decorations;
1051     }
1052     bool resize() const {
1053         return testFunction(Functions::Resize);
1054     }
1055     bool move() const {
1056         return testFunction(Functions::Move);
1057     }
1058     bool minimize() const {
1059         return testFunction(Functions::Minimize);
1060     }
1061     bool maximize() const {
1062         return testFunction(Functions::Maximize);
1063     }
1064     bool close() const {
1065         return testFunction(Functions::Close);
1066     }
1067 
1068 private:
1069     struct MwmHints {
1070         uint32_t flags;
1071         uint32_t functions;
1072         uint32_t decorations;
1073         int32_t input_mode;
1074         uint32_t status;
1075     };
1076     enum class Hints {
1077         Functions = (1L << 0),
1078         Decorations = (1L << 1)
1079     };
1080     enum class Functions {
1081         All = (1L << 0),
1082         Resize = (1L << 1),
1083         Move = (1L << 2),
1084         Minimize = (1L << 3),
1085         Maximize = (1L << 4),
1086         Close = (1L << 5)
1087     };
1088     bool testFunction(Functions flag) const {
1089         if (!m_window || !m_hints) {
1090             return true;
1091         }
1092         if (!(m_hints->flags & uint32_t(Hints::Functions))) {
1093             return true;
1094         }
1095         // if MWM_FUNC_ALL is set, other flags say what to turn _off_
1096         const bool set_value = ((m_hints->functions & uint32_t(Functions::All)) == 0);
1097         if (m_hints->functions & uint32_t(flag)) {
1098             return set_value;
1099         }
1100         return !set_value;
1101     }
1102     xcb_window_t m_window = XCB_WINDOW_NONE;
1103     Property m_prop;
1104     xcb_atom_t m_atom;
1105     MwmHints *m_hints = nullptr;
1106 };
1107 
1108 namespace RandR
1109 {
1110 XCB_WRAPPER(ScreenInfo, xcb_randr_get_screen_info, xcb_window_t)
1111 
1112 XCB_WRAPPER_DATA(ScreenResourcesData, xcb_randr_get_screen_resources, xcb_window_t)
1113 class ScreenResources : public Wrapper<ScreenResourcesData, xcb_window_t>
1114 {
1115 public:
1116     explicit ScreenResources(WindowId window) : Wrapper<ScreenResourcesData, xcb_window_t>(window) {}
1117 
1118     inline xcb_randr_crtc_t *crtcs() {
1119         if (isNull()) {
1120             return nullptr;
1121         }
1122         return xcb_randr_get_screen_resources_crtcs(data());
1123     }
1124     inline xcb_randr_mode_info_t *modes() {
1125         if (isNull()) {
1126             return nullptr;
1127         }
1128         return xcb_randr_get_screen_resources_modes(data());
1129     }
1130     inline uint8_t *names() {
1131         if (isNull()) {
1132             return nullptr;
1133         }
1134         return xcb_randr_get_screen_resources_names(data());
1135     }
1136 };
1137 
1138 XCB_WRAPPER_DATA(CrtcGammaData, xcb_randr_get_crtc_gamma, xcb_randr_crtc_t)
1139 class CrtcGamma : public Wrapper<CrtcGammaData, xcb_randr_crtc_t>
1140 {
1141 public:
1142     explicit CrtcGamma(xcb_randr_crtc_t c) : Wrapper<CrtcGammaData, xcb_randr_crtc_t>(c) {}
1143 
1144     inline uint16_t *red() {
1145         return xcb_randr_get_crtc_gamma_red(data());
1146     }
1147     inline uint16_t *green() {
1148         return xcb_randr_get_crtc_gamma_green(data());
1149     }
1150     inline uint16_t *blue() {
1151         return xcb_randr_get_crtc_gamma_blue(data());
1152     }
1153 };
1154 
1155 XCB_WRAPPER_DATA(CrtcInfoData, xcb_randr_get_crtc_info, xcb_randr_crtc_t, xcb_timestamp_t)
1156 class CrtcInfo : public Wrapper<CrtcInfoData, xcb_randr_crtc_t, xcb_timestamp_t>
1157 {
1158 public:
1159     CrtcInfo() = default;
1160     CrtcInfo(const CrtcInfo&) = default;
1161     explicit CrtcInfo(xcb_randr_crtc_t c, xcb_timestamp_t t) : Wrapper<CrtcInfoData, xcb_randr_crtc_t, xcb_timestamp_t>(c, t) {}
1162 
1163     inline QRect rect() {
1164         const CrtcInfoData::reply_type *info = data();
1165         if (!info || info->num_outputs == 0 || info->mode == XCB_NONE || info->status != XCB_RANDR_SET_CONFIG_SUCCESS) {
1166             return QRect();
1167         }
1168         return QRect(info->x, info->y, info->width, info->height);
1169     }
1170     inline xcb_randr_output_t *outputs() {
1171         const CrtcInfoData::reply_type *info = data();
1172         if (!info || info->num_outputs == 0 || info->mode == XCB_NONE || info->status != XCB_RANDR_SET_CONFIG_SUCCESS) {
1173             return nullptr;
1174         }
1175         return xcb_randr_get_crtc_info_outputs(info);
1176     }
1177 };
1178 
1179 XCB_WRAPPER_DATA(OutputInfoData, xcb_randr_get_output_info, xcb_randr_output_t, xcb_timestamp_t)
1180 class OutputInfo : public Wrapper<OutputInfoData, xcb_randr_output_t, xcb_timestamp_t>
1181 {
1182 public:
1183     OutputInfo() = default;
1184     OutputInfo(const OutputInfo&) = default;
1185     explicit OutputInfo(xcb_randr_output_t c, xcb_timestamp_t t) : Wrapper<OutputInfoData, xcb_randr_output_t, xcb_timestamp_t>(c, t) {}
1186 
1187     inline QString name() {
1188         const OutputInfoData::reply_type *info = data();
1189         if (!info || info->num_crtcs == 0 || info->num_modes == 0 || info->status != XCB_RANDR_SET_CONFIG_SUCCESS) {
1190             return QString();
1191         }
1192         return QString::fromUtf8(reinterpret_cast<char*>(xcb_randr_get_output_info_name(info)), info->name_len);
1193     }
1194 };
1195 
1196 XCB_WRAPPER_DATA(CurrentResourcesData, xcb_randr_get_screen_resources_current, xcb_window_t)
1197 class CurrentResources : public Wrapper<CurrentResourcesData, xcb_window_t>
1198 {
1199 public:
1200     explicit CurrentResources(WindowId window) : Wrapper<CurrentResourcesData, xcb_window_t>(window) {}
1201 
1202     inline xcb_randr_crtc_t *crtcs() {
1203         if (isNull()) {
1204             return nullptr;
1205         }
1206         return xcb_randr_get_screen_resources_current_crtcs(data());
1207     }
1208     inline xcb_randr_mode_info_t *modes() {
1209         if (isNull()) {
1210             return nullptr;
1211         }
1212         return xcb_randr_get_screen_resources_current_modes(data());
1213     }
1214 };
1215 
1216 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*)
1217 }
1218 
1219 class ExtensionData
1220 {
1221 public:
1222     ExtensionData();
1223     int version;
1224     int eventBase;
1225     int errorBase;
1226     int majorOpcode;
1227     bool present;
1228     QByteArray name;
1229     QVector<QByteArray> opCodes;
1230     QVector<QByteArray> errorCodes;
1231 };
1232 
1233 class KWIN_EXPORT Extensions
1234 {
1235 public:
1236     bool isShapeAvailable() const {
1237         return m_shape.version > 0;
1238     }
1239     bool isShapeInputAvailable() const;
1240     int shapeNotifyEvent() const;
1241     bool hasShape(xcb_window_t w) const;
1242     bool isRandrAvailable() const {
1243         return m_randr.present;
1244     }
1245     int randrNotifyEvent() const;
1246     bool isDamageAvailable() const {
1247         return m_damage.present;
1248     }
1249     int damageNotifyEvent() const;
1250     bool isCompositeAvailable() const {
1251         return m_composite.version > 0;
1252     }
1253     bool isCompositeOverlayAvailable() const;
1254     bool isRenderAvailable() const {
1255         return m_render.version > 0;
1256     }
1257     bool isFixesAvailable() const {
1258         return m_fixes.version > 0;
1259     }
1260     int fixesCursorNotifyEvent() const;
1261     int fixesSelectionNotifyEvent() const;
1262     bool isFixesRegionAvailable() const;
1263     bool isSyncAvailable() const {
1264         return m_sync.present;
1265     }
1266     int syncAlarmNotifyEvent() const;
1267     QVector<ExtensionData> extensions() const;
1268     bool hasGlx() const {
1269         return m_glx.present;
1270     }
1271     int glxEventBase() const {
1272         return m_glx.eventBase;
1273     }
1274     int glxMajorOpcode() const {
1275         return m_glx.majorOpcode;
1276     }
1277 
1278     static Extensions *self();
1279     static void destroy();
1280 private:
1281     Extensions();
1282     ~Extensions();
1283     void init();
1284     template <typename reply, typename T, typename F>
1285     void initVersion(T cookie, F f, ExtensionData *dataToFill);
1286     void extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill);
1287 
1288     ExtensionData m_shape;
1289     ExtensionData m_randr;
1290     ExtensionData m_damage;
1291     ExtensionData m_composite;
1292     ExtensionData m_render;
1293     ExtensionData m_fixes;
1294     ExtensionData m_sync;
1295     ExtensionData m_glx;
1296 
1297     static Extensions *s_self;
1298 };
1299 
1300 /**
1301  * This class is an RAII wrapper for an xcb_window_t. An xcb_window_t hold by an instance of this class
1302  * will be freed when the instance gets destroyed.
1303  *
1304  * Furthermore the class provides wrappers around some xcb methods operating on an xcb_window_t.
1305  *
1306  * For the cases that one is more interested in wrapping the xcb methods the constructor which takes
1307  * an existing window and the @ref reset method allow to disable the RAII functionality.
1308  */
1309 class Window
1310 {
1311 public:
1312     /**
1313      * Takes over responsibility of @p window. If @p window is not provided an invalid Window is
1314      * created. Use @ref create to set an xcb_window_t later on.
1315      *
1316      * If @p destroy is @c true the window will be destroyed together with this object, if @c false
1317      * the window will be kept around. This is useful if you are not interested in the RAII capabilities
1318      * but still want to use a window like an object.
1319      *
1320      * @param window The window to manage.
1321      * @param destroy Whether the window should be destroyed together with the object.
1322      * @see reset
1323      */
1324     Window(xcb_window_t window = XCB_WINDOW_NONE, bool destroy = true);
1325     /**
1326      * Creates an xcb_window_t and manages it. It's a convenient method to create a window with
1327      * depth, class and visual being copied from parent and border being @c 0.
1328      * @param geometry The geometry for the window to be created
1329      * @param mask The mask for the values
1330      * @param values The values to be passed to xcb_create_window
1331      * @param parent The parent window
1332      */
1333     Window(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
1334     /**
1335      * Creates an xcb_window_t and manages it. It's a convenient method to create a window with
1336      * depth and visual being copied from parent and border being @c 0.
1337      * @param geometry The geometry for the window to be created
1338      * @param windowClass The window class
1339      * @param mask The mask for the values
1340      * @param values The values to be passed to xcb_create_window
1341      * @param parent The parent window
1342      */
1343     Window(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
1344     Window(const Window &other) = delete;
1345     ~Window();
1346 
1347     /**
1348      * Creates a new window for which the responsibility is taken over. If a window had been managed
1349      * before it is freed.
1350      *
1351      * Depth, class and visual are being copied from parent and border is @c 0.
1352      * @param geometry The geometry for the window to be created
1353      * @param mask The mask for the values
1354      * @param values The values to be passed to xcb_create_window
1355      * @param parent The parent window
1356      */
1357     void create(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
1358     /**
1359      * Creates a new window for which the responsibility is taken over. If a window had been managed
1360      * before it is freed.
1361      *
1362      * Depth and visual are being copied from parent and border is @c 0.
1363      * @param geometry The geometry for the window to be created
1364      * @param windowClass The window class
1365      * @param mask The mask for the values
1366      * @param values The values to be passed to xcb_create_window
1367      * @param parent The parent window
1368      */
1369     void create(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
1370     /**
1371      * Frees the existing window and starts to manage the new @p window.
1372      * If @p destroy is @c true the new managed window will be destroyed together with this
1373      * object or when reset is called again. If @p destroy is @c false the window will not
1374      * be destroyed. It is then the responsibility of the caller to destroy the window.
1375      */
1376     void reset(xcb_window_t window = XCB_WINDOW_NONE, bool destroy = true);
1377     /**
1378      * @returns @c true if a window is managed, @c false otherwise.
1379      */
1380     bool isValid() const;
1381     inline const QRect &geometry() const { return m_logicGeometry; }
1382     /**
1383      * Configures the window with a new geometry.
1384      * @param geometry The new window geometry to be used
1385      */
1386     void setGeometry(const QRect &geometry);
1387     void setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
1388     void move(const QPoint &pos);
1389     void move(uint32_t x, uint32_t y);
1390     void resize(const QSize &size);
1391     void resize(uint32_t width, uint32_t height);
1392     void raise();
1393     void lower();
1394     void map();
1395     void unmap();
1396     void reparent(xcb_window_t parent, int x = 0, int y = 0);
1397     void changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length,
1398                         const void *data, uint8_t mode = XCB_PROP_MODE_REPLACE);
1399     void deleteProperty(xcb_atom_t property);
1400     void setBorderWidth(uint32_t width);
1401     void grabButton(uint8_t pointerMode, uint8_t keyboardmode,
1402                     uint16_t modifiers = XCB_MOD_MASK_ANY,
1403                     uint8_t button = XCB_BUTTON_INDEX_ANY,
1404                     uint16_t eventMask = XCB_EVENT_MASK_BUTTON_PRESS,
1405                     xcb_window_t confineTo = XCB_WINDOW_NONE,
1406                     xcb_cursor_t cursor = XCB_CURSOR_NONE,
1407                     bool ownerEvents = false);
1408     void ungrabButton(uint16_t modifiers = XCB_MOD_MASK_ANY, uint8_t button = XCB_BUTTON_INDEX_ANY);
1409     /**
1410      * Clears the window area. Same as xcb_clear_area with x, y, width, height being @c 0.
1411      */
1412     void clear();
1413     void setBackgroundPixmap(xcb_pixmap_t pixmap);
1414     void defineCursor(xcb_cursor_t cursor);
1415     void focus(uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = XCB_TIME_CURRENT_TIME);
1416     void selectInput(uint32_t events);
1417     void kill();
1418     operator xcb_window_t() const;
1419 private:
1420     xcb_window_t doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = nullptr, xcb_window_t parent = rootWindow());
1421     void destroy();
1422     xcb_window_t m_window;
1423     bool m_destroy;
1424     QRect m_logicGeometry;
1425 };
1426 
1427 inline
1428 Window::Window(xcb_window_t window, bool destroy)
1429     : m_window(window)
1430     , m_destroy(destroy)
1431 {
1432 }
1433 
1434 inline
1435 Window::Window(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
1436     : m_window(doCreate(geometry, XCB_COPY_FROM_PARENT, mask, values, parent))
1437     , m_destroy(true)
1438 {
1439 }
1440 
1441 inline
1442 Window::Window(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
1443     : m_window(doCreate(geometry, windowClass, mask, values, parent))
1444     , m_destroy(true)
1445 {
1446 }
1447 
1448 inline
1449 Window::~Window()
1450 {
1451     destroy();
1452 }
1453 
1454 inline
1455 void Window::destroy()
1456 {
1457     if (!isValid() || !m_destroy) {
1458         return;
1459     }
1460     xcb_destroy_window(connection(), m_window);
1461     m_window = XCB_WINDOW_NONE;
1462 }
1463 
1464 inline
1465 bool Window::isValid() const
1466 {
1467     return m_window != XCB_WINDOW_NONE;
1468 }
1469 
1470 inline
1471 Window::operator xcb_window_t() const
1472 {
1473     return m_window;
1474 }
1475 
1476 inline
1477 void Window::create(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
1478 {
1479     destroy();
1480     m_window = doCreate(geometry, windowClass, mask, values, parent);
1481 }
1482 
1483 inline
1484 void Window::create(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent)
1485 {
1486     create(geometry, XCB_COPY_FROM_PARENT, mask, values, parent);
1487 }
1488 
1489 inline
1490 xcb_window_t Window::doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
1491 {
1492     m_logicGeometry = geometry;
1493     xcb_window_t w = xcb_generate_id(connection());
1494     xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent,
1495                       geometry.x(), geometry.y(), geometry.width(), geometry.height(),
1496                       0, windowClass, XCB_COPY_FROM_PARENT, mask, values);
1497     return w;
1498 }
1499 
1500 inline
1501 void Window::reset(xcb_window_t window, bool shouldDestroy)
1502 {
1503     destroy();
1504     m_window = window;
1505     m_destroy = shouldDestroy;
1506 }
1507 
1508 inline
1509 void Window::setGeometry(const QRect &geometry)
1510 {
1511     setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height());
1512 }
1513 
1514 inline
1515 void Window::setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
1516 {
1517     m_logicGeometry.setRect(x, y, width, height);
1518     if (!isValid()) {
1519         return;
1520     }
1521     const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
1522     const uint32_t values[] = { x, y, width, height };
1523     xcb_configure_window(connection(), m_window, mask, values);
1524 }
1525 
1526 inline
1527 void Window::move(const QPoint &pos)
1528 {
1529     move(pos.x(), pos.y());
1530 }
1531 
1532 inline
1533 void Window::move(uint32_t x, uint32_t y)
1534 {
1535     m_logicGeometry.moveTo(x, y);
1536     if (!isValid()) {
1537         return;
1538     }
1539     moveWindow(m_window, x, y);
1540 }
1541 
1542 inline
1543 void Window::resize(const QSize &size)
1544 {
1545     resize(size.width(), size.height());
1546 }
1547 
1548 inline
1549 void Window::resize(uint32_t width, uint32_t height)
1550 {
1551     m_logicGeometry.setSize(QSize(width, height));
1552     if (!isValid()) {
1553         return;
1554     }
1555     const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
1556     const uint32_t values[] = { width, height };
1557     xcb_configure_window(connection(), m_window, mask, values);
1558 }
1559 
1560 inline
1561 void Window::raise()
1562 {
1563     const uint32_t values[] = { XCB_STACK_MODE_ABOVE };
1564     xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_STACK_MODE, values);
1565 }
1566 
1567 inline
1568 void Window::lower()
1569 {
1570     lowerWindow(m_window);
1571 }
1572 
1573 inline
1574 void Window::map()
1575 {
1576     if (!isValid()) {
1577         return;
1578     }
1579     xcb_map_window(connection(), m_window);
1580 }
1581 
1582 inline
1583 void Window::unmap()
1584 {
1585     if (!isValid()) {
1586         return;
1587     }
1588     xcb_unmap_window(connection(), m_window);
1589 }
1590 
1591 inline
1592 void Window::reparent(xcb_window_t parent, int x, int y)
1593 {
1594     if (!isValid()) {
1595         return;
1596     }
1597     xcb_reparent_window(connection(), m_window, parent, x, y);
1598 }
1599 
1600 inline
1601 void Window::changeProperty(xcb_atom_t property, xcb_atom_t type, uint8_t format, uint32_t length, const void *data, uint8_t mode)
1602 {
1603     if (!isValid()) {
1604         return;
1605     }
1606     xcb_change_property(connection(), mode, m_window, property, type, format, length, data);
1607 }
1608 
1609 inline
1610 void Window::deleteProperty(xcb_atom_t property)
1611 {
1612     if (!isValid()) {
1613         return;
1614     }
1615     xcb_delete_property(connection(), m_window, property);
1616 }
1617 
1618 inline
1619 void Window::setBorderWidth(uint32_t width)
1620 {
1621     if (!isValid()) {
1622         return;
1623     }
1624     xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_BORDER_WIDTH, &width);
1625 }
1626 
1627 inline
1628 void Window::grabButton(uint8_t pointerMode, uint8_t keyboardmode, uint16_t modifiers,
1629                         uint8_t button, uint16_t eventMask, xcb_window_t confineTo,
1630                         xcb_cursor_t cursor, bool ownerEvents)
1631 {
1632     if (!isValid()) {
1633         return;
1634     }
1635     xcb_grab_button(connection(), ownerEvents, m_window, eventMask,
1636                     pointerMode, keyboardmode, confineTo, cursor, button, modifiers);
1637 }
1638 
1639 inline
1640 void Window::ungrabButton(uint16_t modifiers, uint8_t button)
1641 {
1642     if (!isValid()) {
1643         return;
1644     }
1645     xcb_ungrab_button(connection(), button, m_window, modifiers);
1646 }
1647 
1648 inline
1649 void Window::clear()
1650 {
1651     if (!isValid()) {
1652         return;
1653     }
1654     xcb_clear_area(connection(), false, m_window, 0, 0, 0, 0);
1655 }
1656 
1657 inline
1658 void Window::setBackgroundPixmap(xcb_pixmap_t pixmap)
1659 {
1660     if (!isValid()) {
1661         return;
1662     }
1663     const uint32_t values[] = {pixmap};
1664     xcb_change_window_attributes(connection(), m_window, XCB_CW_BACK_PIXMAP, values);
1665 }
1666 
1667 inline
1668 void Window::defineCursor(xcb_cursor_t cursor)
1669 {
1670     Xcb::defineCursor(m_window, cursor);
1671 }
1672 
1673 inline
1674 void Window::focus(uint8_t revertTo, xcb_timestamp_t time)
1675 {
1676     setInputFocus(m_window, revertTo, time);
1677 }
1678 
1679 inline
1680 void Window::selectInput(uint32_t events)
1681 {
1682     Xcb::selectInput(m_window, events);
1683 }
1684 
1685 inline
1686 void Window::kill()
1687 {
1688     xcb_kill_client(connection(), m_window);
1689 }
1690 
1691 // helper functions
1692 static inline void moveResizeWindow(WindowId window, const QRect &geometry)
1693 {
1694     const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
1695     const uint32_t values[] = {
1696         static_cast<uint32_t>(geometry.x()),
1697         static_cast<uint32_t>(geometry.y()),
1698         static_cast<uint32_t>(geometry.width()),
1699         static_cast<uint32_t>(geometry.height())
1700     };
1701     xcb_configure_window(connection(), window, mask, values);
1702 }
1703 
1704 static inline void moveWindow(xcb_window_t window, const QPoint& pos)
1705 {
1706     moveWindow(window, pos.x(), pos.y());
1707 }
1708 
1709 static inline void moveWindow(xcb_window_t window, uint32_t x, uint32_t y)
1710 {
1711     const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
1712     const uint32_t values[] = { x, y };
1713     xcb_configure_window(connection(), window, mask, values);
1714 }
1715 
1716 static inline void lowerWindow(xcb_window_t window)
1717 {
1718     const uint32_t values[] = { XCB_STACK_MODE_BELOW };
1719     xcb_configure_window(connection(), window, XCB_CONFIG_WINDOW_STACK_MODE, values);
1720 }
1721 
1722 static inline WindowId createInputWindow(const QRect &geometry, uint32_t mask, const uint32_t *values)
1723 {
1724     WindowId window = xcb_generate_id(connection());
1725     xcb_create_window(connection(), 0, window, rootWindow(),
1726                       geometry.x(), geometry.y(), geometry.width(), geometry.height(),
1727                       0, XCB_WINDOW_CLASS_INPUT_ONLY,
1728                       XCB_COPY_FROM_PARENT, mask, values);
1729     return window;
1730 }
1731 
1732 static inline void restackWindows(const QVector<xcb_window_t> &windows)
1733 {
1734     if (windows.count() < 2) {
1735         // only one window, nothing to do
1736         return;
1737     }
1738     for (int i=1; i<windows.count(); ++i) {
1739         const uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
1740         const uint32_t stackingValues[] = {
1741             windows.at(i-1),
1742             XCB_STACK_MODE_BELOW
1743         };
1744         xcb_configure_window(connection(), windows.at(i), mask, stackingValues);
1745     }
1746 }
1747 
1748 static inline void restackWindowsWithRaise(const QVector<xcb_window_t> &windows)
1749 {
1750     if (windows.isEmpty()) {
1751         return;
1752     }
1753     const uint32_t values[] = { XCB_STACK_MODE_ABOVE };
1754     xcb_configure_window(connection(), windows.first(), XCB_CONFIG_WINDOW_STACK_MODE, values);
1755     restackWindows(windows);
1756 }
1757 
1758 static inline int defaultDepth()
1759 {
1760     static int depth = 0;
1761     if (depth != 0) {
1762         return depth;
1763     }
1764     int screen = Application::x11ScreenNumber();
1765     for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(connection()));
1766             it.rem;
1767             --screen, xcb_screen_next(&it)) {
1768         if (screen == 0) {
1769             depth = it.data->root_depth;
1770             break;
1771         }
1772     }
1773     return depth;
1774 }
1775 
1776 static inline xcb_rectangle_t fromQt(const QRect &rect)
1777 {
1778     xcb_rectangle_t rectangle;
1779     rectangle.x = rect.x();
1780     rectangle.y = rect.y();
1781     rectangle.width  = rect.width();
1782     rectangle.height = rect.height();
1783     return rectangle;
1784 }
1785 
1786 static inline QVector<xcb_rectangle_t> regionToRects(const QRegion &region)
1787 {
1788     QVector<xcb_rectangle_t> rects;
1789     rects.reserve(region.rectCount());
1790     for (const QRect &rect : region) {
1791         rects.append(Xcb::fromQt(rect));
1792     }
1793     return rects;
1794 }
1795 
1796 static inline void defineCursor(xcb_window_t window, xcb_cursor_t cursor)
1797 {
1798     xcb_change_window_attributes(connection(), window, XCB_CW_CURSOR, &cursor);
1799 }
1800 
1801 static inline void setInputFocus(xcb_window_t window, uint8_t revertTo, xcb_timestamp_t time)
1802 {
1803     xcb_set_input_focus(connection(), revertTo, window, time);
1804 }
1805 
1806 static inline void setTransientFor(xcb_window_t window, xcb_window_t transient_for_window)
1807 {
1808     xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_TRANSIENT_FOR,
1809                         XCB_ATOM_WINDOW, 32, 1, &transient_for_window);
1810 }
1811 
1812 static inline void sync()
1813 {
1814     auto *c = connection();
1815     const auto cookie = xcb_get_input_focus(c);
1816     xcb_generic_error_t *error = nullptr;
1817     ScopedCPointer<xcb_get_input_focus_reply_t> sync(xcb_get_input_focus_reply(c, cookie, &error));
1818     if (error) {
1819         free(error);
1820     }
1821 }
1822 
1823 void selectInput(xcb_window_t window, uint32_t events)
1824 {
1825     xcb_change_window_attributes(connection(), window, XCB_CW_EVENT_MASK, &events);
1826 }
1827 
1828 /**
1829  * @brief Small helper class to encapsulate SHM related functionality.
1830  */
1831 class Shm
1832 {
1833 public:
1834     Shm();
1835     ~Shm();
1836     int shmId() const;
1837     void *buffer() const;
1838     xcb_shm_seg_t segment() const;
1839     bool isValid() const;
1840     uint8_t pixmapFormat() const;
1841 private:
1842     bool init();
1843     int m_shmId;
1844     void *m_buffer;
1845     xcb_shm_seg_t m_segment;
1846     bool m_valid;
1847     uint8_t m_pixmapFormat;
1848 };
1849 
1850 inline
1851 void *Shm::buffer() const
1852 {
1853     return m_buffer;
1854 }
1855 
1856 inline
1857 bool Shm::isValid() const
1858 {
1859     return m_valid;
1860 }
1861 
1862 inline
1863 xcb_shm_seg_t Shm::segment() const
1864 {
1865     return m_segment;
1866 }
1867 
1868 inline
1869 int Shm::shmId() const
1870 {
1871     return m_shmId;
1872 }
1873 
1874 inline
1875 uint8_t Shm::pixmapFormat() const
1876 {
1877     return m_pixmapFormat;
1878 }
1879 
1880 } // namespace X11
1881 
1882 } // namespace KWin
1883 #endif // KWIN_X11_UTILS_H
1884