File indexing completed on 2024-05-12 05:32:16

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 QList<QByteArray> shapeOpCodes()
0051 {
0052     // see https://www.x.org/releases/X11R7.7/doc/xextproto/shape.html
0053     // extracted from <xcb/shape.h>
0054     return QList<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 QList<QByteArray> randrOpCodes()
0066 {
0067     // see https://www.x.org/releases/X11R7.7/doc/randrproto/randrproto.txt
0068     // extracted from <xcb/randr.h>
0069     return QList<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 QList<QByteArray> randrErrorCodes()
0114 {
0115     // see https://www.x.org/releases/X11R7.7/doc/randrproto/randrproto.txt
0116     // extracted from <xcb/randr.h>
0117     return QList<QByteArray>({QByteArrayLiteral("BadOutput"),
0118                               QByteArrayLiteral("BadCrtc"),
0119                               QByteArrayLiteral("BadMode"),
0120                               QByteArrayLiteral("BadProvider")});
0121 }
0122 
0123 QList<QByteArray> damageOpCodes()
0124 {
0125     // see https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt
0126     // extracted from <xcb/damage.h>
0127     return QList<QByteArray>({QByteArrayLiteral("QueryVersion"),
0128                               QByteArrayLiteral("Create"),
0129                               QByteArrayLiteral("Destroy"),
0130                               QByteArrayLiteral("Subtract"),
0131                               QByteArrayLiteral("Add")});
0132 }
0133 
0134 QList<QByteArray> damageErrorCodes()
0135 {
0136     // see https://www.x.org/releases/X11R7.7/doc/damageproto/damageproto.txt
0137     // extracted from <xcb/damage.h>
0138     return QList<QByteArray>({QByteArrayLiteral("BadDamage")});
0139 }
0140 
0141 QList<QByteArray> compositeOpCodes()
0142 {
0143     // see https://www.x.org/releases/X11R7.7/doc/compositeproto/compositeproto.txt
0144     // extracted from <xcb/composite.h>
0145     return QList<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 QList<QByteArray> fixesOpCodes()
0157 {
0158     // see https://www.x.org/releases/X11R7.7/doc/fixesproto/fixesproto.txt
0159     // extracted from <xcb/xfixes.h>
0160     return QList<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 QList<QByteArray> fixesErrorCodes()
0196 {
0197     // see https://www.x.org/releases/X11R7.7/doc/fixesproto/fixesproto.txt
0198     // extracted from <xcb/xfixes.h>
0199     return QList<QByteArray>({QByteArrayLiteral("BadRegion")});
0200 }
0201 
0202 QList<QByteArray> renderOpCodes()
0203 {
0204     // see https://www.x.org/releases/X11R7.7/doc/renderproto/renderproto.txt
0205     // extracted from <xcb/render.h>
0206     return QList<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 QList<QByteArray> syncOpCodes()
0240 {
0241     // see https://www.x.org/releases/X11R7.7/doc/xextproto/sync.html
0242     // extracted from <xcb/sync.h>
0243     return QList<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 QList<QByteArray> glxOpCodes()
0266 {
0267     return QList<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 QList<QByteArray> glxErrorCodes()
0310 {
0311     return QList<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 QList<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