File indexing completed on 2024-05-19 16:34:58

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
0006     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "utils/xcbutils.h"
0011 #include "utils/common.h"
0012 #include <core/output.h>
0013 #include <workspace.h>
0014 
0015 // Qt
0016 #include <QDebug>
0017 // xcb
0018 #include <cmath>
0019 #include <xcb/composite.h>
0020 #include <xcb/damage.h>
0021 #include <xcb/glx.h>
0022 #include <xcb/randr.h>
0023 #include <xcb/render.h>
0024 #include <xcb/shape.h>
0025 #include <xcb/sync.h>
0026 #include <xcb/xfixes.h>
0027 // system
0028 #include <sys/shm.h>
0029 #include <sys/types.h>
0030 
0031 namespace KWin
0032 {
0033 
0034 namespace Xcb
0035 {
0036 
0037 static const int COMPOSITE_MAX_MAJOR = 0;
0038 static const int COMPOSITE_MAX_MINOR = 4;
0039 static const int DAMAGE_MAX_MAJOR = 1;
0040 static const int DAMAGE_MIN_MAJOR = 1;
0041 static const int SYNC_MAX_MAJOR = 3;
0042 static const int SYNC_MAX_MINOR = 0;
0043 static const int RANDR_MAX_MAJOR = 1;
0044 static const int RANDR_MAX_MINOR = 4;
0045 static const int RENDER_MAX_MAJOR = 0;
0046 static const int RENDER_MAX_MINOR = 11;
0047 static const int XFIXES_MAX_MAJOR = 5;
0048 static const int XFIXES_MAX_MINOR = 0;
0049 
0050 QVector<QByteArray> shapeOpCodes()
0051 {
0052     // see https://www.x.org/releases/X11R7.7/doc/xextproto/shape.html
0053     // extracted from <xcb/shape.h>
0054     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
0055                                 QByteArrayLiteral("Rectangles"),
0056                                 QByteArrayLiteral("Mask"),
0057                                 QByteArrayLiteral("Combine"),
0058                                 QByteArrayLiteral("Offset"),
0059                                 QByteArrayLiteral("Extents"),
0060                                 QByteArrayLiteral("Input"),
0061                                 QByteArrayLiteral("InputSelected"),
0062                                 QByteArrayLiteral("GetRectangles")});
0063 }
0064 
0065 QVector<QByteArray> randrOpCodes()
0066 {
0067     // see https://www.x.org/releases/X11R7.7/doc/randrproto/randrproto.txt
0068     // extracted from <xcb/randr.h>
0069     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
0070                                 QByteArray(""), // doesn't exist
0071                                 QByteArrayLiteral("SetScreenConfig"),
0072                                 QByteArray(""), // doesn't exits
0073                                 QByteArrayLiteral("SelectInput"),
0074                                 QByteArrayLiteral("GetScreenInfo"),
0075                                 QByteArrayLiteral("GetScreenSizeRange"),
0076                                 QByteArrayLiteral("SetScreenSize"),
0077                                 QByteArrayLiteral("GetScreenResources"),
0078                                 QByteArrayLiteral("GetOutputInfo"),
0079                                 QByteArrayLiteral("ListOutputProperties"),
0080                                 QByteArrayLiteral("QueryOutputProperty"),
0081                                 QByteArrayLiteral("ConfigureOutputProperty"),
0082                                 QByteArrayLiteral("ChangeOutputProperty"),
0083                                 QByteArrayLiteral("DeleteOutputProperty"),
0084                                 QByteArrayLiteral("GetOutputproperty"),
0085                                 QByteArrayLiteral("CreateMode"),
0086                                 QByteArrayLiteral("DestroyMode"),
0087                                 QByteArrayLiteral("AddOutputMode"),
0088                                 QByteArrayLiteral("DeleteOutputMode"),
0089                                 QByteArrayLiteral("GetCrtcInfo"),
0090                                 QByteArrayLiteral("SetCrtcConfig"),
0091                                 QByteArrayLiteral("GetCrtcGammaSize"),
0092                                 QByteArrayLiteral("GetCrtcGamma"),
0093                                 QByteArrayLiteral("SetCrtcGamma"),
0094                                 QByteArrayLiteral("GetScreenResourcesCurrent"),
0095                                 QByteArrayLiteral("SetCrtcTransform"),
0096                                 QByteArrayLiteral("GetCrtcTransform"),
0097                                 QByteArrayLiteral("GetPanning"),
0098                                 QByteArrayLiteral("SetPanning"),
0099                                 QByteArrayLiteral("SetOutputPrimary"),
0100                                 QByteArrayLiteral("GetOutputPrimary"),
0101                                 QByteArrayLiteral("GetProviders"),
0102                                 QByteArrayLiteral("GetProviderInfo"),
0103                                 QByteArrayLiteral("SetProviderOffloadSink"),
0104                                 QByteArrayLiteral("SetProviderOutputSource"),
0105                                 QByteArrayLiteral("ListProviderProperties"),
0106                                 QByteArrayLiteral("QueryProviderProperty"),
0107                                 QByteArrayLiteral("ConfigureProviderroperty"),
0108                                 QByteArrayLiteral("ChangeProviderProperty"),
0109                                 QByteArrayLiteral("DeleteProviderProperty"),
0110                                 QByteArrayLiteral("GetProviderProperty")});
0111 }
0112 
0113 QVector<QByteArray> randrErrorCodes()
0114 {
0115     // see https://www.x.org/releases/X11R7.7/doc/randrproto/randrproto.txt
0116     // extracted from <xcb/randr.h>
0117     return QVector<QByteArray>({QByteArrayLiteral("BadOutput"),
0118                                 QByteArrayLiteral("BadCrtc"),
0119                                 QByteArrayLiteral("BadMode"),
0120                                 QByteArrayLiteral("BadProvider")});
0121 }
0122 
0123 QVector<QByteArray> damageOpCodes()
0124 {
0125     // see https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt
0126     // extracted from <xcb/damage.h>
0127     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
0128                                 QByteArrayLiteral("Create"),
0129                                 QByteArrayLiteral("Destroy"),
0130                                 QByteArrayLiteral("Subtract"),
0131                                 QByteArrayLiteral("Add")});
0132 }
0133 
0134 QVector<QByteArray> damageErrorCodes()
0135 {
0136     // see https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt
0137     // extracted from <xcb/damage.h>
0138     return QVector<QByteArray>({QByteArrayLiteral("BadDamage")});
0139 }
0140 
0141 QVector<QByteArray> compositeOpCodes()
0142 {
0143     // see https://www.x.org/releases/X11R7.7/doc/compositeproto/compositeproto.txt
0144     // extracted from <xcb/composite.h>
0145     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
0146                                 QByteArrayLiteral("RedirectWindow"),
0147                                 QByteArrayLiteral("RedirectSubwindows"),
0148                                 QByteArrayLiteral("UnredirectWindow"),
0149                                 QByteArrayLiteral("UnredirectSubwindows"),
0150                                 QByteArrayLiteral("CreateRegionFromBorderClip"),
0151                                 QByteArrayLiteral("NameWindowPixmap"),
0152                                 QByteArrayLiteral("GetOverlayWindow"),
0153                                 QByteArrayLiteral("ReleaseOverlayWindow")});
0154 }
0155 
0156 QVector<QByteArray> fixesOpCodes()
0157 {
0158     // see https://www.x.org/releases/X11R7.7/doc/fixesproto/fixesproto.txt
0159     // extracted from <xcb/xfixes.h>
0160     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
0161                                 QByteArrayLiteral("ChangeSaveSet"),
0162                                 QByteArrayLiteral("SelectSelectionInput"),
0163                                 QByteArrayLiteral("SelectCursorInput"),
0164                                 QByteArrayLiteral("GetCursorImage"),
0165                                 QByteArrayLiteral("CreateRegion"),
0166                                 QByteArrayLiteral("CreateRegionFromBitmap"),
0167                                 QByteArrayLiteral("CreateRegionFromWindow"),
0168                                 QByteArrayLiteral("CreateRegionFromGc"),
0169                                 QByteArrayLiteral("CreateRegionFromPicture"),
0170                                 QByteArrayLiteral("DestroyRegion"),
0171                                 QByteArrayLiteral("SetRegion"),
0172                                 QByteArrayLiteral("CopyRegion"),
0173                                 QByteArrayLiteral("UnionRegion"),
0174                                 QByteArrayLiteral("IntersectRegion"),
0175                                 QByteArrayLiteral("SubtractRegion"),
0176                                 QByteArrayLiteral("InvertRegion"),
0177                                 QByteArrayLiteral("TranslateRegion"),
0178                                 QByteArrayLiteral("RegionExtents"),
0179                                 QByteArrayLiteral("FetchRegion"),
0180                                 QByteArrayLiteral("SetGcClipRegion"),
0181                                 QByteArrayLiteral("SetWindowShapeRegion"),
0182                                 QByteArrayLiteral("SetPictureClipRegion"),
0183                                 QByteArrayLiteral("SetCursorName"),
0184                                 QByteArrayLiteral("GetCursorName"),
0185                                 QByteArrayLiteral("GetCursorImageAndName"),
0186                                 QByteArrayLiteral("ChangeCursor"),
0187                                 QByteArrayLiteral("ChangeCursorByName"),
0188                                 QByteArrayLiteral("ExpandRegion"),
0189                                 QByteArrayLiteral("HideCursor"),
0190                                 QByteArrayLiteral("ShowCursor"),
0191                                 QByteArrayLiteral("CreatePointerBarrier"),
0192                                 QByteArrayLiteral("DeletePointerBarrier")});
0193 }
0194 
0195 QVector<QByteArray> fixesErrorCodes()
0196 {
0197     // see https://www.x.org/releases/X11R7.7/doc/fixesproto/fixesproto.txt
0198     // extracted from <xcb/xfixes.h>
0199     return QVector<QByteArray>({QByteArrayLiteral("BadRegion")});
0200 }
0201 
0202 QVector<QByteArray> renderOpCodes()
0203 {
0204     // see https://www.x.org/releases/X11R7.7/doc/renderproto/renderproto.txt
0205     // extracted from <xcb/render.h>
0206     return QVector<QByteArray>({QByteArrayLiteral("QueryVersion"),
0207                                 QByteArrayLiteral("QueryPictFormats"),
0208                                 QByteArrayLiteral("QueryPictIndexValues"),
0209                                 QByteArrayLiteral("CreatePicture"),
0210                                 QByteArrayLiteral("ChangePicture"),
0211                                 QByteArrayLiteral("SetPictureClipRectangles"),
0212                                 QByteArrayLiteral("FreePicture"),
0213                                 QByteArrayLiteral("Composite"),
0214                                 QByteArrayLiteral("Trapezoids"),
0215                                 QByteArrayLiteral("Triangles"),
0216                                 QByteArrayLiteral("TriStrip"),
0217                                 QByteArrayLiteral("TriFan"),
0218                                 QByteArrayLiteral("CreateGlyphSet"),
0219                                 QByteArrayLiteral("ReferenceGlyphSet"),
0220                                 QByteArrayLiteral("FreeGlyphSet"),
0221                                 QByteArrayLiteral("AddGlyphs"),
0222                                 QByteArrayLiteral("FreeGlyphs"),
0223                                 QByteArrayLiteral("CompositeGlyphs8"),
0224                                 QByteArrayLiteral("CompositeGlyphs16"),
0225                                 QByteArrayLiteral("CompositeGlyphs32"),
0226                                 QByteArrayLiteral("FillRectangles"),
0227                                 QByteArrayLiteral("CreateCursor"),
0228                                 QByteArrayLiteral("SetPictureTransform"),
0229                                 QByteArrayLiteral("QueryFilters"),
0230                                 QByteArrayLiteral("SetPictureFilter"),
0231                                 QByteArrayLiteral("CreateAnimCursor"),
0232                                 QByteArrayLiteral("AddTraps"),
0233                                 QByteArrayLiteral("CreateSolidFill"),
0234                                 QByteArrayLiteral("CreateLinearGradient"),
0235                                 QByteArrayLiteral("CreateRadialGradient"),
0236                                 QByteArrayLiteral("CreateConicalGradient")});
0237 }
0238 
0239 QVector<QByteArray> syncOpCodes()
0240 {
0241     // see https://www.x.org/releases/X11R7.7/doc/xextproto/sync.html
0242     // extracted from <xcb/sync.h>
0243     return QVector<QByteArray>({QByteArrayLiteral("Initialize"),
0244                                 QByteArrayLiteral("ListSystemCounters"),
0245                                 QByteArrayLiteral("CreateCounter"),
0246                                 QByteArrayLiteral("DestroyCounter"),
0247                                 QByteArrayLiteral("QueryCounter"),
0248                                 QByteArrayLiteral("Await"),
0249                                 QByteArrayLiteral("ChangeCounter"),
0250                                 QByteArrayLiteral("SetCounter"),
0251                                 QByteArrayLiteral("CreateAlarm"),
0252                                 QByteArrayLiteral("ChangeAlarm"),
0253                                 QByteArrayLiteral("DestroyAlarm"),
0254                                 QByteArrayLiteral("QueryAlarm"),
0255                                 QByteArrayLiteral("SetPriority"),
0256                                 QByteArrayLiteral("GetPriority"),
0257                                 QByteArrayLiteral("CreateFence"),
0258                                 QByteArrayLiteral("TriggerFence"),
0259                                 QByteArrayLiteral("ResetFence"),
0260                                 QByteArrayLiteral("DestroyFence"),
0261                                 QByteArrayLiteral("QueryFence"),
0262                                 QByteArrayLiteral("AwaitFence")});
0263 }
0264 
0265 static QVector<QByteArray> glxOpCodes()
0266 {
0267     return QVector<QByteArray>{
0268         QByteArrayLiteral(""),
0269         QByteArrayLiteral("Render"),
0270         QByteArrayLiteral("RenderLarge"),
0271         QByteArrayLiteral("CreateContext"),
0272         QByteArrayLiteral("DestroyContext"),
0273         QByteArrayLiteral("MakeCurrent"),
0274         QByteArrayLiteral("IsDirect"),
0275         QByteArrayLiteral("QueryVersion"),
0276         QByteArrayLiteral("WaitGL"),
0277         QByteArrayLiteral("WaitX"),
0278         QByteArrayLiteral("CopyContext"),
0279         QByteArrayLiteral("SwapBuffers"),
0280         QByteArrayLiteral("UseXFont"),
0281         QByteArrayLiteral("CreateGLXPixmap"),
0282         QByteArrayLiteral("GetVisualConfigs"),
0283         QByteArrayLiteral("DestroyGLXPixmap"),
0284         QByteArrayLiteral("VendorPrivate"),
0285         QByteArrayLiteral("VendorPrivateWithReply"),
0286         QByteArrayLiteral("QueryExtensionsString"),
0287         QByteArrayLiteral("QueryServerString"),
0288         QByteArrayLiteral("ClientInfo"),
0289         QByteArrayLiteral("GetFBConfigs"),
0290         QByteArrayLiteral("CreatePixmap"),
0291         QByteArrayLiteral("DestroyPixmap"),
0292         QByteArrayLiteral("CreateNewContext"),
0293         QByteArrayLiteral("QueryContext"),
0294         QByteArrayLiteral("MakeContextCurrent"),
0295         QByteArrayLiteral("CreatePbuffer"),
0296         QByteArrayLiteral("DestroyPbuffer"),
0297         QByteArrayLiteral("GetDrawableAttributes"),
0298         QByteArrayLiteral("ChangeDrawableAttributes"),
0299         QByteArrayLiteral("CreateWindow"),
0300         QByteArrayLiteral("DeleteWindow"),
0301         QByteArrayLiteral("SetClientInfoARB"),
0302         QByteArrayLiteral("CreateContextAttribsARB"),
0303         QByteArrayLiteral("SetClientInfo2ARB")
0304         // Opcodes 36-100 are unused
0305         // The GL single commands begin at opcode 101
0306     };
0307 }
0308 
0309 static QVector<QByteArray> glxErrorCodes()
0310 {
0311     return QVector<QByteArray>{
0312         QByteArrayLiteral("BadContext"),
0313         QByteArrayLiteral("BadContextState"),
0314         QByteArrayLiteral("BadDrawable"),
0315         QByteArrayLiteral("BadPixmap"),
0316         QByteArrayLiteral("BadContextTag"),
0317         QByteArrayLiteral("BadCurrentWindow"),
0318         QByteArrayLiteral("BadRenderRequest"),
0319         QByteArrayLiteral("BadLargeRequest"),
0320         QByteArrayLiteral("UnsupportedPrivateRequest"),
0321         QByteArrayLiteral("BadFBConfig"),
0322         QByteArrayLiteral("BadPbuffer"),
0323         QByteArrayLiteral("BadCurrentDrawable"),
0324         QByteArrayLiteral("BadWindow"),
0325         QByteArrayLiteral("GLXBadProfileARB")};
0326 }
0327 
0328 ExtensionData::ExtensionData()
0329     : version(0)
0330     , eventBase(0)
0331     , errorBase(0)
0332     , majorOpcode(0)
0333     , present(0)
0334 {
0335 }
0336 
0337 template<typename reply, typename T, typename F>
0338 void Extensions::initVersion(T cookie, F f, ExtensionData *dataToFill)
0339 {
0340     UniqueCPtr<reply> version(f(connection(), cookie, nullptr));
0341     dataToFill->version = version->major_version * 0x10 + version->minor_version;
0342 }
0343 
0344 Extensions *Extensions::s_self = nullptr;
0345 
0346 Extensions *Extensions::self()
0347 {
0348     if (!s_self) {
0349         s_self = new Extensions();
0350     }
0351     return s_self;
0352 }
0353 
0354 void Extensions::destroy()
0355 {
0356     delete s_self;
0357     s_self = nullptr;
0358 }
0359 
0360 Extensions::Extensions()
0361 {
0362     init();
0363 }
0364 
0365 Extensions::~Extensions()
0366 {
0367 }
0368 
0369 void Extensions::init()
0370 {
0371     xcb_connection_t *c = connection();
0372     Q_ASSERT(c);
0373     xcb_prefetch_extension_data(c, &xcb_shape_id);
0374     xcb_prefetch_extension_data(c, &xcb_randr_id);
0375     xcb_prefetch_extension_data(c, &xcb_damage_id);
0376     xcb_prefetch_extension_data(c, &xcb_composite_id);
0377     xcb_prefetch_extension_data(c, &xcb_xfixes_id);
0378     xcb_prefetch_extension_data(c, &xcb_render_id);
0379     xcb_prefetch_extension_data(c, &xcb_sync_id);
0380     xcb_prefetch_extension_data(c, &xcb_glx_id);
0381 
0382     m_shape.name = QByteArray("SHAPE");
0383     m_randr.name = QByteArray("RANDR");
0384     m_damage.name = QByteArray("DAMAGE");
0385     m_composite.name = QByteArray("Composite");
0386     m_fixes.name = QByteArray("XFIXES");
0387     m_render.name = QByteArray("RENDER");
0388     m_sync.name = QByteArray("SYNC");
0389     m_glx.name = QByteArray("GLX");
0390 
0391     m_shape.opCodes = shapeOpCodes();
0392     m_randr.opCodes = randrOpCodes();
0393     m_damage.opCodes = damageOpCodes();
0394     m_composite.opCodes = compositeOpCodes();
0395     m_fixes.opCodes = fixesOpCodes();
0396     m_render.opCodes = renderOpCodes();
0397     m_sync.opCodes = syncOpCodes();
0398     m_glx.opCodes = glxOpCodes();
0399 
0400     m_randr.errorCodes = randrErrorCodes();
0401     m_damage.errorCodes = damageErrorCodes();
0402     m_fixes.errorCodes = fixesErrorCodes();
0403     m_glx.errorCodes = glxErrorCodes();
0404 
0405     extensionQueryReply(xcb_get_extension_data(c, &xcb_shape_id), &m_shape);
0406     extensionQueryReply(xcb_get_extension_data(c, &xcb_randr_id), &m_randr);
0407     extensionQueryReply(xcb_get_extension_data(c, &xcb_damage_id), &m_damage);
0408     extensionQueryReply(xcb_get_extension_data(c, &xcb_composite_id), &m_composite);
0409     extensionQueryReply(xcb_get_extension_data(c, &xcb_xfixes_id), &m_fixes);
0410     extensionQueryReply(xcb_get_extension_data(c, &xcb_render_id), &m_render);
0411     extensionQueryReply(xcb_get_extension_data(c, &xcb_sync_id), &m_sync);
0412     extensionQueryReply(xcb_get_extension_data(c, &xcb_glx_id), &m_glx);
0413 
0414     // extension specific queries
0415     xcb_shape_query_version_cookie_t shapeVersion;
0416     xcb_randr_query_version_cookie_t randrVersion;
0417     xcb_damage_query_version_cookie_t damageVersion;
0418     xcb_composite_query_version_cookie_t compositeVersion;
0419     xcb_xfixes_query_version_cookie_t xfixesVersion;
0420     xcb_render_query_version_cookie_t renderVersion;
0421     xcb_sync_initialize_cookie_t syncVersion;
0422     if (m_shape.present) {
0423         shapeVersion = xcb_shape_query_version_unchecked(c);
0424     }
0425     if (m_randr.present) {
0426         randrVersion = xcb_randr_query_version_unchecked(c, RANDR_MAX_MAJOR, RANDR_MAX_MINOR);
0427         xcb_randr_select_input(connection(), rootWindow(), XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
0428     }
0429     if (m_damage.present) {
0430         damageVersion = xcb_damage_query_version_unchecked(c, DAMAGE_MAX_MAJOR, DAMAGE_MIN_MAJOR);
0431     }
0432     if (m_composite.present) {
0433         compositeVersion = xcb_composite_query_version_unchecked(c, COMPOSITE_MAX_MAJOR, COMPOSITE_MAX_MINOR);
0434     }
0435     if (m_fixes.present) {
0436         xfixesVersion = xcb_xfixes_query_version_unchecked(c, XFIXES_MAX_MAJOR, XFIXES_MAX_MINOR);
0437     }
0438     if (m_render.present) {
0439         renderVersion = xcb_render_query_version_unchecked(c, RENDER_MAX_MAJOR, RENDER_MAX_MINOR);
0440     }
0441     if (m_sync.present) {
0442         syncVersion = xcb_sync_initialize(c, SYNC_MAX_MAJOR, SYNC_MAX_MINOR);
0443     }
0444     // handle replies
0445     if (m_shape.present) {
0446         initVersion<xcb_shape_query_version_reply_t>(shapeVersion, &xcb_shape_query_version_reply, &m_shape);
0447     }
0448     if (m_randr.present) {
0449         initVersion<xcb_randr_query_version_reply_t>(randrVersion, &xcb_randr_query_version_reply, &m_randr);
0450     }
0451     if (m_damage.present) {
0452         initVersion<xcb_damage_query_version_reply_t>(damageVersion, &xcb_damage_query_version_reply, &m_damage);
0453     }
0454     if (m_composite.present) {
0455         initVersion<xcb_composite_query_version_reply_t>(compositeVersion, &xcb_composite_query_version_reply, &m_composite);
0456     }
0457     if (m_fixes.present) {
0458         initVersion<xcb_xfixes_query_version_reply_t>(xfixesVersion, &xcb_xfixes_query_version_reply, &m_fixes);
0459     }
0460     if (m_render.present) {
0461         initVersion<xcb_render_query_version_reply_t>(renderVersion, &xcb_render_query_version_reply, &m_render);
0462     }
0463     if (m_sync.present) {
0464         initVersion<xcb_sync_initialize_reply_t>(syncVersion, &xcb_sync_initialize_reply, &m_sync);
0465     }
0466     qCDebug(KWIN_CORE) << "Extensions: shape: 0x" << QString::number(m_shape.version, 16)
0467                        << " composite: 0x" << QString::number(m_composite.version, 16)
0468                        << " render: 0x" << QString::number(m_render.version, 16)
0469                        << " fixes: 0x" << QString::number(m_fixes.version, 16)
0470                        << " randr: 0x" << QString::number(m_randr.version, 16)
0471                        << " sync: 0x" << QString::number(m_sync.version, 16)
0472                        << " damage: 0x " << QString::number(m_damage.version, 16);
0473 }
0474 
0475 void Extensions::extensionQueryReply(const xcb_query_extension_reply_t *extension, ExtensionData *dataToFill)
0476 {
0477     if (!extension) {
0478         return;
0479     }
0480     dataToFill->present = extension->present;
0481     dataToFill->eventBase = extension->first_event;
0482     dataToFill->errorBase = extension->first_error;
0483     dataToFill->majorOpcode = extension->major_opcode;
0484 }
0485 
0486 int Extensions::damageNotifyEvent() const
0487 {
0488     return m_damage.eventBase + XCB_DAMAGE_NOTIFY;
0489 }
0490 
0491 bool Extensions::hasShape(xcb_window_t w) const
0492 {
0493     if (!isShapeAvailable()) {
0494         return false;
0495     }
0496     UniqueCPtr<xcb_shape_query_extents_reply_t> extents(xcb_shape_query_extents_reply(
0497         connection(), xcb_shape_query_extents_unchecked(connection(), w), nullptr));
0498     if (!extents) {
0499         return false;
0500     }
0501     return extents->bounding_shaped > 0;
0502 }
0503 
0504 bool Extensions::isCompositeOverlayAvailable() const
0505 {
0506     return m_composite.version >= 0x03; // 0.3
0507 }
0508 
0509 bool Extensions::isFixesRegionAvailable() const
0510 {
0511     return m_fixes.version >= 0x30; // 3
0512 }
0513 
0514 int Extensions::fixesCursorNotifyEvent() const
0515 {
0516     return m_fixes.eventBase + XCB_XFIXES_CURSOR_NOTIFY;
0517 }
0518 
0519 int Extensions::fixesSelectionNotifyEvent() const
0520 {
0521     return m_fixes.eventBase + XCB_XFIXES_SELECTION_NOTIFY;
0522 }
0523 
0524 bool Extensions::isShapeInputAvailable() const
0525 {
0526     return m_shape.version >= 0x11; // 1.1
0527 }
0528 
0529 int Extensions::randrNotifyEvent() const
0530 {
0531     return m_randr.eventBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY;
0532 }
0533 
0534 int Extensions::shapeNotifyEvent() const
0535 {
0536     return m_shape.eventBase + XCB_SHAPE_NOTIFY;
0537 }
0538 
0539 int Extensions::syncAlarmNotifyEvent() const
0540 {
0541     return m_sync.eventBase + XCB_SYNC_ALARM_NOTIFY;
0542 }
0543 
0544 QVector<ExtensionData> Extensions::extensions() const
0545 {
0546     return {
0547         m_shape,
0548         m_randr,
0549         m_damage,
0550         m_composite,
0551         m_render,
0552         m_fixes,
0553         m_sync,
0554         m_glx};
0555 }
0556 
0557 //****************************************
0558 // Shm
0559 //****************************************
0560 Shm::Shm()
0561     : m_shmId(-1)
0562     , m_buffer(nullptr)
0563     , m_segment(XCB_NONE)
0564     , m_valid(false)
0565     , m_pixmapFormat(XCB_IMAGE_FORMAT_XY_BITMAP)
0566 {
0567     m_valid = init();
0568 }
0569 
0570 Shm::~Shm()
0571 {
0572     if (m_valid) {
0573         xcb_shm_detach(connection(), m_segment);
0574         shmdt(m_buffer);
0575     }
0576 }
0577 
0578 bool Shm::init()
0579 {
0580     const xcb_query_extension_reply_t *ext = xcb_get_extension_data(connection(), &xcb_shm_id);
0581     if (!ext || !ext->present) {
0582         qCDebug(KWIN_CORE) << "SHM extension not available";
0583         return false;
0584     }
0585     UniqueCPtr<xcb_shm_query_version_reply_t> version(xcb_shm_query_version_reply(connection(),
0586                                                                                   xcb_shm_query_version_unchecked(connection()), nullptr));
0587     if (!version) {
0588         qCDebug(KWIN_CORE) << "Failed to get SHM extension version information";
0589         return false;
0590     }
0591     m_pixmapFormat = version->pixmap_format;
0592     const int MAXSIZE = 4096 * 2048 * 4; // TODO check there are not larger windows
0593     m_shmId = shmget(IPC_PRIVATE, MAXSIZE, IPC_CREAT | 0600);
0594     if (m_shmId < 0) {
0595         qCDebug(KWIN_CORE) << "Failed to allocate SHM segment";
0596         return false;
0597     }
0598     m_buffer = shmat(m_shmId, nullptr, 0 /*read/write*/);
0599     if (-1 == reinterpret_cast<long>(m_buffer)) {
0600         qCDebug(KWIN_CORE) << "Failed to attach SHM segment";
0601         shmctl(m_shmId, IPC_RMID, nullptr);
0602         return false;
0603     }
0604     shmctl(m_shmId, IPC_RMID, nullptr);
0605 
0606     m_segment = xcb_generate_id(connection());
0607     const xcb_void_cookie_t cookie = xcb_shm_attach_checked(connection(), m_segment, m_shmId, false);
0608     UniqueCPtr<xcb_generic_error_t> error(xcb_request_check(connection(), cookie));
0609     if (error) {
0610         qCDebug(KWIN_CORE) << "xcb_shm_attach error: " << error->error_code;
0611         shmdt(m_buffer);
0612         return false;
0613     }
0614 
0615     return true;
0616 }
0617 
0618 uint32_t toXNative(qreal value)
0619 {
0620     //debug helper, check for things getting mangled
0621     if (!qFuzzyIsNull(std::fmod(kwinApp()->xwaylandScale() * value, 1))) {
0622         qCDebug(KWIN_CORE) << "precision lost! floating value sent to X" << kwinApp()->xwaylandScale() * value;
0623     }
0624     return std::round(kwinApp()->xwaylandScale() * value);
0625 }
0626 
0627 QRect toXNative(const QRectF &r)
0628 {
0629     return QRect(toXNative(r.x()), toXNative(r.y()), toXNative(r.width()), toXNative(r.height()));
0630 }
0631 
0632 qreal fromXNative(int value)
0633 {
0634     return value / kwinApp()->xwaylandScale();
0635 }
0636 
0637 QRectF fromXNative(const QRect &r)
0638 {
0639     return QRectF(fromXNative(r.x()), fromXNative(r.y()), fromXNative(r.width()), fromXNative(r.height()));
0640 }
0641 
0642 QSizeF fromXNative(const QSize &s)
0643 {
0644     return QSizeF(fromXNative(s.width()), fromXNative(s.height()));
0645 }
0646 
0647 static qreal nativeFloor(qreal value)
0648 {
0649     return std::floor(value * kwinApp()->xwaylandScale()) / kwinApp()->xwaylandScale();
0650 }
0651 
0652 QRectF nativeFloor(const QRectF &rect)
0653 {
0654     const auto output = workspace()->outputAt(rect.center());
0655     const QRectF outputRect = output->mapFromGlobal(rect);
0656     return output->mapToGlobal(QRectF(nativeFloor(outputRect.left()), nativeFloor(outputRect.top()),
0657                                       nativeFloor(outputRect.width()), nativeFloor(outputRect.height())));
0658 }
0659 
0660 } // namespace Xcb
0661 } // namespace KWin