1 /*
2     KWin - the KDE window manager
3     This file is part of the KDE project.
4 
5     SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
6     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
7 
8     SPDX-License-Identifier: GPL-2.0-or-later
9 */
10 #include "xcbutils.h"
11 #include "utils.h"
12 // Qt
13 #include <QDebug>
14 // xcb
15 #include <xcb/composite.h>
16 #include <xcb/damage.h>
17 #include <xcb/randr.h>
18 #include <xcb/render.h>
19 #include <xcb/shape.h>
20 #include <xcb/sync.h>
21 #include <xcb/xfixes.h>
22 #include <xcb/glx.h>
23 // system
24 #include <sys/shm.h>
25 #include <sys/types.h>
26 
27 namespace KWin {
28 
29 namespace Xcb {
30 
31 static const int COMPOSITE_MAX_MAJOR = 0;
32 static const int COMPOSITE_MAX_MINOR = 4;
33 static const int DAMAGE_MAX_MAJOR = 1;
34 static const int DAMAGE_MIN_MAJOR = 1;
35 static const int SYNC_MAX_MAJOR = 3;
36 static const int SYNC_MAX_MINOR = 0;
37 static const int RANDR_MAX_MAJOR = 1;
38 static const int RANDR_MAX_MINOR = 4;
39 static const int RENDER_MAX_MAJOR = 0;
40 static const int RENDER_MAX_MINOR = 11;
41 static const int XFIXES_MAX_MAJOR = 5;
42 static const int XFIXES_MAX_MINOR = 0;
43 
shapeOpCodes()44 QVector<QByteArray> shapeOpCodes()
45 {
46     // see https://www.x.org/releases/X11R7.7/doc/xextproto/shape.html
47     // extracted from <xcb/shape.h>
48     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
49                                 QByteArrayLiteral("Rectangles"),
50                                 QByteArrayLiteral("Mask"),
51                                 QByteArrayLiteral("Combine"),
52                                 QByteArrayLiteral("Offset"),
53                                 QByteArrayLiteral("Extents"),
54                                 QByteArrayLiteral("Input"),
55                                 QByteArrayLiteral("InputSelected"),
56                                 QByteArrayLiteral("GetRectangles")});
57 }
58 
randrOpCodes()59 QVector<QByteArray> randrOpCodes()
60 {
61     // see https://www.x.org/releases/X11R7.7/doc/randrproto/randrproto.txt
62     // extracted from <xcb/randr.h>
63     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
64                                 QByteArray(""), // doesn't exist
65                                 QByteArrayLiteral("SetScreenConfig"),
66                                 QByteArray(""), // doesn't exits
67                                 QByteArrayLiteral("SelectInput"),
68                                 QByteArrayLiteral("GetScreenInfo"),
69                                 QByteArrayLiteral("GetScreenSizeRange"),
70                                 QByteArrayLiteral("SetScreenSize"),
71                                 QByteArrayLiteral("GetScreenResources"),
72                                 QByteArrayLiteral("GetOutputInfo"),
73                                 QByteArrayLiteral("ListOutputProperties"),
74                                 QByteArrayLiteral("QueryOutputProperty"),
75                                 QByteArrayLiteral("ConfigureOutputProperty"),
76                                 QByteArrayLiteral("ChangeOutputProperty"),
77                                 QByteArrayLiteral("DeleteOutputProperty"),
78                                 QByteArrayLiteral("GetOutputproperty"),
79                                 QByteArrayLiteral("CreateMode"),
80                                 QByteArrayLiteral("DestroyMode"),
81                                 QByteArrayLiteral("AddOutputMode"),
82                                 QByteArrayLiteral("DeleteOutputMode"),
83                                 QByteArrayLiteral("GetCrtcInfo"),
84                                 QByteArrayLiteral("SetCrtcConfig"),
85                                 QByteArrayLiteral("GetCrtcGammaSize"),
86                                 QByteArrayLiteral("GetCrtcGamma"),
87                                 QByteArrayLiteral("SetCrtcGamma"),
88                                 QByteArrayLiteral("GetScreenResourcesCurrent"),
89                                 QByteArrayLiteral("SetCrtcTransform"),
90                                 QByteArrayLiteral("GetCrtcTransform"),
91                                 QByteArrayLiteral("GetPanning"),
92                                 QByteArrayLiteral("SetPanning"),
93                                 QByteArrayLiteral("SetOutputPrimary"),
94                                 QByteArrayLiteral("GetOutputPrimary"),
95                                 QByteArrayLiteral("GetProviders"),
96                                 QByteArrayLiteral("GetProviderInfo"),
97                                 QByteArrayLiteral("SetProviderOffloadSink"),
98                                 QByteArrayLiteral("SetProviderOutputSource"),
99                                 QByteArrayLiteral("ListProviderProperties"),
100                                 QByteArrayLiteral("QueryProviderProperty"),
101                                 QByteArrayLiteral("ConfigureProviderroperty"),
102                                 QByteArrayLiteral("ChangeProviderProperty"),
103                                 QByteArrayLiteral("DeleteProviderProperty"),
104                                 QByteArrayLiteral("GetProviderProperty")});
105 }
106 
randrErrorCodes()107 QVector<QByteArray> randrErrorCodes()
108 {
109     // see https://www.x.org/releases/X11R7.7/doc/randrproto/randrproto.txt
110     // extracted from <xcb/randr.h>
111     return QVector<QByteArray>({QByteArrayLiteral("BadOutput"),
112                                 QByteArrayLiteral("BadCrtc"),
113                                 QByteArrayLiteral("BadMode"),
114                                 QByteArrayLiteral("BadProvider")});
115 }
116 
damageOpCodes()117 QVector<QByteArray> damageOpCodes()
118 {
119     // see https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt
120     // extracted from <xcb/damage.h>
121     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
122                                 QByteArrayLiteral("Create"),
123                                 QByteArrayLiteral("Destroy"),
124                                 QByteArrayLiteral("Subtract"),
125                                 QByteArrayLiteral("Add")});
126 }
127 
damageErrorCodes()128 QVector<QByteArray> damageErrorCodes()
129 {
130     // see https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt
131     // extracted from <xcb/damage.h>
132     return QVector<QByteArray>({QByteArrayLiteral("BadDamage")});
133 }
134 
compositeOpCodes()135 QVector<QByteArray> compositeOpCodes()
136 {
137     // see https://www.x.org/releases/X11R7.7/doc/compositeproto/compositeproto.txt
138     // extracted from <xcb/composite.h>
139     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
140                                 QByteArrayLiteral("RedirectWindow"),
141                                 QByteArrayLiteral("RedirectSubwindows"),
142                                 QByteArrayLiteral("UnredirectWindow"),
143                                 QByteArrayLiteral("UnredirectSubwindows"),
144                                 QByteArrayLiteral("CreateRegionFromBorderClip"),
145                                 QByteArrayLiteral("NameWindowPixmap"),
146                                 QByteArrayLiteral("GetOverlayWindow"),
147                                 QByteArrayLiteral("ReleaseOverlayWindow")});
148 }
149 
fixesOpCodes()150 QVector<QByteArray> fixesOpCodes()
151 {
152     // see https://www.x.org/releases/X11R7.7/doc/fixesproto/fixesproto.txt
153     // extracted from <xcb/xfixes.h>
154     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
155                                 QByteArrayLiteral("ChangeSaveSet"),
156                                 QByteArrayLiteral("SelectSelectionInput"),
157                                 QByteArrayLiteral("SelectCursorInput"),
158                                 QByteArrayLiteral("GetCursorImage"),
159                                 QByteArrayLiteral("CreateRegion"),
160                                 QByteArrayLiteral("CreateRegionFromBitmap"),
161                                 QByteArrayLiteral("CreateRegionFromWindow"),
162                                 QByteArrayLiteral("CreateRegionFromGc"),
163                                 QByteArrayLiteral("CreateRegionFromPicture"),
164                                 QByteArrayLiteral("DestroyRegion"),
165                                 QByteArrayLiteral("SetRegion"),
166                                 QByteArrayLiteral("CopyRegion"),
167                                 QByteArrayLiteral("UnionRegion"),
168                                 QByteArrayLiteral("IntersectRegion"),
169                                 QByteArrayLiteral("SubtractRegion"),
170                                 QByteArrayLiteral("InvertRegion"),
171                                 QByteArrayLiteral("TranslateRegion"),
172                                 QByteArrayLiteral("RegionExtents"),
173                                 QByteArrayLiteral("FetchRegion"),
174                                 QByteArrayLiteral("SetGcClipRegion"),
175                                 QByteArrayLiteral("SetWindowShapeRegion"),
176                                 QByteArrayLiteral("SetPictureClipRegion"),
177                                 QByteArrayLiteral("SetCursorName"),
178                                 QByteArrayLiteral("GetCursorName"),
179                                 QByteArrayLiteral("GetCursorImageAndName"),
180                                 QByteArrayLiteral("ChangeCursor"),
181                                 QByteArrayLiteral("ChangeCursorByName"),
182                                 QByteArrayLiteral("ExpandRegion"),
183                                 QByteArrayLiteral("HideCursor"),
184                                 QByteArrayLiteral("ShowCursor"),
185                                 QByteArrayLiteral("CreatePointerBarrier"),
186                                 QByteArrayLiteral("DeletePointerBarrier")});
187 }
188 
fixesErrorCodes()189 QVector<QByteArray> fixesErrorCodes()
190 {
191     // see https://www.x.org/releases/X11R7.7/doc/fixesproto/fixesproto.txt
192     // extracted from <xcb/xfixes.h>
193     return QVector<QByteArray>({QByteArrayLiteral("BadRegion")});
194 }
195 
renderOpCodes()196 QVector<QByteArray> renderOpCodes()
197 {
198     // see https://www.x.org/releases/X11R7.7/doc/renderproto/renderproto.txt
199     // extracted from <xcb/render.h>
200     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
201                                 QByteArrayLiteral("QueryPictFormats"),
202                                 QByteArrayLiteral("QueryPictIndexValues"),
203                                 QByteArrayLiteral("CreatePicture"),
204                                 QByteArrayLiteral("ChangePicture"),
205                                 QByteArrayLiteral("SetPictureClipRectangles"),
206                                 QByteArrayLiteral("FreePicture"),
207                                 QByteArrayLiteral("Composite"),
208                                 QByteArrayLiteral("Trapezoids"),
209                                 QByteArrayLiteral("Triangles"),
210                                 QByteArrayLiteral("TriStrip"),
211                                 QByteArrayLiteral("TriFan"),
212                                 QByteArrayLiteral("CreateGlyphSet"),
213                                 QByteArrayLiteral("ReferenceGlyphSet"),
214                                 QByteArrayLiteral("FreeGlyphSet"),
215                                 QByteArrayLiteral("AddGlyphs"),
216                                 QByteArrayLiteral("FreeGlyphs"),
217                                 QByteArrayLiteral("CompositeGlyphs8"),
218                                 QByteArrayLiteral("CompositeGlyphs16"),
219                                 QByteArrayLiteral("CompositeGlyphs32"),
220                                 QByteArrayLiteral("FillRectangles"),
221                                 QByteArrayLiteral("CreateCursor"),
222                                 QByteArrayLiteral("SetPictureTransform"),
223                                 QByteArrayLiteral("QueryFilters"),
224                                 QByteArrayLiteral("SetPictureFilter"),
225                                 QByteArrayLiteral("CreateAnimCursor"),
226                                 QByteArrayLiteral("AddTraps"),
227                                 QByteArrayLiteral("CreateSolidFill"),
228                                 QByteArrayLiteral("CreateLinearGradient"),
229                                 QByteArrayLiteral("CreateRadialGradient"),
230                                 QByteArrayLiteral("CreateConicalGradient")});
231 }
232 
syncOpCodes()233 QVector<QByteArray> syncOpCodes()
234 {
235     // see https://www.x.org/releases/X11R7.7/doc/xextproto/sync.html
236     // extracted from <xcb/sync.h>
237     return QVector<QByteArray>({QByteArrayLiteral("Initialize"),
238                                 QByteArrayLiteral("ListSystemCounters"),
239                                 QByteArrayLiteral("CreateCounter"),
240                                 QByteArrayLiteral("DestroyCounter"),
241                                 QByteArrayLiteral("QueryCounter"),
242                                 QByteArrayLiteral("Await"),
243                                 QByteArrayLiteral("ChangeCounter"),
244                                 QByteArrayLiteral("SetCounter"),
245                                 QByteArrayLiteral("CreateAlarm"),
246                                 QByteArrayLiteral("ChangeAlarm"),
247                                 QByteArrayLiteral("DestroyAlarm"),
248                                 QByteArrayLiteral("QueryAlarm"),
249                                 QByteArrayLiteral("SetPriority"),
250                                 QByteArrayLiteral("GetPriority"),
251                                 QByteArrayLiteral("CreateFence"),
252                                 QByteArrayLiteral("TriggerFence"),
253                                 QByteArrayLiteral("ResetFence"),
254                                 QByteArrayLiteral("DestroyFence"),
255                                 QByteArrayLiteral("QueryFence"),
256                                 QByteArrayLiteral("AwaitFence")});
257 }
258 
glxOpCodes()259 static QVector<QByteArray> glxOpCodes()
260 {
261     return QVector<QByteArray>{
262         QByteArrayLiteral(""),
263         QByteArrayLiteral("Render"),
264         QByteArrayLiteral("RenderLarge"),
265         QByteArrayLiteral("CreateContext"),
266         QByteArrayLiteral("DestroyContext"),
267         QByteArrayLiteral("MakeCurrent"),
268         QByteArrayLiteral("IsDirect"),
269         QByteArrayLiteral("QueryVersion"),
270         QByteArrayLiteral("WaitGL"),
271         QByteArrayLiteral("WaitX"),
272         QByteArrayLiteral("CopyContext"),
273         QByteArrayLiteral("SwapBuffers"),
274         QByteArrayLiteral("UseXFont"),
275         QByteArrayLiteral("CreateGLXPixmap"),
276         QByteArrayLiteral("GetVisualConfigs"),
277         QByteArrayLiteral("DestroyGLXPixmap"),
278         QByteArrayLiteral("VendorPrivate"),
279         QByteArrayLiteral("VendorPrivateWithReply"),
280         QByteArrayLiteral("QueryExtensionsString"),
281         QByteArrayLiteral("QueryServerString"),
282         QByteArrayLiteral("ClientInfo"),
283         QByteArrayLiteral("GetFBConfigs"),
284         QByteArrayLiteral("CreatePixmap"),
285         QByteArrayLiteral("DestroyPixmap"),
286         QByteArrayLiteral("CreateNewContext"),
287         QByteArrayLiteral("QueryContext"),
288         QByteArrayLiteral("MakeContextCurrent"),
289         QByteArrayLiteral("CreatePbuffer"),
290         QByteArrayLiteral("DestroyPbuffer"),
291         QByteArrayLiteral("GetDrawableAttributes"),
292         QByteArrayLiteral("ChangeDrawableAttributes"),
293         QByteArrayLiteral("CreateWindow"),
294         QByteArrayLiteral("DeleteWindow"),
295         QByteArrayLiteral("SetClientInfoARB"),
296         QByteArrayLiteral("CreateContextAttribsARB"),
297         QByteArrayLiteral("SetClientInfo2ARB")
298         // Opcodes 36-100 are unused
299         // The GL single commands begin at opcode 101
300     };
301 }
302 
glxErrorCodes()303 static QVector<QByteArray> glxErrorCodes()
304 {
305     return QVector<QByteArray>{
306         QByteArrayLiteral("BadContext"),
307         QByteArrayLiteral("BadContextState"),
308         QByteArrayLiteral("BadDrawable"),
309         QByteArrayLiteral("BadPixmap"),
310         QByteArrayLiteral("BadContextTag"),
311         QByteArrayLiteral("BadCurrentWindow"),
312         QByteArrayLiteral("BadRenderRequest"),
313         QByteArrayLiteral("BadLargeRequest"),
314         QByteArrayLiteral("UnsupportedPrivateRequest"),
315         QByteArrayLiteral("BadFBConfig"),
316         QByteArrayLiteral("BadPbuffer"),
317         QByteArrayLiteral("BadCurrentDrawable"),
318         QByteArrayLiteral("BadWindow"),
319         QByteArrayLiteral("GLXBadProfileARB")
320     };
321 }
322 
ExtensionData()323 ExtensionData::ExtensionData()
324     : version(0)
325     , eventBase(0)
326     , errorBase(0)
327     , majorOpcode(0)
328     , present(0)
329 {
330 }
331 
332 template<typename reply, typename T, typename F>
initVersion(T cookie,F f,ExtensionData * dataToFill)333 void Extensions::initVersion(T cookie, F f, ExtensionData *dataToFill)
334 {
335     ScopedCPointer<reply> version(f(connection(), cookie, nullptr));
336     dataToFill->version = version->major_version * 0x10 + version->minor_version;
337 }
338 
339 Extensions *Extensions::s_self = nullptr;
340 
self()341 Extensions *Extensions::self()
342 {
343     if (!s_self) {
344         s_self = new Extensions();
345     }
346     return s_self;
347 }
348 
destroy()349 void Extensions::destroy()
350 {
351     delete s_self;
352     s_self = nullptr;
353 }
354 
Extensions()355 Extensions::Extensions()
356 {
357     init();
358 }
359 
~Extensions()360 Extensions::~Extensions()
361 {
362 }
363 
init()364 void Extensions::init()
365 {
366     xcb_connection_t *c = connection();
367     xcb_prefetch_extension_data(c, &xcb_shape_id);
368     xcb_prefetch_extension_data(c, &xcb_randr_id);
369     xcb_prefetch_extension_data(c, &xcb_damage_id);
370     xcb_prefetch_extension_data(c, &xcb_composite_id);
371     xcb_prefetch_extension_data(c, &xcb_xfixes_id);
372     xcb_prefetch_extension_data(c, &xcb_render_id);
373     xcb_prefetch_extension_data(c, &xcb_sync_id);
374     xcb_prefetch_extension_data(c, &xcb_glx_id);
375 
376     m_shape.name     = QByteArray("SHAPE");
377     m_randr.name     = QByteArray("RANDR");
378     m_damage.name    = QByteArray("DAMAGE");
379     m_composite.name = QByteArray("Composite");
380     m_fixes.name     = QByteArray("XFIXES");
381     m_render.name    = QByteArray("RENDER");
382     m_sync.name      = QByteArray("SYNC");
383     m_glx.name       = QByteArray("GLX");
384 
385     m_shape.opCodes     = shapeOpCodes();
386     m_randr.opCodes     = randrOpCodes();
387     m_damage.opCodes    = damageOpCodes();
388     m_composite.opCodes = compositeOpCodes();
389     m_fixes.opCodes     = fixesOpCodes();
390     m_render.opCodes    = renderOpCodes();
391     m_sync.opCodes      = syncOpCodes();
392     m_glx.opCodes       = glxOpCodes();
393 
394     m_randr.errorCodes  = randrErrorCodes();
395     m_damage.errorCodes = damageErrorCodes();
396     m_fixes.errorCodes  = fixesErrorCodes();
397     m_glx.errorCodes    = glxErrorCodes();
398 
399     extensionQueryReply(xcb_get_extension_data(c, &xcb_shape_id), &m_shape);
400     extensionQueryReply(xcb_get_extension_data(c, &xcb_randr_id), &m_randr);
401     extensionQueryReply(xcb_get_extension_data(c, &xcb_damage_id), &m_damage);
402     extensionQueryReply(xcb_get_extension_data(c, &xcb_composite_id), &m_composite);
403     extensionQueryReply(xcb_get_extension_data(c, &xcb_xfixes_id), &m_fixes);
404     extensionQueryReply(xcb_get_extension_data(c, &xcb_render_id), &m_render);
405     extensionQueryReply(xcb_get_extension_data(c, &xcb_sync_id), &m_sync);
406     extensionQueryReply(xcb_get_extension_data(c, &xcb_glx_id), &m_glx);
407 
408     // extension specific queries
409     xcb_shape_query_version_cookie_t shapeVersion;
410     xcb_randr_query_version_cookie_t randrVersion;
411     xcb_damage_query_version_cookie_t damageVersion;
412     xcb_composite_query_version_cookie_t compositeVersion;
413     xcb_xfixes_query_version_cookie_t xfixesVersion;
414     xcb_render_query_version_cookie_t renderVersion;
415     xcb_sync_initialize_cookie_t syncVersion;
416     if (m_shape.present) {
417         shapeVersion = xcb_shape_query_version_unchecked(c);
418     }
419     if (m_randr.present) {
420         randrVersion = xcb_randr_query_version_unchecked(c, RANDR_MAX_MAJOR, RANDR_MAX_MINOR);
421         xcb_randr_select_input(connection(), rootWindow(), XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
422     }
423     if (m_damage.present) {
424         damageVersion = xcb_damage_query_version_unchecked(c, DAMAGE_MAX_MAJOR, DAMAGE_MIN_MAJOR);
425     }
426     if (m_composite.present) {
427         compositeVersion = xcb_composite_query_version_unchecked(c, COMPOSITE_MAX_MAJOR, COMPOSITE_MAX_MINOR);
428     }
429     if (m_fixes.present) {
430         xfixesVersion = xcb_xfixes_query_version_unchecked(c, XFIXES_MAX_MAJOR, XFIXES_MAX_MINOR);
431     }
432     if (m_render.present) {
433         renderVersion = xcb_render_query_version_unchecked(c, RENDER_MAX_MAJOR, RENDER_MAX_MINOR);
434     }
435     if (m_sync.present) {
436         syncVersion = xcb_sync_initialize(c, SYNC_MAX_MAJOR, SYNC_MAX_MINOR);
437     }
438     // handle replies
439     if (m_shape.present) {
440         initVersion<xcb_shape_query_version_reply_t>(shapeVersion, &xcb_shape_query_version_reply, &m_shape);
441     }
442     if (m_randr.present) {
443         initVersion<xcb_randr_query_version_reply_t>(randrVersion, &xcb_randr_query_version_reply, &m_randr);
444     }
445     if (m_damage.present) {
446         initVersion<xcb_damage_query_version_reply_t>(damageVersion, &xcb_damage_query_version_reply, &m_damage);
447     }
448     if (m_composite.present) {
449         initVersion<xcb_composite_query_version_reply_t>(compositeVersion, &xcb_composite_query_version_reply, &m_composite);
450     }
451     if (m_fixes.present) {
452         initVersion<xcb_xfixes_query_version_reply_t>(xfixesVersion, &xcb_xfixes_query_version_reply, &m_fixes);
453     }
454     if (m_render.present) {
455         initVersion<xcb_render_query_version_reply_t>(renderVersion, &xcb_render_query_version_reply, &m_render);
456     }
457     if (m_sync.present) {
458         initVersion<xcb_sync_initialize_reply_t>(syncVersion, &xcb_sync_initialize_reply, &m_sync);
459     }
460     qCDebug(KWIN_CORE) << "Extensions: shape: 0x" << QString::number(m_shape.version, 16)
461                  << " composite: 0x" << QString::number(m_composite.version, 16)
462                  << " render: 0x" << QString::number(m_render.version, 16)
463                  << " fixes: 0x" << QString::number(m_fixes.version, 16)
464                  << " randr: 0x" << QString::number(m_randr.version, 16)
465                  << " sync: 0x" << QString::number(m_sync.version, 16)
466                  << " damage: 0x " << QString::number(m_damage.version, 16);
467 }
468 
extensionQueryReply(const xcb_query_extension_reply_t * extension,ExtensionData * dataToFill)469 void Extensions::extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill)
470 {
471     if (!extension) {
472         return;
473     }
474     dataToFill->present = extension->present;
475     dataToFill->eventBase = extension->first_event;
476     dataToFill->errorBase = extension->first_error;
477     dataToFill->majorOpcode = extension->major_opcode;
478 }
479 
damageNotifyEvent() const480 int Extensions::damageNotifyEvent() const
481 {
482     return m_damage.eventBase + XCB_DAMAGE_NOTIFY;
483 }
484 
hasShape(xcb_window_t w) const485 bool Extensions::hasShape(xcb_window_t w) const
486 {
487     if (!isShapeAvailable()) {
488         return false;
489     }
490     ScopedCPointer<xcb_shape_query_extents_reply_t> extents(xcb_shape_query_extents_reply(
491         connection(), xcb_shape_query_extents_unchecked(connection(), w), nullptr));
492     if (extents.isNull()) {
493         return false;
494     }
495     return extents->bounding_shaped > 0;
496 }
497 
isCompositeOverlayAvailable() const498 bool Extensions::isCompositeOverlayAvailable() const
499 {
500     return m_composite.version >= 0x03; // 0.3
501 }
502 
isFixesRegionAvailable() const503 bool Extensions::isFixesRegionAvailable() const
504 {
505     return m_fixes.version >= 0x30; // 3
506 }
507 
fixesCursorNotifyEvent() const508 int Extensions::fixesCursorNotifyEvent() const
509 {
510     return m_fixes.eventBase + XCB_XFIXES_CURSOR_NOTIFY;
511 }
512 
fixesSelectionNotifyEvent() const513 int Extensions::fixesSelectionNotifyEvent() const
514 {
515     return m_fixes.eventBase + XCB_XFIXES_SELECTION_NOTIFY;
516 }
517 
isShapeInputAvailable() const518 bool Extensions::isShapeInputAvailable() const
519 {
520     return m_shape.version >= 0x11; // 1.1
521 }
522 
randrNotifyEvent() const523 int Extensions::randrNotifyEvent() const
524 {
525     return m_randr.eventBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY;
526 }
527 
shapeNotifyEvent() const528 int Extensions::shapeNotifyEvent() const
529 {
530     return m_shape.eventBase + XCB_SHAPE_NOTIFY;
531 }
532 
syncAlarmNotifyEvent() const533 int Extensions::syncAlarmNotifyEvent() const
534 {
535     return m_sync.eventBase + XCB_SYNC_ALARM_NOTIFY;
536 }
537 
extensions() const538 QVector<ExtensionData> Extensions::extensions() const
539 {
540     return {
541         m_shape,
542         m_randr,
543         m_damage,
544         m_composite,
545         m_render,
546         m_fixes,
547         m_sync,
548         m_glx
549     };
550 }
551 
552 //****************************************
553 // Shm
554 //****************************************
Shm()555 Shm::Shm()
556     : m_shmId(-1)
557     , m_buffer(nullptr)
558     , m_segment(XCB_NONE)
559     , m_valid(false)
560     , m_pixmapFormat(XCB_IMAGE_FORMAT_XY_BITMAP)
561 {
562     m_valid = init();
563 }
564 
~Shm()565 Shm::~Shm()
566 {
567     if (m_valid) {
568         xcb_shm_detach(connection(), m_segment);
569         shmdt(m_buffer);
570     }
571 }
572 
init()573 bool Shm::init()
574 {
575     const xcb_query_extension_reply_t *ext = xcb_get_extension_data(connection(), &xcb_shm_id);
576     if (!ext || !ext->present) {
577         qCDebug(KWIN_CORE) << "SHM extension not available";
578         return false;
579     }
580     ScopedCPointer<xcb_shm_query_version_reply_t> version(xcb_shm_query_version_reply(connection(),
581         xcb_shm_query_version_unchecked(connection()), nullptr));
582     if (version.isNull()) {
583         qCDebug(KWIN_CORE) << "Failed to get SHM extension version information";
584         return false;
585     }
586     m_pixmapFormat = version->pixmap_format;
587     const int MAXSIZE = 4096 * 2048 * 4; // TODO check there are not larger windows
588     m_shmId = shmget(IPC_PRIVATE, MAXSIZE, IPC_CREAT | 0600);
589     if (m_shmId < 0) {
590         qCDebug(KWIN_CORE) << "Failed to allocate SHM segment";
591         return false;
592     }
593     m_buffer = shmat(m_shmId, nullptr, 0 /*read/write*/);
594     if (-1 == reinterpret_cast<long>(m_buffer)) {
595         qCDebug(KWIN_CORE) << "Failed to attach SHM segment";
596         shmctl(m_shmId, IPC_RMID, nullptr);
597         return false;
598     }
599     shmctl(m_shmId, IPC_RMID, nullptr);
600 
601     m_segment = xcb_generate_id(connection());
602     const xcb_void_cookie_t cookie = xcb_shm_attach_checked(connection(), m_segment, m_shmId, false);
603     ScopedCPointer<xcb_generic_error_t> error(xcb_request_check(connection(), cookie));
604     if (!error.isNull()) {
605         qCDebug(KWIN_CORE) << "xcb_shm_attach error: " << error->error_code;
606         shmdt(m_buffer);
607         return false;
608     }
609 
610     return true;
611 }
612 
613 } // namespace Xcb
614 } // namespace KWin
615