1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org> |
6 | Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org> |
7 | |
8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | *********************************************************************/ |
21 | #include "xcbutils.h" |
22 | #include "utils.h" |
23 | // KDE |
24 | #include <KDE/KDebug> |
25 | // xcb |
26 | #include <xcb/composite.h> |
27 | #include <xcb/damage.h> |
28 | #include <xcb/randr.h> |
29 | #include <xcb/render.h> |
30 | #include <xcb/shape.h> |
31 | #include <xcb/sync.h> |
32 | #include <xcb/xfixes.h> |
33 | |
34 | namespace KWin { |
35 | |
36 | namespace Xcb { |
37 | |
38 | static const int COMPOSITE_MAX_MAJOR = 0; |
39 | static const int COMPOSITE_MAX_MINOR = 4; |
40 | static const int DAMAGE_MAX_MAJOR = 1; |
41 | static const int DAMAGE_MIN_MAJOR = 1; |
42 | static const int SYNC_MAX_MAJOR = 3; |
43 | static const int SYNC_MAX_MINOR = 0; |
44 | static const int RANDR_MAX_MAJOR = 1; |
45 | static const int RANDR_MAX_MINOR = 4; |
46 | static const int RENDER_MAX_MAJOR = 0; |
47 | static const int RENDER_MAX_MINOR = 11; |
48 | static const int XFIXES_MAX_MAJOR = 5; |
49 | static const int XFIXES_MAX_MINOR = 0; |
50 | |
51 | ExtensionData::ExtensionData() |
52 | : version(0) |
53 | , eventBase(0) |
54 | , errorBase(0) |
55 | , majorOpcode(0) |
56 | , present(0) |
57 | { |
58 | } |
59 | |
60 | template<typename reply, typename T, typename F> |
61 | void Extensions::initVersion(T cookie, F f, ExtensionData *dataToFill) |
62 | { |
63 | ScopedCPointer<reply> version(f(connection(), cookie, NULL)); |
64 | dataToFill->version = version->major_version * 0x10 + version->minor_version; |
65 | } |
66 | |
67 | Extensions *Extensions::s_self = NULL; |
68 | |
69 | Extensions *Extensions::self() |
70 | { |
71 | if (!s_self) { |
72 | s_self = new Extensions(); |
73 | } |
74 | return s_self; |
75 | } |
76 | |
77 | void Extensions::destroy() |
78 | { |
79 | delete s_self; |
80 | s_self = NULL; |
81 | } |
82 | |
83 | Extensions::Extensions() |
84 | { |
85 | init(); |
86 | } |
87 | |
88 | Extensions::~Extensions() |
89 | { |
90 | } |
91 | |
92 | void Extensions::init() |
93 | { |
94 | xcb_connection_t *c = connection(); |
95 | xcb_prefetch_extension_data(c, &xcb_shape_id); |
96 | xcb_prefetch_extension_data(c, &xcb_randr_id); |
97 | xcb_prefetch_extension_data(c, &xcb_damage_id); |
98 | xcb_prefetch_extension_data(c, &xcb_composite_id); |
99 | xcb_prefetch_extension_data(c, &xcb_xfixes_id); |
100 | xcb_prefetch_extension_data(c, &xcb_render_id); |
101 | xcb_prefetch_extension_data(c, &xcb_sync_id); |
102 | |
103 | m_shape.name = QByteArray("SHAPE" ); |
104 | m_randr.name = QByteArray("RANDR" ); |
105 | m_damage.name = QByteArray("DAMAGE" ); |
106 | m_composite.name = QByteArray("Composite" ); |
107 | m_fixes.name = QByteArray("XFIXES" ); |
108 | m_render.name = QByteArray("RENDER" ); |
109 | m_sync.name = QByteArray("SYNC" ); |
110 | |
111 | extensionQueryReply(xcb_get_extension_data(c, &xcb_shape_id), &m_shape); |
112 | extensionQueryReply(xcb_get_extension_data(c, &xcb_randr_id), &m_randr); |
113 | extensionQueryReply(xcb_get_extension_data(c, &xcb_damage_id), &m_damage); |
114 | extensionQueryReply(xcb_get_extension_data(c, &xcb_composite_id), &m_composite); |
115 | extensionQueryReply(xcb_get_extension_data(c, &xcb_xfixes_id), &m_fixes); |
116 | extensionQueryReply(xcb_get_extension_data(c, &xcb_render_id), &m_render); |
117 | extensionQueryReply(xcb_get_extension_data(c, &xcb_sync_id), &m_sync); |
118 | |
119 | // extension specific queries |
120 | xcb_shape_query_version_cookie_t shapeVersion; |
121 | xcb_randr_query_version_cookie_t randrVersion; |
122 | xcb_damage_query_version_cookie_t damageVersion; |
123 | xcb_composite_query_version_cookie_t compositeVersion; |
124 | xcb_xfixes_query_version_cookie_t xfixesVersion; |
125 | xcb_render_query_version_cookie_t renderVersion; |
126 | xcb_sync_initialize_cookie_t syncVersion; |
127 | if (m_shape.present) { |
128 | shapeVersion = xcb_shape_query_version_unchecked(c); |
129 | } |
130 | if (m_randr.present) { |
131 | randrVersion = xcb_randr_query_version_unchecked(c, RANDR_MAX_MAJOR, RANDR_MAX_MINOR); |
132 | } |
133 | if (m_damage.present) { |
134 | damageVersion = xcb_damage_query_version_unchecked(c, DAMAGE_MAX_MAJOR, DAMAGE_MIN_MAJOR); |
135 | } |
136 | if (m_composite.present) { |
137 | compositeVersion = xcb_composite_query_version_unchecked(c, COMPOSITE_MAX_MAJOR, COMPOSITE_MAX_MINOR); |
138 | } |
139 | if (m_fixes.present) { |
140 | xfixesVersion = xcb_xfixes_query_version_unchecked(c, XFIXES_MAX_MAJOR, XFIXES_MAX_MINOR); |
141 | } |
142 | if (m_render.present) { |
143 | renderVersion = xcb_render_query_version_unchecked(c, RENDER_MAX_MAJOR, RENDER_MAX_MINOR); |
144 | } |
145 | if (m_sync.present) { |
146 | syncVersion = xcb_sync_initialize(c, SYNC_MAX_MAJOR, SYNC_MAX_MINOR); |
147 | } |
148 | // handle replies |
149 | if (m_shape.present) { |
150 | initVersion<xcb_shape_query_version_reply_t>(shapeVersion, &xcb_shape_query_version_reply, &m_shape); |
151 | } |
152 | if (m_randr.present) { |
153 | initVersion<xcb_randr_query_version_reply_t>(randrVersion, &xcb_randr_query_version_reply, &m_randr); |
154 | } |
155 | if (m_damage.present) { |
156 | initVersion<xcb_damage_query_version_reply_t>(damageVersion, &xcb_damage_query_version_reply, &m_damage); |
157 | } |
158 | if (m_composite.present) { |
159 | initVersion<xcb_composite_query_version_reply_t>(compositeVersion, &xcb_composite_query_version_reply, &m_composite); |
160 | } |
161 | if (m_fixes.present) { |
162 | initVersion<xcb_xfixes_query_version_reply_t>(xfixesVersion, &xcb_xfixes_query_version_reply, &m_fixes); |
163 | } |
164 | if (m_render.present) { |
165 | initVersion<xcb_render_query_version_reply_t>(renderVersion, &xcb_render_query_version_reply, &m_render); |
166 | } |
167 | if (m_sync.present) { |
168 | initVersion<xcb_sync_initialize_reply_t>(syncVersion, &xcb_sync_initialize_reply, &m_sync); |
169 | } |
170 | kDebug(1212) << "Extensions: shape: 0x" << QString::number(m_shape.version, 16) |
171 | << " composite: 0x" << QString::number(m_composite.version, 16) |
172 | << " render: 0x" << QString::number(m_render.version, 16) |
173 | << " fixes: 0x" << QString::number(m_fixes.version, 16) |
174 | << " randr: 0x" << QString::number(m_randr.version, 16) |
175 | << " sync: 0x" << QString::number(m_sync.version, 16) |
176 | << " damage: 0x " << QString::number(m_damage.version, 16) << endl; |
177 | } |
178 | |
179 | void Extensions::extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill) |
180 | { |
181 | if (!extension) { |
182 | return; |
183 | } |
184 | dataToFill->present = extension->present; |
185 | dataToFill->eventBase = extension->first_event; |
186 | dataToFill->errorBase = extension->first_error; |
187 | dataToFill->majorOpcode = extension->major_opcode; |
188 | } |
189 | |
190 | int Extensions::damageNotifyEvent() const |
191 | { |
192 | return m_damage.eventBase + XCB_DAMAGE_NOTIFY; |
193 | } |
194 | |
195 | bool Extensions::hasShape(xcb_window_t w) const |
196 | { |
197 | if (!isShapeAvailable()) { |
198 | return false; |
199 | } |
200 | ScopedCPointer<xcb_shape_query_extents_reply_t> extents(xcb_shape_query_extents_reply( |
201 | connection(), xcb_shape_query_extents_unchecked(connection(), w), NULL)); |
202 | if (extents.isNull()) { |
203 | return false; |
204 | } |
205 | return extents->bounding_shaped > 0; |
206 | } |
207 | |
208 | bool Extensions::isCompositeOverlayAvailable() const |
209 | { |
210 | return m_composite.version >= 0x03; // 0.3 |
211 | } |
212 | |
213 | bool Extensions::isFixesRegionAvailable() const |
214 | { |
215 | return m_fixes.version >= 0x30; // 3 |
216 | } |
217 | |
218 | int Extensions::fixesCursorNotifyEvent() const |
219 | { |
220 | return m_fixes.eventBase + XCB_XFIXES_CURSOR_NOTIFY; |
221 | } |
222 | |
223 | bool Extensions::isShapeInputAvailable() const |
224 | { |
225 | return m_shape.version >= 0x11; // 1.1 |
226 | } |
227 | |
228 | int Extensions::randrNotifyEvent() const |
229 | { |
230 | return m_randr.eventBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY; |
231 | } |
232 | |
233 | int Extensions::shapeNotifyEvent() const |
234 | { |
235 | return m_shape.eventBase + XCB_SHAPE_NOTIFY; |
236 | } |
237 | |
238 | int Extensions::syncAlarmNotifyEvent() const |
239 | { |
240 | return m_sync.eventBase + XCB_SYNC_ALARM_NOTIFY; |
241 | } |
242 | |
243 | QVector<ExtensionData> Extensions::extensions() const |
244 | { |
245 | QVector<ExtensionData> extensions; |
246 | extensions << m_shape |
247 | << m_randr |
248 | << m_damage |
249 | << m_composite |
250 | << m_render |
251 | << m_fixes |
252 | << m_sync; |
253 | return extensions; |
254 | } |
255 | |
256 | } // namespace Xcb |
257 | } // namespace KWin |
258 | |