1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
6Copyright (C) 2012 Martin Gräßlin <mgraesslin@kde.org>
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along 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
34namespace KWin {
35
36namespace Xcb {
37
38static const int COMPOSITE_MAX_MAJOR = 0;
39static const int COMPOSITE_MAX_MINOR = 4;
40static const int DAMAGE_MAX_MAJOR = 1;
41static const int DAMAGE_MIN_MAJOR = 1;
42static const int SYNC_MAX_MAJOR = 3;
43static const int SYNC_MAX_MINOR = 0;
44static const int RANDR_MAX_MAJOR = 1;
45static const int RANDR_MAX_MINOR = 4;
46static const int RENDER_MAX_MAJOR = 0;
47static const int RENDER_MAX_MINOR = 11;
48static const int XFIXES_MAX_MAJOR = 5;
49static const int XFIXES_MAX_MINOR = 0;
50
51ExtensionData::ExtensionData()
52 : version(0)
53 , eventBase(0)
54 , errorBase(0)
55 , majorOpcode(0)
56 , present(0)
57{
58}
59
60template<typename reply, typename T, typename F>
61void 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
67Extensions *Extensions::s_self = NULL;
68
69Extensions *Extensions::self()
70{
71 if (!s_self) {
72 s_self = new Extensions();
73 }
74 return s_self;
75}
76
77void Extensions::destroy()
78{
79 delete s_self;
80 s_self = NULL;
81}
82
83Extensions::Extensions()
84{
85 init();
86}
87
88Extensions::~Extensions()
89{
90}
91
92void 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
179void 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
190int Extensions::damageNotifyEvent() const
191{
192 return m_damage.eventBase + XCB_DAMAGE_NOTIFY;
193}
194
195bool 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
208bool Extensions::isCompositeOverlayAvailable() const
209{
210 return m_composite.version >= 0x03; // 0.3
211}
212
213bool Extensions::isFixesRegionAvailable() const
214{
215 return m_fixes.version >= 0x30; // 3
216}
217
218int Extensions::fixesCursorNotifyEvent() const
219{
220 return m_fixes.eventBase + XCB_XFIXES_CURSOR_NOTIFY;
221}
222
223bool Extensions::isShapeInputAvailable() const
224{
225 return m_shape.version >= 0x11; // 1.1
226}
227
228int Extensions::randrNotifyEvent() const
229{
230 return m_randr.eventBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY;
231}
232
233int Extensions::shapeNotifyEvent() const
234{
235 return m_shape.eventBase + XCB_SHAPE_NOTIFY;
236}
237
238int Extensions::syncAlarmNotifyEvent() const
239{
240 return m_sync.eventBase + XCB_SYNC_ALARM_NOTIFY;
241}
242
243QVector<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