File indexing completed on 2026-06-14 15:32:07

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
0006     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "wayland_backend.h"
0011 
0012 #include "wayland_display.h"
0013 #include "wayland_egl_backend.h"
0014 #include "wayland_logging.h"
0015 #include "wayland_output.h"
0016 #include "wayland_qpainter_backend.h"
0017 
0018 #include "dpmsinputeventfilter.h"
0019 #include "input.h"
0020 
0021 #include <KWayland/Client/keyboard.h>
0022 #include <KWayland/Client/pointer.h>
0023 #include <KWayland/Client/pointergestures.h>
0024 #include <KWayland/Client/relativepointer.h>
0025 #include <KWayland/Client/seat.h>
0026 #include <KWayland/Client/surface.h>
0027 #include <KWayland/Client/touch.h>
0028 
0029 #include <QAbstractEventDispatcher>
0030 
0031 #include <drm_fourcc.h>
0032 #include <fcntl.h>
0033 #include <gbm.h>
0034 #include <linux/input.h>
0035 #include <unistd.h>
0036 #include <wayland-client-core.h>
0037 
0038 #include "../drm/gbm_dmabuf.h"
0039 
0040 namespace KWin
0041 {
0042 namespace Wayland
0043 {
0044 
0045 using namespace KWayland::Client;
0046 
0047 inline static QPointF sizeToPoint(const QSizeF &size)
0048 {
0049     return QPointF(size.width(), size.height());
0050 }
0051 
0052 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Keyboard *keyboard, WaylandSeat *seat)
0053     : m_seat(seat)
0054     , m_keyboard(keyboard)
0055 {
0056     connect(keyboard, &Keyboard::keyChanged, this, [this](quint32 key, Keyboard::KeyState nativeState, quint32 time) {
0057         InputRedirection::KeyboardKeyState state;
0058         switch (nativeState) {
0059         case Keyboard::KeyState::Pressed:
0060             if (key == KEY_RIGHTCTRL) {
0061                 m_seat->backend()->togglePointerLock();
0062             }
0063             state = InputRedirection::KeyboardKeyPressed;
0064             break;
0065         case Keyboard::KeyState::Released:
0066             state = InputRedirection::KeyboardKeyReleased;
0067             break;
0068         default:
0069             Q_UNREACHABLE();
0070         }
0071         Q_EMIT keyChanged(key, state, std::chrono::milliseconds(time), this);
0072     });
0073 }
0074 
0075 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Pointer *pointer, WaylandSeat *seat)
0076     : m_seat(seat)
0077     , m_pointer(pointer)
0078 {
0079     connect(pointer, &Pointer::entered, this, [this](quint32 serial, const QPointF &relativeToSurface) {
0080         WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface());
0081         Q_ASSERT(output);
0082         output->cursor()->setPointer(m_pointer.get());
0083     });
0084     connect(pointer, &Pointer::left, this, [this]() {
0085         // wl_pointer.leave carries the wl_surface, but KWayland::Client::Pointer::left does not.
0086         const auto outputs = m_seat->backend()->outputs();
0087         for (Output *output : outputs) {
0088             WaylandOutput *waylandOutput = static_cast<WaylandOutput *>(output);
0089             if (waylandOutput->cursor()->pointer()) {
0090                 waylandOutput->cursor()->setPointer(nullptr);
0091             }
0092         }
0093     });
0094     connect(pointer, &Pointer::motion, this, [this](const QPointF &relativeToSurface, quint32 time) {
0095         WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface());
0096         Q_ASSERT(output);
0097         const QPointF absolutePos = output->geometry().topLeft() + relativeToSurface;
0098         Q_EMIT pointerMotionAbsolute(absolutePos, std::chrono::milliseconds(time), this);
0099     });
0100     connect(pointer, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState nativeState) {
0101         InputRedirection::PointerButtonState state;
0102         switch (nativeState) {
0103         case Pointer::ButtonState::Pressed:
0104             state = InputRedirection::PointerButtonPressed;
0105             break;
0106         case Pointer::ButtonState::Released:
0107             state = InputRedirection::PointerButtonReleased;
0108             break;
0109         default:
0110             Q_UNREACHABLE();
0111         }
0112         Q_EMIT pointerButtonChanged(button, state, std::chrono::milliseconds(time), this);
0113     });
0114     // TODO: Send discreteDelta and source as well.
0115     connect(pointer, &Pointer::axisChanged, this, [this](quint32 time, Pointer::Axis nativeAxis, qreal delta) {
0116         InputRedirection::PointerAxis axis;
0117         switch (nativeAxis) {
0118         case Pointer::Axis::Horizontal:
0119             axis = InputRedirection::PointerAxisHorizontal;
0120             break;
0121         case Pointer::Axis::Vertical:
0122             axis = InputRedirection::PointerAxisVertical;
0123             break;
0124         default:
0125             Q_UNREACHABLE();
0126         }
0127         Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, std::chrono::milliseconds(time), this);
0128     });
0129 
0130     KWayland::Client::PointerGestures *pointerGestures = m_seat->backend()->display()->pointerGestures();
0131     if (pointerGestures) {
0132         m_pinchGesture.reset(pointerGestures->createPinchGesture(m_pointer.get(), this));
0133         connect(m_pinchGesture.get(), &PointerPinchGesture::started, this, [this](quint32 serial, quint32 time) {
0134             Q_EMIT pinchGestureBegin(m_pinchGesture->fingerCount(), std::chrono::milliseconds(time), this);
0135         });
0136         connect(m_pinchGesture.get(), &PointerPinchGesture::updated, this, [this](const QSizeF &delta, qreal scale, qreal rotation, quint32 time) {
0137             Q_EMIT pinchGestureUpdate(scale, rotation, sizeToPoint(delta), std::chrono::milliseconds(time), this);
0138         });
0139         connect(m_pinchGesture.get(), &PointerPinchGesture::ended, this, [this](quint32 serial, quint32 time) {
0140             Q_EMIT pinchGestureEnd(std::chrono::milliseconds(time), this);
0141         });
0142         connect(m_pinchGesture.get(), &PointerPinchGesture::cancelled, this, [this](quint32 serial, quint32 time) {
0143             Q_EMIT pinchGestureCancelled(std::chrono::milliseconds(time), this);
0144         });
0145 
0146         m_swipeGesture.reset(pointerGestures->createSwipeGesture(m_pointer.get(), this));
0147         connect(m_swipeGesture.get(), &PointerSwipeGesture::started, this, [this](quint32 serial, quint32 time) {
0148             Q_EMIT swipeGestureBegin(m_swipeGesture->fingerCount(), std::chrono::milliseconds(time), this);
0149         });
0150         connect(m_swipeGesture.get(), &PointerSwipeGesture::updated, this, [this](const QSizeF &delta, quint32 time) {
0151             Q_EMIT swipeGestureUpdate(sizeToPoint(delta), std::chrono::milliseconds(time), this);
0152         });
0153         connect(m_swipeGesture.get(), &PointerSwipeGesture::ended, this, [this](quint32 serial, quint32 time) {
0154             Q_EMIT swipeGestureEnd(std::chrono::milliseconds(time), this);
0155         });
0156         connect(m_swipeGesture.get(), &PointerSwipeGesture::cancelled, this, [this](quint32 serial, quint32 time) {
0157             Q_EMIT swipeGestureCancelled(std::chrono::milliseconds(time), this);
0158         });
0159     }
0160 }
0161 
0162 WaylandInputDevice::WaylandInputDevice(KWayland::Client::RelativePointer *relativePointer, WaylandSeat *seat)
0163     : m_seat(seat)
0164     , m_relativePointer(relativePointer)
0165 {
0166     connect(relativePointer, &RelativePointer::relativeMotion, this, [this](const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestamp) {
0167         Q_EMIT pointerMotion(sizeToPoint(delta), sizeToPoint(deltaNonAccelerated), std::chrono::microseconds(timestamp), this);
0168     });
0169 }
0170 
0171 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Touch *touch, WaylandSeat *seat)
0172     : m_seat(seat)
0173     , m_touch(touch)
0174 {
0175     connect(touch, &Touch::sequenceCanceled, this, [this]() {
0176         Q_EMIT touchCanceled(this);
0177     });
0178     connect(touch, &Touch::frameEnded, this, [this]() {
0179         Q_EMIT touchFrame(this);
0180     });
0181     connect(touch, &Touch::sequenceStarted, this, [this](TouchPoint *tp) {
0182         Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this);
0183     });
0184     connect(touch, &Touch::pointAdded, this, [this](TouchPoint *tp) {
0185         Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this);
0186     });
0187     connect(touch, &Touch::pointRemoved, this, [this](TouchPoint *tp) {
0188         Q_EMIT touchUp(tp->id(), std::chrono::milliseconds(tp->time()), this);
0189     });
0190     connect(touch, &Touch::pointMoved, this, [this](TouchPoint *tp) {
0191         Q_EMIT touchMotion(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this);
0192     });
0193 }
0194 
0195 WaylandInputDevice::~WaylandInputDevice()
0196 {
0197 }
0198 
0199 QString WaylandInputDevice::sysName() const
0200 {
0201     return QString();
0202 }
0203 
0204 QString WaylandInputDevice::name() const
0205 {
0206     return QString();
0207 }
0208 
0209 bool WaylandInputDevice::isEnabled() const
0210 {
0211     return true;
0212 }
0213 
0214 void WaylandInputDevice::setEnabled(bool enabled)
0215 {
0216 }
0217 
0218 LEDs WaylandInputDevice::leds() const
0219 {
0220     return LEDs();
0221 }
0222 
0223 void WaylandInputDevice::setLeds(LEDs leds)
0224 {
0225 }
0226 
0227 bool WaylandInputDevice::isKeyboard() const
0228 {
0229     return m_keyboard != nullptr;
0230 }
0231 
0232 bool WaylandInputDevice::isAlphaNumericKeyboard() const
0233 {
0234     return m_keyboard != nullptr;
0235 }
0236 
0237 bool WaylandInputDevice::isPointer() const
0238 {
0239     return m_pointer || m_relativePointer;
0240 }
0241 
0242 bool WaylandInputDevice::isTouchpad() const
0243 {
0244     return false;
0245 }
0246 
0247 bool WaylandInputDevice::isTouch() const
0248 {
0249     return m_touch != nullptr;
0250 }
0251 
0252 bool WaylandInputDevice::isTabletTool() const
0253 {
0254     return false;
0255 }
0256 
0257 bool WaylandInputDevice::isTabletPad() const
0258 {
0259     return false;
0260 }
0261 
0262 bool WaylandInputDevice::isTabletModeSwitch() const
0263 {
0264     return false;
0265 }
0266 
0267 bool WaylandInputDevice::isLidSwitch() const
0268 {
0269     return false;
0270 }
0271 
0272 KWayland::Client::Pointer *WaylandInputDevice::nativePointer() const
0273 {
0274     return m_pointer.get();
0275 }
0276 
0277 WaylandInputBackend::WaylandInputBackend(WaylandBackend *backend, QObject *parent)
0278     : InputBackend(parent)
0279     , m_backend(backend)
0280 {
0281 }
0282 
0283 void WaylandInputBackend::initialize()
0284 {
0285     WaylandSeat *seat = m_backend->seat();
0286     if (seat->relativePointerDevice()) {
0287         Q_EMIT deviceAdded(seat->relativePointerDevice());
0288     }
0289     if (seat->pointerDevice()) {
0290         Q_EMIT deviceAdded(seat->pointerDevice());
0291     }
0292     if (seat->keyboardDevice()) {
0293         Q_EMIT deviceAdded(seat->keyboardDevice());
0294     }
0295     if (seat->touchDevice()) {
0296         Q_EMIT deviceAdded(seat->touchDevice());
0297     }
0298 
0299     connect(seat, &WaylandSeat::deviceAdded, this, &InputBackend::deviceAdded);
0300     connect(seat, &WaylandSeat::deviceRemoved, this, &InputBackend::deviceRemoved);
0301 }
0302 
0303 WaylandSeat::WaylandSeat(KWayland::Client::Seat *nativeSeat, WaylandBackend *backend)
0304     : QObject(nullptr)
0305     , m_seat(nativeSeat)
0306     , m_backend(backend)
0307 {
0308     auto updateKeyboardDevice = [this](){
0309         if (m_seat->hasKeyboard()) {
0310             createKeyboardDevice();
0311         } else {
0312             destroyKeyboardDevice();
0313         }
0314     };
0315 
0316     updateKeyboardDevice();
0317     connect(m_seat, &Seat::hasKeyboardChanged, this, updateKeyboardDevice);
0318 
0319     auto updatePointerDevice = [this]() {
0320         if (m_seat->hasPointer()) {
0321             createPointerDevice();
0322         } else {
0323             destroyPointerDevice();
0324         }
0325     };
0326 
0327     updatePointerDevice();
0328     connect(m_seat, &Seat::hasPointerChanged, this, updatePointerDevice);
0329 
0330     auto updateTouchDevice = [this]() {
0331         if (m_seat->hasTouch()) {
0332             createTouchDevice();
0333         } else {
0334             destroyTouchDevice();
0335         }
0336     };
0337 
0338     updateTouchDevice();
0339     connect(m_seat, &Seat::hasTouchChanged, this, updateTouchDevice);
0340 }
0341 
0342 WaylandSeat::~WaylandSeat()
0343 {
0344     destroyPointerDevice();
0345     destroyKeyboardDevice();
0346     destroyTouchDevice();
0347 }
0348 
0349 void WaylandSeat::createPointerDevice()
0350 {
0351     m_pointerDevice = std::make_unique<WaylandInputDevice>(m_seat->createPointer(), this);
0352     Q_EMIT deviceAdded(m_pointerDevice.get());
0353 }
0354 
0355 void WaylandSeat::destroyPointerDevice()
0356 {
0357     if (m_pointerDevice) {
0358         Q_EMIT deviceRemoved(m_pointerDevice.get());
0359         destroyRelativePointer();
0360         m_pointerDevice.reset();
0361     }
0362 }
0363 
0364 void WaylandSeat::createRelativePointer()
0365 {
0366     KWayland::Client::RelativePointerManager *manager = m_backend->display()->relativePointerManager();
0367     if (manager) {
0368         m_relativePointerDevice = std::make_unique<WaylandInputDevice>(manager->createRelativePointer(m_pointerDevice->nativePointer()), this);
0369         Q_EMIT deviceAdded(m_relativePointerDevice.get());
0370     }
0371 }
0372 
0373 void WaylandSeat::destroyRelativePointer()
0374 {
0375     if (m_relativePointerDevice) {
0376         Q_EMIT deviceRemoved(m_relativePointerDevice.get());
0377         m_relativePointerDevice.reset();
0378     }
0379 }
0380 
0381 void WaylandSeat::createKeyboardDevice()
0382 {
0383     m_keyboardDevice = std::make_unique<WaylandInputDevice>(m_seat->createKeyboard(), this);
0384     Q_EMIT deviceAdded(m_keyboardDevice.get());
0385 }
0386 
0387 void WaylandSeat::destroyKeyboardDevice()
0388 {
0389     if (m_keyboardDevice) {
0390         Q_EMIT deviceRemoved(m_keyboardDevice.get());
0391         m_keyboardDevice.reset();
0392     }
0393 }
0394 
0395 void WaylandSeat::createTouchDevice()
0396 {
0397     m_touchDevice = std::make_unique<WaylandInputDevice>(m_seat->createTouch(), this);
0398     Q_EMIT deviceAdded(m_touchDevice.get());
0399 }
0400 
0401 void WaylandSeat::destroyTouchDevice()
0402 {
0403     if (m_touchDevice) {
0404         Q_EMIT deviceRemoved(m_touchDevice.get());
0405         m_touchDevice.reset();
0406     }
0407 }
0408 
0409 WaylandBackend::WaylandBackend(const WaylandBackendOptions &options, QObject *parent)
0410     : OutputBackend(parent)
0411     , m_options(options)
0412 {
0413     char const *drm_render_node = "/dev/dri/renderD128";
0414     m_drmFileDescriptor = FileDescriptor(open(drm_render_node, O_RDWR | O_CLOEXEC));
0415     if (!m_drmFileDescriptor.isValid()) {
0416         qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to open drm render node" << drm_render_node;
0417         m_gbmDevice = nullptr;
0418         return;
0419     }
0420     m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get());
0421 }
0422 
0423 WaylandBackend::~WaylandBackend()
0424 {
0425     if (sceneEglDisplay() != EGL_NO_DISPLAY) {
0426         eglTerminate(sceneEglDisplay());
0427     }
0428 
0429     destroyOutputs();
0430 
0431     m_seat.reset();
0432     m_display.reset();
0433 
0434     if (m_gbmDevice) {
0435         gbm_device_destroy(m_gbmDevice);
0436     }
0437     qCDebug(KWIN_WAYLAND_BACKEND) << "Destroyed Wayland display";
0438 }
0439 
0440 bool WaylandBackend::initialize()
0441 {
0442     m_display = std::make_unique<WaylandDisplay>();
0443     if (!m_display->initialize(m_options.socketName)) {
0444         return false;
0445     }
0446 
0447     createOutputs();
0448 
0449     m_seat = std::make_unique<WaylandSeat>(m_display->seat(), this);
0450 
0451     QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance();
0452     QObject::connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_display.get(), &WaylandDisplay::flush);
0453     QObject::connect(dispatcher, &QAbstractEventDispatcher::awake, m_display.get(), &WaylandDisplay::flush);
0454 
0455     connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) {
0456         if (locked) {
0457             m_seat->createRelativePointer();
0458         } else {
0459             m_seat->destroyRelativePointer();
0460         }
0461     });
0462 
0463     return true;
0464 }
0465 
0466 void WaylandBackend::createOutputs()
0467 {
0468     // we need to multiply the initial window size with the scale in order to
0469     // create an output window of this size in the end
0470     const QSize pixelSize = m_options.outputSize * m_options.outputScale;
0471     for (int i = 0; i < m_options.outputCount; i++) {
0472         WaylandOutput *output = createOutput(QStringLiteral("WL-%1").arg(i), pixelSize, m_options.outputScale);
0473         m_outputs << output;
0474         Q_EMIT outputAdded(output);
0475         output->updateEnabled(true);
0476     }
0477 
0478     Q_EMIT outputsQueried();
0479 }
0480 
0481 WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size, qreal scale)
0482 {
0483     WaylandOutput *waylandOutput = new WaylandOutput(name, this);
0484     waylandOutput->init(size, scale);
0485 
0486     // Wait until the output window is configured by the host compositor.
0487     while (!waylandOutput->isReady()) {
0488         wl_display_roundtrip(m_display->nativeDisplay());
0489     }
0490 
0491     return waylandOutput;
0492 }
0493 
0494 void WaylandBackend::destroyOutputs()
0495 {
0496     while (!m_outputs.isEmpty()) {
0497         WaylandOutput *output = m_outputs.takeLast();
0498         output->updateEnabled(false);
0499         Q_EMIT outputRemoved(output);
0500         delete output;
0501     }
0502 }
0503 
0504 std::unique_ptr<InputBackend> WaylandBackend::createInputBackend()
0505 {
0506     return std::make_unique<WaylandInputBackend>(this);
0507 }
0508 
0509 std::unique_ptr<OpenGLBackend> WaylandBackend::createOpenGLBackend()
0510 {
0511     return std::make_unique<WaylandEglBackend>(this);
0512 }
0513 
0514 std::unique_ptr<QPainterBackend> WaylandBackend::createQPainterBackend()
0515 {
0516     return std::make_unique<WaylandQPainterBackend>(this);
0517 }
0518 
0519 WaylandOutput *WaylandBackend::findOutput(KWayland::Client::Surface *nativeSurface) const
0520 {
0521     for (WaylandOutput *output : m_outputs) {
0522         if (output->surface() == nativeSurface) {
0523             return output;
0524         }
0525     }
0526     return nullptr;
0527 }
0528 
0529 bool WaylandBackend::supportsPointerLock()
0530 {
0531     return m_display->pointerConstraints() && m_display->relativePointerManager();
0532 }
0533 
0534 void WaylandBackend::togglePointerLock()
0535 {
0536     if (!supportsPointerLock()) {
0537         return;
0538     }
0539     if (!m_seat) {
0540         return;
0541     }
0542     auto pointer = m_seat->pointerDevice()->nativePointer();
0543     if (!pointer) {
0544         return;
0545     }
0546     if (m_outputs.isEmpty()) {
0547         return;
0548     }
0549 
0550     for (auto output : std::as_const(m_outputs)) {
0551         output->lockPointer(m_seat->pointerDevice()->nativePointer(), !m_pointerLockRequested);
0552     }
0553     m_pointerLockRequested = !m_pointerLockRequested;
0554 }
0555 
0556 QVector<CompositingType> WaylandBackend::supportedCompositors() const
0557 {
0558     QVector<CompositingType> ret;
0559     if (m_display->linuxDmabuf() && m_gbmDevice) {
0560         ret.append(OpenGLCompositing);
0561     }
0562     ret.append(QPainterCompositing);
0563     return ret;
0564 }
0565 
0566 Outputs WaylandBackend::outputs() const
0567 {
0568     return m_outputs;
0569 }
0570 
0571 void WaylandBackend::createDpmsFilter()
0572 {
0573     if (m_dpmsFilter) {
0574         // already another output is off
0575         return;
0576     }
0577     m_dpmsFilter = std::make_unique<DpmsInputEventFilter>();
0578     input()->prependInputEventFilter(m_dpmsFilter.get());
0579 }
0580 
0581 void WaylandBackend::clearDpmsFilter()
0582 {
0583     m_dpmsFilter.reset();
0584 }
0585 
0586 Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale)
0587 {
0588     return createOutput(name, size * scale, scale);
0589 }
0590 
0591 void WaylandBackend::removeVirtualOutput(Output *output)
0592 {
0593     WaylandOutput *waylandOutput = dynamic_cast<WaylandOutput *>(output);
0594     if (waylandOutput && m_outputs.removeAll(waylandOutput)) {
0595         waylandOutput->updateEnabled(false);
0596         Q_EMIT outputRemoved(waylandOutput);
0597         waylandOutput->unref();
0598     }
0599 }
0600 
0601 std::optional<DmaBufParams> WaylandBackend::testCreateDmaBuf(const QSize &size, quint32 format, const QVector<uint64_t> &modifiers)
0602 {
0603     gbm_bo *bo = createGbmBo(m_gbmDevice, size, format, modifiers);
0604     if (!bo) {
0605         return {};
0606     }
0607 
0608     auto ret = dmaBufParamsForBo(bo);
0609     gbm_bo_destroy(bo);
0610     return ret;
0611 }
0612 
0613 std::shared_ptr<DmaBufTexture> WaylandBackend::createDmaBufTexture(const QSize &size, quint32 format, uint64_t modifier)
0614 {
0615     gbm_bo *bo = createGbmBo(m_gbmDevice, size, format, {modifier});
0616     if (!bo) {
0617         return {};
0618     }
0619 
0620     // The bo will be kept around until the last fd is closed.
0621     DmaBufAttributes attributes = dmaBufAttributesForBo(bo);
0622     gbm_bo_destroy(bo);
0623     m_eglBackend->makeCurrent();
0624     return std::make_shared<DmaBufTexture>(m_eglBackend->importDmaBufAsTexture(attributes), std::move(attributes));
0625 }
0626 
0627 }
0628 
0629 } // KWin