1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de> |
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 | |
21 | #include "overlaywindow.h" |
22 | |
23 | #include "kwinglobals.h" |
24 | #include "utils.h" |
25 | #include "xcbutils.h" |
26 | |
27 | #include "assert.h" |
28 | |
29 | #include <QVector> |
30 | |
31 | #include <xcb/composite.h> |
32 | #include <xcb/shape.h> |
33 | #if XCB_COMPOSITE_MAJOR_VERSION > 0 || XCB_COMPOSITE_MINOR_VERSION >= 3 |
34 | #define KWIN_HAVE_XCOMPOSITE_OVERLAY |
35 | #endif |
36 | |
37 | namespace KWin { |
38 | OverlayWindow::OverlayWindow() |
39 | : m_visible(true) |
40 | , m_shown(false) |
41 | , m_window(XCB_WINDOW_NONE) |
42 | { |
43 | } |
44 | |
45 | OverlayWindow::~OverlayWindow() |
46 | { |
47 | } |
48 | |
49 | bool OverlayWindow::create() |
50 | { |
51 | assert(m_window == XCB_WINDOW_NONE); |
52 | if (!Xcb::Extensions::self()->isCompositeOverlayAvailable()) |
53 | return false; |
54 | if (!Xcb::Extensions::self()->isShapeInputAvailable()) // needed in setupOverlay() |
55 | return false; |
56 | #ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY |
57 | Xcb::OverlayWindow overlay(rootWindow()); |
58 | if (overlay.isNull()) { |
59 | return false; |
60 | } |
61 | m_window = overlay->overlay_win; |
62 | if (m_window == XCB_WINDOW_NONE) |
63 | return false; |
64 | resize(QSize(displayWidth(), displayHeight())); |
65 | return true; |
66 | #else |
67 | return false; |
68 | #endif |
69 | } |
70 | |
71 | void OverlayWindow::setup(xcb_window_t window) |
72 | { |
73 | assert(m_window != XCB_WINDOW_NONE); |
74 | assert(Xcb::Extensions::self()->isShapeInputAvailable()); |
75 | setNoneBackgroundPixmap(m_window); |
76 | m_shape = QRegion(); |
77 | setShape(QRect(0, 0, displayWidth(), displayHeight())); |
78 | if (window != XCB_WINDOW_NONE) { |
79 | setNoneBackgroundPixmap(window); |
80 | setupInputShape(window); |
81 | } |
82 | const uint32_t eventMask = XCB_EVENT_MASK_VISIBILITY_CHANGE; |
83 | xcb_change_window_attributes(connection(), m_window, XCB_CW_EVENT_MASK, &eventMask); |
84 | } |
85 | |
86 | void OverlayWindow::setupInputShape(xcb_window_t window) |
87 | { |
88 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, window, 0, 0, 0, NULL); |
89 | } |
90 | |
91 | void OverlayWindow::setNoneBackgroundPixmap(xcb_window_t window) |
92 | { |
93 | const uint32_t mask = XCB_BACK_PIXMAP_NONE; |
94 | xcb_change_window_attributes(connection(), window, XCB_CW_BACK_PIXMAP, &mask); |
95 | } |
96 | |
97 | void OverlayWindow::show() |
98 | { |
99 | assert(m_window != XCB_WINDOW_NONE); |
100 | if (m_shown) |
101 | return; |
102 | xcb_map_subwindows(connection(), m_window); |
103 | xcb_map_window(connection(), m_window); |
104 | m_shown = true; |
105 | } |
106 | |
107 | void OverlayWindow::hide() |
108 | { |
109 | assert(m_window != XCB_WINDOW_NONE); |
110 | xcb_unmap_window(connection(), m_window); |
111 | m_shown = false; |
112 | setShape(QRect(0, 0, displayWidth(), displayHeight())); |
113 | } |
114 | |
115 | void OverlayWindow::setShape(const QRegion& reg) |
116 | { |
117 | // Avoid setting the same shape again, it causes flicker (apparently it is not a no-op |
118 | // and triggers something). |
119 | if (reg == m_shape) |
120 | return; |
121 | QVector< QRect > rects = reg.rects(); |
122 | xcb_rectangle_t *xrects = new xcb_rectangle_t[rects.count()]; |
123 | for (int i = 0; |
124 | i < rects.count(); |
125 | ++i) { |
126 | xrects[ i ].x = rects[ i ].x(); |
127 | xrects[ i ].y = rects[ i ].y(); |
128 | xrects[ i ].width = rects[ i ].width(); |
129 | xrects[ i ].height = rects[ i ].height(); |
130 | } |
131 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, |
132 | m_window, 0, 0, rects.count(), xrects); |
133 | delete[] xrects; |
134 | setupInputShape(m_window); |
135 | m_shape = reg; |
136 | } |
137 | |
138 | void OverlayWindow::resize(const QSize &size) |
139 | { |
140 | assert(m_window != XCB_WINDOW_NONE); |
141 | const uint32_t geometry[2] = { |
142 | static_cast<uint32_t>(size.width()), |
143 | static_cast<uint32_t>(size.height()) |
144 | }; |
145 | xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, geometry); |
146 | setShape(QRegion(0, 0, size.width(), size.height())); |
147 | } |
148 | |
149 | bool OverlayWindow::isVisible() const |
150 | { |
151 | return m_visible; |
152 | } |
153 | |
154 | void OverlayWindow::setVisibility(bool visible) |
155 | { |
156 | m_visible = visible; |
157 | } |
158 | |
159 | void OverlayWindow::destroy() |
160 | { |
161 | if (m_window == XCB_WINDOW_NONE) |
162 | return; |
163 | // reset the overlay shape |
164 | xcb_rectangle_t rec = { 0, 0, static_cast<uint16_t>(displayWidth()), static_cast<uint16_t>(displayHeight()) }; |
165 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec); |
166 | xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec); |
167 | #ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY |
168 | xcb_composite_release_overlay_window(connection(), m_window); |
169 | #endif |
170 | m_window = XCB_WINDOW_NONE; |
171 | m_shown = false; |
172 | } |
173 | |
174 | xcb_window_t OverlayWindow::window() const |
175 | { |
176 | return m_window; |
177 | } |
178 | |
179 | } // namespace KWin |
180 | |