1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2012, 2013 Martin Gräßlin <mgraesslin@kde.org> |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | *********************************************************************/ |
20 | #ifndef KWIN_XCB_UTILS_H |
21 | #define KWIN_XCB_UTILS_H |
22 | |
23 | #include <kwinglobals.h> |
24 | #include "utils.h" |
25 | |
26 | #include <QRect> |
27 | #include <QRegion> |
28 | #include <QVector> |
29 | |
30 | #include <xcb/xcb.h> |
31 | #include <xcb/composite.h> |
32 | |
33 | namespace KWin { |
34 | |
35 | namespace Xcb { |
36 | |
37 | typedef xcb_window_t WindowId; |
38 | |
39 | // forward declaration of methods |
40 | static void defineCursor(xcb_window_t window, xcb_cursor_t cursor); |
41 | static void setInputFocus(xcb_window_t window, uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = xTime()); |
42 | static void moveWindow(xcb_window_t window, const QPoint &pos); |
43 | static void moveWindow(xcb_window_t window, uint32_t x, uint32_t y); |
44 | |
45 | template <typename Reply, |
46 | typename Cookie, |
47 | Reply *(*replyFunc)(xcb_connection_t*, Cookie, xcb_generic_error_t**), |
48 | Cookie (*requestFunc)(xcb_connection_t*, xcb_window_t)> |
49 | class Wrapper |
50 | { |
51 | public: |
52 | Wrapper() |
53 | : m_retrieved(false) |
54 | , m_window(XCB_WINDOW_NONE) |
55 | , m_reply(NULL) |
56 | { |
57 | m_cookie.sequence = 0; |
58 | } |
59 | explicit Wrapper(WindowId window) |
60 | : m_retrieved(false) |
61 | , m_cookie(requestFunc(connection(), window)) |
62 | , m_window(window) |
63 | , m_reply(NULL) |
64 | { |
65 | } |
66 | explicit Wrapper(const Wrapper &other) |
67 | : m_retrieved(other.m_retrieved) |
68 | , m_cookie(other.m_cookie) |
69 | , m_window(other.m_window) |
70 | , m_reply(NULL) |
71 | { |
72 | takeFromOther(const_cast<Wrapper&>(other)); |
73 | } |
74 | virtual ~Wrapper() { |
75 | cleanup(); |
76 | } |
77 | inline Wrapper &operator=(const Wrapper &other) { |
78 | if (this != &other) { |
79 | // if we had managed a reply, free it |
80 | cleanup(); |
81 | // copy members |
82 | m_retrieved = other.m_retrieved; |
83 | m_cookie = other.m_cookie; |
84 | m_window = other.m_window; |
85 | m_reply = other.m_reply; |
86 | // take over the responsibility for the reply pointer |
87 | takeFromOther(const_cast<Wrapper&>(other)); |
88 | } |
89 | return *this; |
90 | } |
91 | |
92 | inline const Reply *operator->() { |
93 | getReply(); |
94 | return m_reply; |
95 | } |
96 | inline bool isNull() { |
97 | getReply(); |
98 | return m_reply == NULL; |
99 | } |
100 | inline operator bool() { |
101 | return !isNull(); |
102 | } |
103 | inline const Reply *data() { |
104 | getReply(); |
105 | return m_reply; |
106 | } |
107 | inline WindowId window() const { |
108 | return m_window; |
109 | } |
110 | inline bool isRetrieved() const { |
111 | return m_retrieved; |
112 | } |
113 | /** |
114 | * Returns the value of the reply pointer referenced by this object. The reply pointer of |
115 | * this object will be reset to null. Calling any method which requires the reply to be valid |
116 | * will crash. |
117 | * |
118 | * Callers of this function take ownership of the pointer. |
119 | **/ |
120 | inline Reply *take() { |
121 | getReply(); |
122 | Reply *ret = m_reply; |
123 | m_reply = NULL; |
124 | m_window = XCB_WINDOW_NONE; |
125 | return ret; |
126 | } |
127 | |
128 | protected: |
129 | void getReply() { |
130 | if (m_retrieved || !m_cookie.sequence) { |
131 | return; |
132 | } |
133 | m_reply = replyFunc(connection(), m_cookie, NULL); |
134 | m_retrieved = true; |
135 | } |
136 | |
137 | private: |
138 | inline void cleanup() { |
139 | if (!m_retrieved && m_cookie.sequence) { |
140 | xcb_discard_reply(connection(), m_cookie.sequence); |
141 | } else if (m_reply) { |
142 | free(m_reply); |
143 | } |
144 | } |
145 | inline void takeFromOther(Wrapper &other) { |
146 | if (m_retrieved) { |
147 | m_reply = other.take(); |
148 | } else { |
149 | //ensure that other object doesn't try to get the reply or discards it in the dtor |
150 | other.m_retrieved = true; |
151 | other.m_window = XCB_WINDOW_NONE; |
152 | } |
153 | } |
154 | bool m_retrieved; |
155 | Cookie m_cookie; |
156 | WindowId m_window; |
157 | Reply *m_reply; |
158 | }; |
159 | |
160 | typedef Wrapper<xcb_get_window_attributes_reply_t, xcb_get_window_attributes_cookie_t, &xcb_get_window_attributes_reply, &xcb_get_window_attributes_unchecked> WindowAttributes; |
161 | typedef Wrapper<xcb_composite_get_overlay_window_reply_t, xcb_composite_get_overlay_window_cookie_t, &xcb_composite_get_overlay_window_reply, &xcb_composite_get_overlay_window_unchecked> OverlayWindow; |
162 | |
163 | |
164 | class WindowGeometry : public Wrapper<xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, &xcb_get_geometry_reply, &xcb_get_geometry_unchecked> |
165 | { |
166 | public: |
167 | WindowGeometry() : Wrapper<xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, &xcb_get_geometry_reply, &xcb_get_geometry_unchecked>() {} |
168 | explicit WindowGeometry(xcb_window_t window) : Wrapper<xcb_get_geometry_reply_t, xcb_get_geometry_cookie_t, &xcb_get_geometry_reply, &xcb_get_geometry_unchecked>(window) {} |
169 | |
170 | inline QRect rect() { |
171 | const xcb_get_geometry_reply_t *geometry = data(); |
172 | if (!geometry) { |
173 | return QRect(); |
174 | } |
175 | return QRect(geometry->x, geometry->y, geometry->width, geometry->height); |
176 | } |
177 | }; |
178 | |
179 | class Tree : public Wrapper<xcb_query_tree_reply_t, xcb_query_tree_cookie_t, &xcb_query_tree_reply, &xcb_query_tree_unchecked> |
180 | { |
181 | public: |
182 | explicit Tree(WindowId window) : Wrapper<xcb_query_tree_reply_t, xcb_query_tree_cookie_t, &xcb_query_tree_reply, &xcb_query_tree_unchecked>(window) {} |
183 | |
184 | inline WindowId *children() { |
185 | return xcb_query_tree_children(data()); |
186 | } |
187 | inline xcb_window_t parent() { |
188 | if (isNull()) |
189 | return XCB_WINDOW_NONE; |
190 | return (*this)->parent; |
191 | } |
192 | }; |
193 | |
194 | inline xcb_get_input_focus_cookie_t get_input_focus(xcb_connection_t *c, xcb_window_t) { |
195 | return xcb_get_input_focus(c); |
196 | } |
197 | class CurrentInput : public Wrapper<xcb_get_input_focus_reply_t, xcb_get_input_focus_cookie_t, &xcb_get_input_focus_reply, &get_input_focus> |
198 | { |
199 | public: |
200 | CurrentInput() : Wrapper<xcb_get_input_focus_reply_t, xcb_get_input_focus_cookie_t, &xcb_get_input_focus_reply, &get_input_focus>(XCB_WINDOW_NONE) {} |
201 | |
202 | inline xcb_window_t window() { |
203 | if (isNull()) |
204 | return XCB_WINDOW_NONE; |
205 | return (*this)->focus; |
206 | } |
207 | }; |
208 | |
209 | inline xcb_get_property_cookie_t get_transient_for(xcb_connection_t *c, xcb_window_t window) |
210 | { |
211 | return xcb_get_property_unchecked(c, 0, window, XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 0, 1); |
212 | } |
213 | |
214 | class TransientFor : public Wrapper<xcb_get_property_reply_t, xcb_get_property_cookie_t, &xcb_get_property_reply, &get_transient_for> |
215 | { |
216 | public: |
217 | explicit TransientFor(WindowId window) : Wrapper<xcb_get_property_reply_t, xcb_get_property_cookie_t, &xcb_get_property_reply, &get_transient_for>(window) {} |
218 | |
219 | /** |
220 | * @brief Fill given window pointer with the WM_TRANSIENT_FOR property of a window. |
221 | * @param prop WM_TRANSIENT_FOR property value. |
222 | * @returns @c true on success, @c false otherwise |
223 | **/ |
224 | inline bool getTransientFor(WindowId *prop) { |
225 | if (isNull()) { |
226 | return false; |
227 | } |
228 | |
229 | const xcb_get_property_reply_t *reply = data(); |
230 | if (!reply || reply->type != XCB_ATOM_WINDOW || reply->format != 32 || reply->length == 0) |
231 | return false; |
232 | |
233 | *prop = *reinterpret_cast<WindowId *>(xcb_get_property_value(reply)); |
234 | return true; |
235 | } |
236 | }; |
237 | |
238 | class ExtensionData |
239 | { |
240 | public: |
241 | ExtensionData(); |
242 | int version; |
243 | int eventBase; |
244 | int errorBase; |
245 | int majorOpcode; |
246 | bool present; |
247 | QByteArray name; |
248 | }; |
249 | |
250 | class Extensions |
251 | { |
252 | public: |
253 | bool isShapeAvailable() const { |
254 | return m_shape.version > 0; |
255 | } |
256 | bool isShapeInputAvailable() const; |
257 | int shapeNotifyEvent() const; |
258 | bool hasShape(xcb_window_t w) const; |
259 | bool isRandrAvailable() const { |
260 | return m_randr.present; |
261 | } |
262 | int randrNotifyEvent() const; |
263 | bool isDamageAvailable() const { |
264 | return m_damage.present; |
265 | } |
266 | int damageNotifyEvent() const; |
267 | bool isCompositeAvailable() const { |
268 | return m_composite.version > 0; |
269 | } |
270 | bool isCompositeOverlayAvailable() const; |
271 | bool isRenderAvailable() const { |
272 | return m_render.version > 0; |
273 | } |
274 | bool isFixesAvailable() const { |
275 | return m_fixes.version > 0; |
276 | } |
277 | int fixesCursorNotifyEvent() const; |
278 | bool isFixesRegionAvailable() const; |
279 | bool isSyncAvailable() const { |
280 | return m_sync.present; |
281 | } |
282 | int syncAlarmNotifyEvent() const; |
283 | QVector<ExtensionData> extensions() const; |
284 | |
285 | static Extensions *self(); |
286 | static void destroy(); |
287 | private: |
288 | Extensions(); |
289 | ~Extensions(); |
290 | void init(); |
291 | template <typename reply, typename T, typename F> |
292 | void initVersion(T cookie, F f, ExtensionData *dataToFill); |
293 | void extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill); |
294 | |
295 | ExtensionData m_shape; |
296 | ExtensionData m_randr; |
297 | ExtensionData m_damage; |
298 | ExtensionData m_composite; |
299 | ExtensionData m_render; |
300 | ExtensionData m_fixes; |
301 | ExtensionData m_sync; |
302 | |
303 | static Extensions *s_self; |
304 | }; |
305 | |
306 | /** |
307 | * This class is an RAII wrapper for an xcb_window_t. An xcb_window_t hold by an instance of this class |
308 | * will be freed when the instance gets destroyed. |
309 | * |
310 | * Furthermore the class provides wrappers around some xcb methods operating on an xcb_window_t. |
311 | **/ |
312 | class Window |
313 | { |
314 | public: |
315 | /** |
316 | * Takes over responsibility of @p window. If @p window is not provided an invalid Window is |
317 | * created. Use @link create to set an xcb_window_t later on. |
318 | * @param window The window to manage. |
319 | **/ |
320 | Window(xcb_window_t window = XCB_WINDOW_NONE); |
321 | /** |
322 | * Creates an xcb_window_t and manages it. It's a convenient method to create a window with |
323 | * depth, class and visual being copied from parent and border being @c 0. |
324 | * @param geometry The geometry for the window to be created |
325 | * @param mask The mask for the values |
326 | * @param values The values to be passed to xcb_create_window |
327 | * @param parent The parent window |
328 | **/ |
329 | Window(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow()); |
330 | /** |
331 | * Creates an xcb_window_t and manages it. It's a convenient method to create a window with |
332 | * depth and visual being copied from parent and border being @c 0. |
333 | * @param geometry The geometry for the window to be created |
334 | * @param class The window class |
335 | * @param mask The mask for the values |
336 | * @param values The values to be passed to xcb_create_window |
337 | * @param parent The parent window |
338 | **/ |
339 | Window(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow()); |
340 | ~Window(); |
341 | |
342 | /** |
343 | * Creates a new window for which the responsibility is taken over. If a window had been managed |
344 | * before it is freed. |
345 | * |
346 | * Depth, class and visual are being copied from parent and border is @c 0. |
347 | * @param geometry The geometry for the window to be created |
348 | * @param mask The mask for the values |
349 | * @param values The values to be passed to xcb_create_window |
350 | * @param parent The parent window |
351 | **/ |
352 | void create(const QRect &geometry, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow()); |
353 | /** |
354 | * Creates a new window for which the responsibility is taken over. If a window had been managed |
355 | * before it is freed. |
356 | * |
357 | * Depth and visual are being copied from parent and border is @c 0. |
358 | * @param geometry The geometry for the window to be created |
359 | * @param class The window class |
360 | * @param mask The mask for the values |
361 | * @param values The values to be passed to xcb_create_window |
362 | * @param parent The parent window |
363 | **/ |
364 | void create(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow()); |
365 | /** |
366 | * Frees the existing window and starts to manage the new @p window. |
367 | **/ |
368 | void reset(xcb_window_t window = XCB_WINDOW_NONE); |
369 | /** |
370 | * @returns @c true if a window is managed, @c false otherwise. |
371 | **/ |
372 | bool isValid() const; |
373 | /** |
374 | * Configures the window with a new geometry. |
375 | * @param geometry The new window geometry to be used |
376 | **/ |
377 | void setGeometry(const QRect &geometry); |
378 | void setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height); |
379 | void move(const QPoint &pos); |
380 | void move(uint32_t x, uint32_t y); |
381 | void resize(const QSize &size); |
382 | void resize(uint32_t width, uint32_t height); |
383 | void raise(); |
384 | void map(); |
385 | void unmap(); |
386 | /** |
387 | * Clears the window area. Same as xcb_clear_area with x, y, width, height being @c 0. |
388 | **/ |
389 | void clear(); |
390 | void setBackgroundPixmap(xcb_pixmap_t pixmap); |
391 | void defineCursor(xcb_cursor_t cursor); |
392 | void focus(uint8_t revertTo = XCB_INPUT_FOCUS_POINTER_ROOT, xcb_timestamp_t time = xTime()); |
393 | operator xcb_window_t() const; |
394 | private: |
395 | Window(const Window &other); |
396 | xcb_window_t doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask = 0, const uint32_t *values = NULL, xcb_window_t parent = rootWindow()); |
397 | void destroy(); |
398 | xcb_window_t m_window; |
399 | }; |
400 | |
401 | inline |
402 | Window::Window(xcb_window_t window) |
403 | : m_window(window) |
404 | { |
405 | } |
406 | |
407 | inline |
408 | Window::Window(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent) |
409 | : m_window(doCreate(geometry, XCB_COPY_FROM_PARENT, mask, values, parent)) |
410 | { |
411 | } |
412 | |
413 | inline |
414 | Window::Window(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent) |
415 | : m_window(doCreate(geometry, windowClass, mask, values, parent)) |
416 | { |
417 | } |
418 | |
419 | inline |
420 | Window::~Window() |
421 | { |
422 | destroy(); |
423 | } |
424 | |
425 | inline |
426 | void Window::destroy() |
427 | { |
428 | if (!isValid()) { |
429 | return; |
430 | } |
431 | xcb_destroy_window(connection(), m_window); |
432 | m_window = XCB_WINDOW_NONE; |
433 | } |
434 | |
435 | inline |
436 | bool Window::isValid() const |
437 | { |
438 | return m_window != XCB_WINDOW_NONE; |
439 | } |
440 | |
441 | inline |
442 | Window::operator xcb_window_t() const |
443 | { |
444 | return m_window; |
445 | } |
446 | |
447 | inline |
448 | void Window::create(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent) |
449 | { |
450 | destroy(); |
451 | m_window = doCreate(geometry, windowClass, mask, values, parent); |
452 | } |
453 | |
454 | inline |
455 | void Window::create(const QRect &geometry, uint32_t mask, const uint32_t *values, xcb_window_t parent) |
456 | { |
457 | create(geometry, XCB_COPY_FROM_PARENT, mask, values, parent); |
458 | } |
459 | |
460 | inline |
461 | xcb_window_t Window::doCreate(const QRect &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent) |
462 | { |
463 | xcb_window_t w = xcb_generate_id(connection()); |
464 | xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent, |
465 | geometry.x(), geometry.y(), geometry.width(), geometry.height(), |
466 | 0, windowClass, XCB_COPY_FROM_PARENT, mask, values); |
467 | return w; |
468 | } |
469 | |
470 | inline |
471 | void Window::reset(xcb_window_t window) |
472 | { |
473 | destroy(); |
474 | m_window = window; |
475 | } |
476 | |
477 | inline |
478 | void Window::setGeometry(const QRect &geometry) |
479 | { |
480 | setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height()); |
481 | } |
482 | |
483 | inline |
484 | void Window::setGeometry(uint32_t x, uint32_t y, uint32_t width, uint32_t height) |
485 | { |
486 | if (!isValid()) { |
487 | return; |
488 | } |
489 | const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; |
490 | const uint32_t values[] = { x, y, width, height }; |
491 | xcb_configure_window(connection(), m_window, mask, values); |
492 | } |
493 | |
494 | inline |
495 | void Window::move(const QPoint &pos) |
496 | { |
497 | move(pos.x(), pos.y()); |
498 | } |
499 | |
500 | inline |
501 | void Window::move(uint32_t x, uint32_t y) |
502 | { |
503 | if (!isValid()) { |
504 | return; |
505 | } |
506 | moveWindow(m_window, x, y); |
507 | } |
508 | |
509 | inline |
510 | void Window::resize(const QSize &size) |
511 | { |
512 | resize(size.width(), size.height()); |
513 | } |
514 | |
515 | inline |
516 | void Window::resize(uint32_t width, uint32_t height) |
517 | { |
518 | if (!isValid()) { |
519 | return; |
520 | } |
521 | const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; |
522 | const uint32_t values[] = { width, height }; |
523 | xcb_configure_window(connection(), m_window, mask, values); |
524 | } |
525 | |
526 | inline |
527 | void Window::raise() |
528 | { |
529 | const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; |
530 | xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_STACK_MODE, values); |
531 | } |
532 | |
533 | inline |
534 | void Window::map() |
535 | { |
536 | if (!isValid()) { |
537 | return; |
538 | } |
539 | xcb_map_window(connection(), m_window); |
540 | } |
541 | |
542 | inline |
543 | void Window::unmap() |
544 | { |
545 | if (!isValid()) { |
546 | return; |
547 | } |
548 | xcb_unmap_window(connection(), m_window); |
549 | } |
550 | |
551 | inline |
552 | void Window::clear() |
553 | { |
554 | if (!isValid()) { |
555 | return; |
556 | } |
557 | xcb_clear_area(connection(), false, m_window, 0, 0, 0, 0); |
558 | } |
559 | |
560 | inline |
561 | void Window::setBackgroundPixmap(xcb_pixmap_t pixmap) |
562 | { |
563 | if (!isValid()) { |
564 | return; |
565 | } |
566 | const uint32_t values[] = {pixmap}; |
567 | xcb_change_window_attributes(connection(), m_window, XCB_CW_BACK_PIXMAP, values); |
568 | } |
569 | |
570 | inline |
571 | void Window::defineCursor(xcb_cursor_t cursor) |
572 | { |
573 | Xcb::defineCursor(m_window, cursor); |
574 | } |
575 | |
576 | inline |
577 | void Window::focus(uint8_t revertTo, xcb_timestamp_t time) |
578 | { |
579 | setInputFocus(m_window, revertTo, time); |
580 | } |
581 | |
582 | // helper functions |
583 | static inline void moveResizeWindow(WindowId window, const QRect &geometry) |
584 | { |
585 | const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; |
586 | const uint32_t values[] = { |
587 | static_cast<uint32_t>(geometry.x()), |
588 | static_cast<uint32_t>(geometry.y()), |
589 | static_cast<uint32_t>(geometry.width()), |
590 | static_cast<uint32_t>(geometry.height()) |
591 | }; |
592 | xcb_configure_window(connection(), window, mask, values); |
593 | } |
594 | |
595 | static inline void moveWindow(xcb_window_t window, const QPoint& pos) |
596 | { |
597 | moveWindow(window, pos.x(), pos.y()); |
598 | } |
599 | |
600 | static inline void moveWindow(xcb_window_t window, uint32_t x, uint32_t y) |
601 | { |
602 | const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y; |
603 | const uint32_t values[] = { x, y }; |
604 | xcb_configure_window(connection(), window, mask, values); |
605 | } |
606 | |
607 | static inline WindowId createInputWindow(const QRect &geometry, uint32_t mask, const uint32_t *values) |
608 | { |
609 | WindowId window = xcb_generate_id(connection()); |
610 | xcb_create_window(connection(), 0, window, rootWindow(), |
611 | geometry.x(), geometry.y(), geometry.width(), geometry.height(), |
612 | 0, XCB_WINDOW_CLASS_INPUT_ONLY, |
613 | XCB_COPY_FROM_PARENT, mask, values); |
614 | return window; |
615 | } |
616 | |
617 | static inline void restackWindows(const QVector<xcb_window_t> &windows) |
618 | { |
619 | if (windows.count() < 2) { |
620 | // only one window, nothing to do |
621 | return; |
622 | } |
623 | for (int i=1; i<windows.count(); ++i) { |
624 | const uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; |
625 | const uint32_t stackingValues[] = { |
626 | windows.at(i-1), |
627 | XCB_STACK_MODE_BELOW |
628 | }; |
629 | xcb_configure_window(connection(), windows.at(i), mask, stackingValues); |
630 | } |
631 | } |
632 | |
633 | static inline void restackWindowsWithRaise(const QVector<xcb_window_t> &windows) |
634 | { |
635 | if (windows.isEmpty()) { |
636 | return; |
637 | } |
638 | const uint32_t values[] = { XCB_STACK_MODE_ABOVE }; |
639 | xcb_configure_window(connection(), windows.first(), XCB_CONFIG_WINDOW_STACK_MODE, values); |
640 | restackWindows(windows); |
641 | } |
642 | |
643 | static inline int defaultDepth() |
644 | { |
645 | static int depth = 0; |
646 | if (depth != 0) { |
647 | return depth; |
648 | } |
649 | int screen = QX11Info::appScreen(); |
650 | for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(connection())); |
651 | it.rem; |
652 | --screen, xcb_screen_next(&it)) { |
653 | if (screen == 0) { |
654 | depth = it.data->root_depth; |
655 | break; |
656 | } |
657 | } |
658 | return depth; |
659 | } |
660 | |
661 | static inline xcb_rectangle_t fromQt(const QRect &rect) |
662 | { |
663 | xcb_rectangle_t rectangle; |
664 | rectangle.x = rect.x(); |
665 | rectangle.y = rect.y(); |
666 | rectangle.width = rect.width(); |
667 | rectangle.height = rect.height(); |
668 | return rectangle; |
669 | } |
670 | |
671 | static inline QVector<xcb_rectangle_t> regionToRects(const QRegion ®ion) |
672 | { |
673 | const QVector<QRect> regionRects = region.rects(); |
674 | QVector<xcb_rectangle_t> rects(regionRects.count()); |
675 | for (int i=0; i<regionRects.count(); ++i) { |
676 | rects[i] = Xcb::fromQt(regionRects.at(i)); |
677 | } |
678 | return rects; |
679 | } |
680 | |
681 | static inline void defineCursor(xcb_window_t window, xcb_cursor_t cursor) |
682 | { |
683 | xcb_change_window_attributes(connection(), window, XCB_CW_CURSOR, &cursor); |
684 | } |
685 | |
686 | static inline void setInputFocus(xcb_window_t window, uint8_t revertTo, xcb_timestamp_t time) |
687 | { |
688 | xcb_set_input_focus(connection(), revertTo, window, time); |
689 | } |
690 | |
691 | static inline void setTransientFor(xcb_window_t window, xcb_window_t transient_for_window) |
692 | { |
693 | xcb_change_property(connection(), XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_TRANSIENT_FOR, |
694 | XCB_ATOM_WINDOW, 32, 1, &transient_for_window); |
695 | } |
696 | |
697 | } // namespace X11 |
698 | |
699 | } // namespace KWin |
700 | #endif // KWIN_X11_UTILS_H |
701 | |