File indexing completed on 2025-03-23 11:14:19
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 ®ion) 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