File indexing completed on 2024-11-10 04:56:33

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 #include "input.h"
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 <KWayland/Client/keyboard.h>
0019 #include <KWayland/Client/pointer.h>
0020 #include <KWayland/Client/pointergestures.h>
0021 #include <KWayland/Client/relativepointer.h>
0022 #include <KWayland/Client/seat.h>
0023 #include <KWayland/Client/surface.h>
0024 #include <KWayland/Client/touch.h>
0025 
0026 #include <QAbstractEventDispatcher>
0027 
0028 #include <drm_fourcc.h>
0029 #include <fcntl.h>
0030 #include <gbm.h>
0031 #include <linux/input.h>
0032 #include <unistd.h>
0033 #include <wayland-client-core.h>
0034 
0035 #include "wayland-linux-dmabuf-unstable-v1-client-protocol.h"
0036 
0037 namespace KWin
0038 {
0039 namespace Wayland
0040 {
0041 
0042 using namespace KWayland::Client;
0043 
0044 inline static QPointF sizeToPoint(const QSizeF &size)
0045 {
0046     return QPointF(size.width(), size.height());
0047 }
0048 
0049 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Keyboard *keyboard, WaylandSeat *seat)
0050     : m_seat(seat)
0051     , m_keyboard(keyboard)
0052 {
0053     connect(keyboard, &Keyboard::left, this, [this](quint32 time) {
0054         for (quint32 key : std::as_const(m_pressedKeys)) {
0055             Q_EMIT keyChanged(key, InputRedirection::KeyboardKeyReleased, std::chrono::milliseconds(time), this);
0056         }
0057         m_pressedKeys.clear();
0058     });
0059     connect(keyboard, &Keyboard::keyChanged, this, [this](quint32 key, Keyboard::KeyState nativeState, quint32 time) {
0060         InputRedirection::KeyboardKeyState state;
0061         switch (nativeState) {
0062         case Keyboard::KeyState::Pressed:
0063             if (key == KEY_RIGHTCTRL) {
0064                 m_seat->backend()->togglePointerLock();
0065             }
0066             state = InputRedirection::KeyboardKeyPressed;
0067             m_pressedKeys.insert(key);
0068             break;
0069         case Keyboard::KeyState::Released:
0070             m_pressedKeys.remove(key);
0071             state = InputRedirection::KeyboardKeyReleased;
0072             break;
0073         default:
0074             Q_UNREACHABLE();
0075         }
0076         Q_EMIT keyChanged(key, state, std::chrono::milliseconds(time), this);
0077     });
0078 }
0079 
0080 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Pointer *pointer, WaylandSeat *seat)
0081     : m_seat(seat)
0082     , m_pointer(pointer)
0083 {
0084     connect(pointer, &Pointer::entered, this, [this](quint32 serial, const QPointF &relativeToSurface) {
0085         WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface());
0086         Q_ASSERT(output);
0087         output->cursor()->setPointer(m_pointer.get());
0088     });
0089     connect(pointer, &Pointer::left, this, [this]() {
0090         // wl_pointer.leave carries the wl_surface, but KWayland::Client::Pointer::left does not.
0091         const auto outputs = m_seat->backend()->outputs();
0092         for (Output *output : outputs) {
0093             WaylandOutput *waylandOutput = static_cast<WaylandOutput *>(output);
0094             if (waylandOutput->cursor()->pointer()) {
0095                 waylandOutput->cursor()->setPointer(nullptr);
0096             }
0097         }
0098     });
0099     connect(pointer, &Pointer::motion, this, [this](const QPointF &relativeToSurface, quint32 time) {
0100         WaylandOutput *output = m_seat->backend()->findOutput(m_pointer->enteredSurface());
0101         Q_ASSERT(output);
0102         const QPointF absolutePos = output->geometry().topLeft() + relativeToSurface;
0103         Q_EMIT pointerMotionAbsolute(absolutePos, std::chrono::milliseconds(time), this);
0104     });
0105     connect(pointer, &Pointer::buttonStateChanged, this, [this](quint32 serial, quint32 time, quint32 button, Pointer::ButtonState nativeState) {
0106         InputRedirection::PointerButtonState state;
0107         switch (nativeState) {
0108         case Pointer::ButtonState::Pressed:
0109             state = InputRedirection::PointerButtonPressed;
0110             break;
0111         case Pointer::ButtonState::Released:
0112             state = InputRedirection::PointerButtonReleased;
0113             break;
0114         default:
0115             Q_UNREACHABLE();
0116         }
0117         Q_EMIT pointerButtonChanged(button, state, std::chrono::milliseconds(time), this);
0118     });
0119     // TODO: Send discreteDelta and source as well.
0120     connect(pointer, &Pointer::axisChanged, this, [this](quint32 time, Pointer::Axis nativeAxis, qreal delta) {
0121         InputRedirection::PointerAxis axis;
0122         switch (nativeAxis) {
0123         case Pointer::Axis::Horizontal:
0124             axis = InputRedirection::PointerAxisHorizontal;
0125             break;
0126         case Pointer::Axis::Vertical:
0127             axis = InputRedirection::PointerAxisVertical;
0128             break;
0129         default:
0130             Q_UNREACHABLE();
0131         }
0132         Q_EMIT pointerAxisChanged(axis, delta, 0, InputRedirection::PointerAxisSourceUnknown, std::chrono::milliseconds(time), this);
0133     });
0134 
0135     connect(pointer, &Pointer::frame, this, [this]() {
0136         Q_EMIT pointerFrame(this);
0137     });
0138 
0139     KWayland::Client::PointerGestures *pointerGestures = m_seat->backend()->display()->pointerGestures();
0140     if (pointerGestures) {
0141         m_pinchGesture.reset(pointerGestures->createPinchGesture(m_pointer.get(), this));
0142         connect(m_pinchGesture.get(), &PointerPinchGesture::started, this, [this](quint32 serial, quint32 time) {
0143             Q_EMIT pinchGestureBegin(m_pinchGesture->fingerCount(), std::chrono::milliseconds(time), this);
0144         });
0145         connect(m_pinchGesture.get(), &PointerPinchGesture::updated, this, [this](const QSizeF &delta, qreal scale, qreal rotation, quint32 time) {
0146             Q_EMIT pinchGestureUpdate(scale, rotation, sizeToPoint(delta), std::chrono::milliseconds(time), this);
0147         });
0148         connect(m_pinchGesture.get(), &PointerPinchGesture::ended, this, [this](quint32 serial, quint32 time) {
0149             Q_EMIT pinchGestureEnd(std::chrono::milliseconds(time), this);
0150         });
0151         connect(m_pinchGesture.get(), &PointerPinchGesture::cancelled, this, [this](quint32 serial, quint32 time) {
0152             Q_EMIT pinchGestureCancelled(std::chrono::milliseconds(time), this);
0153         });
0154 
0155         m_swipeGesture.reset(pointerGestures->createSwipeGesture(m_pointer.get(), this));
0156         connect(m_swipeGesture.get(), &PointerSwipeGesture::started, this, [this](quint32 serial, quint32 time) {
0157             Q_EMIT swipeGestureBegin(m_swipeGesture->fingerCount(), std::chrono::milliseconds(time), this);
0158         });
0159         connect(m_swipeGesture.get(), &PointerSwipeGesture::updated, this, [this](const QSizeF &delta, quint32 time) {
0160             Q_EMIT swipeGestureUpdate(sizeToPoint(delta), std::chrono::milliseconds(time), this);
0161         });
0162         connect(m_swipeGesture.get(), &PointerSwipeGesture::ended, this, [this](quint32 serial, quint32 time) {
0163             Q_EMIT swipeGestureEnd(std::chrono::milliseconds(time), this);
0164         });
0165         connect(m_swipeGesture.get(), &PointerSwipeGesture::cancelled, this, [this](quint32 serial, quint32 time) {
0166             Q_EMIT swipeGestureCancelled(std::chrono::milliseconds(time), this);
0167         });
0168     }
0169 }
0170 
0171 WaylandInputDevice::WaylandInputDevice(KWayland::Client::RelativePointer *relativePointer, WaylandSeat *seat)
0172     : m_seat(seat)
0173     , m_relativePointer(relativePointer)
0174 {
0175     connect(relativePointer, &RelativePointer::relativeMotion, this, [this](const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestamp) {
0176         Q_EMIT pointerMotion(sizeToPoint(delta), sizeToPoint(deltaNonAccelerated), std::chrono::microseconds(timestamp), this);
0177     });
0178 }
0179 
0180 WaylandInputDevice::WaylandInputDevice(KWayland::Client::Touch *touch, WaylandSeat *seat)
0181     : m_seat(seat)
0182     , m_touch(touch)
0183 {
0184     connect(touch, &Touch::sequenceCanceled, this, [this]() {
0185         Q_EMIT touchCanceled(this);
0186     });
0187     connect(touch, &Touch::frameEnded, this, [this]() {
0188         Q_EMIT touchFrame(this);
0189     });
0190     connect(touch, &Touch::sequenceStarted, this, [this](TouchPoint *tp) {
0191         Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this);
0192     });
0193     connect(touch, &Touch::pointAdded, this, [this](TouchPoint *tp) {
0194         Q_EMIT touchDown(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this);
0195     });
0196     connect(touch, &Touch::pointRemoved, this, [this](TouchPoint *tp) {
0197         Q_EMIT touchUp(tp->id(), std::chrono::milliseconds(tp->time()), this);
0198     });
0199     connect(touch, &Touch::pointMoved, this, [this](TouchPoint *tp) {
0200         Q_EMIT touchMotion(tp->id(), tp->position(), std::chrono::milliseconds(tp->time()), this);
0201     });
0202 }
0203 
0204 WaylandInputDevice::~WaylandInputDevice()
0205 {
0206 }
0207 
0208 QString WaylandInputDevice::sysName() const
0209 {
0210     return QString();
0211 }
0212 
0213 QString WaylandInputDevice::name() const
0214 {
0215     return QString();
0216 }
0217 
0218 bool WaylandInputDevice::isEnabled() const
0219 {
0220     return true;
0221 }
0222 
0223 void WaylandInputDevice::setEnabled(bool enabled)
0224 {
0225 }
0226 
0227 LEDs WaylandInputDevice::leds() const
0228 {
0229     return LEDs();
0230 }
0231 
0232 void WaylandInputDevice::setLeds(LEDs leds)
0233 {
0234 }
0235 
0236 bool WaylandInputDevice::isKeyboard() const
0237 {
0238     return m_keyboard != nullptr;
0239 }
0240 
0241 bool WaylandInputDevice::isAlphaNumericKeyboard() const
0242 {
0243     return m_keyboard != nullptr;
0244 }
0245 
0246 bool WaylandInputDevice::isPointer() const
0247 {
0248     return m_pointer || m_relativePointer;
0249 }
0250 
0251 bool WaylandInputDevice::isTouchpad() const
0252 {
0253     return false;
0254 }
0255 
0256 bool WaylandInputDevice::isTouch() const
0257 {
0258     return m_touch != nullptr;
0259 }
0260 
0261 bool WaylandInputDevice::isTabletTool() const
0262 {
0263     return false;
0264 }
0265 
0266 bool WaylandInputDevice::isTabletPad() const
0267 {
0268     return false;
0269 }
0270 
0271 bool WaylandInputDevice::isTabletModeSwitch() const
0272 {
0273     return false;
0274 }
0275 
0276 bool WaylandInputDevice::isLidSwitch() const
0277 {
0278     return false;
0279 }
0280 
0281 KWayland::Client::Pointer *WaylandInputDevice::nativePointer() const
0282 {
0283     return m_pointer.get();
0284 }
0285 
0286 WaylandInputBackend::WaylandInputBackend(WaylandBackend *backend, QObject *parent)
0287     : InputBackend(parent)
0288     , m_backend(backend)
0289 {
0290 }
0291 
0292 void WaylandInputBackend::initialize()
0293 {
0294     WaylandSeat *seat = m_backend->seat();
0295     if (seat->relativePointerDevice()) {
0296         Q_EMIT deviceAdded(seat->relativePointerDevice());
0297     }
0298     if (seat->pointerDevice()) {
0299         Q_EMIT deviceAdded(seat->pointerDevice());
0300     }
0301     if (seat->keyboardDevice()) {
0302         Q_EMIT deviceAdded(seat->keyboardDevice());
0303     }
0304     if (seat->touchDevice()) {
0305         Q_EMIT deviceAdded(seat->touchDevice());
0306     }
0307 
0308     connect(seat, &WaylandSeat::deviceAdded, this, &InputBackend::deviceAdded);
0309     connect(seat, &WaylandSeat::deviceRemoved, this, &InputBackend::deviceRemoved);
0310 }
0311 
0312 WaylandSeat::WaylandSeat(KWayland::Client::Seat *nativeSeat, WaylandBackend *backend)
0313     : QObject(nullptr)
0314     , m_seat(nativeSeat)
0315     , m_backend(backend)
0316 {
0317     auto updateKeyboardDevice = [this](){
0318         if (m_seat->hasKeyboard()) {
0319             createKeyboardDevice();
0320         } else {
0321             destroyKeyboardDevice();
0322         }
0323     };
0324 
0325     updateKeyboardDevice();
0326     connect(m_seat, &Seat::hasKeyboardChanged, this, updateKeyboardDevice);
0327 
0328     auto updatePointerDevice = [this]() {
0329         if (m_seat->hasPointer()) {
0330             createPointerDevice();
0331         } else {
0332             destroyPointerDevice();
0333         }
0334     };
0335 
0336     updatePointerDevice();
0337     connect(m_seat, &Seat::hasPointerChanged, this, updatePointerDevice);
0338 
0339     auto updateTouchDevice = [this]() {
0340         if (m_seat->hasTouch()) {
0341             createTouchDevice();
0342         } else {
0343             destroyTouchDevice();
0344         }
0345     };
0346 
0347     updateTouchDevice();
0348     connect(m_seat, &Seat::hasTouchChanged, this, updateTouchDevice);
0349 }
0350 
0351 WaylandSeat::~WaylandSeat()
0352 {
0353     destroyPointerDevice();
0354     destroyKeyboardDevice();
0355     destroyTouchDevice();
0356 }
0357 
0358 void WaylandSeat::createPointerDevice()
0359 {
0360     m_pointerDevice = std::make_unique<WaylandInputDevice>(m_seat->createPointer(), this);
0361     Q_EMIT deviceAdded(m_pointerDevice.get());
0362 }
0363 
0364 void WaylandSeat::destroyPointerDevice()
0365 {
0366     if (m_pointerDevice) {
0367         Q_EMIT deviceRemoved(m_pointerDevice.get());
0368         destroyRelativePointer();
0369         m_pointerDevice.reset();
0370     }
0371 }
0372 
0373 void WaylandSeat::createRelativePointer()
0374 {
0375     KWayland::Client::RelativePointerManager *manager = m_backend->display()->relativePointerManager();
0376     if (manager) {
0377         m_relativePointerDevice = std::make_unique<WaylandInputDevice>(manager->createRelativePointer(m_pointerDevice->nativePointer()), this);
0378         Q_EMIT deviceAdded(m_relativePointerDevice.get());
0379     }
0380 }
0381 
0382 void WaylandSeat::destroyRelativePointer()
0383 {
0384     if (m_relativePointerDevice) {
0385         Q_EMIT deviceRemoved(m_relativePointerDevice.get());
0386         m_relativePointerDevice.reset();
0387     }
0388 }
0389 
0390 void WaylandSeat::createKeyboardDevice()
0391 {
0392     m_keyboardDevice = std::make_unique<WaylandInputDevice>(m_seat->createKeyboard(), this);
0393     Q_EMIT deviceAdded(m_keyboardDevice.get());
0394 }
0395 
0396 void WaylandSeat::destroyKeyboardDevice()
0397 {
0398     if (m_keyboardDevice) {
0399         Q_EMIT deviceRemoved(m_keyboardDevice.get());
0400         m_keyboardDevice.reset();
0401     }
0402 }
0403 
0404 void WaylandSeat::createTouchDevice()
0405 {
0406     m_touchDevice = std::make_unique<WaylandInputDevice>(m_seat->createTouch(), this);
0407     Q_EMIT deviceAdded(m_touchDevice.get());
0408 }
0409 
0410 void WaylandSeat::destroyTouchDevice()
0411 {
0412     if (m_touchDevice) {
0413         Q_EMIT deviceRemoved(m_touchDevice.get());
0414         m_touchDevice.reset();
0415     }
0416 }
0417 
0418 WaylandBackend::WaylandBackend(const WaylandBackendOptions &options, QObject *parent)
0419     : OutputBackend(parent)
0420     , m_options(options)
0421 {
0422 }
0423 
0424 WaylandBackend::~WaylandBackend()
0425 {
0426     m_eglDisplay.reset();
0427     destroyOutputs();
0428 
0429     m_buffers.clear();
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     if (WaylandLinuxDmabufV1 *dmabuf = m_display->linuxDmabuf()) {
0448         m_drmFileDescriptor = FileDescriptor(open(dmabuf->mainDevice(), O_RDWR | O_CLOEXEC));
0449         if (m_drmFileDescriptor.isValid()) {
0450             m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get());
0451         } else {
0452             qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to open drm render node" << dmabuf->mainDevice();
0453         }
0454     }
0455 
0456     createOutputs();
0457 
0458     m_seat = std::make_unique<WaylandSeat>(m_display->seat(), this);
0459 
0460     QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance();
0461     QObject::connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, m_display.get(), &WaylandDisplay::flush);
0462     QObject::connect(dispatcher, &QAbstractEventDispatcher::awake, m_display.get(), &WaylandDisplay::flush);
0463 
0464     connect(this, &WaylandBackend::pointerLockChanged, this, [this](bool locked) {
0465         if (locked) {
0466             m_seat->createRelativePointer();
0467         } else {
0468             m_seat->destroyRelativePointer();
0469         }
0470     });
0471 
0472     return true;
0473 }
0474 
0475 void WaylandBackend::createOutputs()
0476 {
0477     // we need to multiply the initial window size with the scale in order to
0478     // create an output window of this size in the end
0479     const QSize pixelSize = m_options.outputSize * m_options.outputScale;
0480     for (int i = 0; i < m_options.outputCount; i++) {
0481         WaylandOutput *output = createOutput(QStringLiteral("WL-%1").arg(i), pixelSize, m_options.outputScale);
0482         m_outputs << output;
0483         Q_EMIT outputAdded(output);
0484         output->updateEnabled(true);
0485     }
0486 
0487     Q_EMIT outputsQueried();
0488 }
0489 
0490 WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size, qreal scale)
0491 {
0492     WaylandOutput *waylandOutput = new WaylandOutput(name, this);
0493     waylandOutput->init(size, scale);
0494 
0495     // Wait until the output window is configured by the host compositor.
0496     while (!waylandOutput->isReady()) {
0497         wl_display_roundtrip(m_display->nativeDisplay());
0498     }
0499 
0500     return waylandOutput;
0501 }
0502 
0503 void WaylandBackend::destroyOutputs()
0504 {
0505     while (!m_outputs.isEmpty()) {
0506         WaylandOutput *output = m_outputs.takeLast();
0507         output->updateEnabled(false);
0508         Q_EMIT outputRemoved(output);
0509         delete output;
0510     }
0511 }
0512 
0513 std::unique_ptr<InputBackend> WaylandBackend::createInputBackend()
0514 {
0515     return std::make_unique<WaylandInputBackend>(this);
0516 }
0517 
0518 std::unique_ptr<OpenGLBackend> WaylandBackend::createOpenGLBackend()
0519 {
0520     return std::make_unique<WaylandEglBackend>(this);
0521 }
0522 
0523 std::unique_ptr<QPainterBackend> WaylandBackend::createQPainterBackend()
0524 {
0525     return std::make_unique<WaylandQPainterBackend>(this);
0526 }
0527 
0528 WaylandOutput *WaylandBackend::findOutput(KWayland::Client::Surface *nativeSurface) const
0529 {
0530     for (WaylandOutput *output : m_outputs) {
0531         if (output->surface() == nativeSurface) {
0532             return output;
0533         }
0534     }
0535     return nullptr;
0536 }
0537 
0538 bool WaylandBackend::supportsPointerLock()
0539 {
0540     return m_display->pointerConstraints() && m_display->relativePointerManager();
0541 }
0542 
0543 void WaylandBackend::togglePointerLock()
0544 {
0545     if (!supportsPointerLock()) {
0546         return;
0547     }
0548     if (!m_seat) {
0549         return;
0550     }
0551     auto pointer = m_seat->pointerDevice()->nativePointer();
0552     if (!pointer) {
0553         return;
0554     }
0555     if (m_outputs.isEmpty()) {
0556         return;
0557     }
0558 
0559     for (auto output : std::as_const(m_outputs)) {
0560         output->lockPointer(m_seat->pointerDevice()->nativePointer(), !m_pointerLockRequested);
0561     }
0562     m_pointerLockRequested = !m_pointerLockRequested;
0563 }
0564 
0565 QList<CompositingType> WaylandBackend::supportedCompositors() const
0566 {
0567     QList<CompositingType> ret;
0568     if (m_display->linuxDmabuf() && m_gbmDevice) {
0569         ret.append(OpenGLCompositing);
0570     }
0571     ret.append(QPainterCompositing);
0572     return ret;
0573 }
0574 
0575 Outputs WaylandBackend::outputs() const
0576 {
0577     return m_outputs;
0578 }
0579 
0580 Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale)
0581 {
0582     return createOutput(name, size * scale, scale);
0583 }
0584 
0585 void WaylandBackend::removeVirtualOutput(Output *output)
0586 {
0587     WaylandOutput *waylandOutput = dynamic_cast<WaylandOutput *>(output);
0588     if (waylandOutput && m_outputs.removeAll(waylandOutput)) {
0589         waylandOutput->updateEnabled(false);
0590         Q_EMIT outputRemoved(waylandOutput);
0591         waylandOutput->unref();
0592     }
0593 }
0594 
0595 static wl_buffer *importDmaBufBuffer(WaylandDisplay *display, const DmaBufAttributes *attributes)
0596 {
0597     zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(display->linuxDmabuf()->handle());
0598     for (int i = 0; i < attributes->planeCount; ++i) {
0599         zwp_linux_buffer_params_v1_add(params,
0600                                        attributes->fd[i].get(),
0601                                        i,
0602                                        attributes->offset[i],
0603                                        attributes->pitch[i],
0604                                        attributes->modifier >> 32,
0605                                        attributes->modifier & 0xffffffff);
0606     }
0607 
0608     wl_buffer *buffer = zwp_linux_buffer_params_v1_create_immed(params, attributes->width, attributes->height, attributes->format, 0);
0609     zwp_linux_buffer_params_v1_destroy(params);
0610 
0611     return buffer;
0612 }
0613 
0614 static wl_buffer *importShmBuffer(WaylandDisplay *display, const ShmAttributes *attributes)
0615 {
0616     wl_shm_format format;
0617     switch (attributes->format) {
0618     case DRM_FORMAT_ARGB8888:
0619         format = WL_SHM_FORMAT_ARGB8888;
0620         break;
0621     case DRM_FORMAT_XRGB8888:
0622         format = WL_SHM_FORMAT_XRGB8888;
0623         break;
0624     default:
0625         format = static_cast<wl_shm_format>(attributes->format);
0626         break;
0627     }
0628 
0629     wl_shm_pool *pool = wl_shm_create_pool(display->shm(), attributes->fd.get(), attributes->size.height() * attributes->stride);
0630     wl_buffer *buffer = wl_shm_pool_create_buffer(pool,
0631                                                   attributes->offset,
0632                                                   attributes->size.width(),
0633                                                   attributes->size.height(),
0634                                                   attributes->stride,
0635                                                   format);
0636     wl_shm_pool_destroy(pool);
0637 
0638     return buffer;
0639 }
0640 
0641 wl_buffer *WaylandBackend::importBuffer(GraphicsBuffer *graphicsBuffer)
0642 {
0643     auto &buffer = m_buffers[graphicsBuffer];
0644     if (!buffer) {
0645         wl_buffer *handle = nullptr;
0646         if (const DmaBufAttributes *attributes = graphicsBuffer->dmabufAttributes()) {
0647             handle = importDmaBufBuffer(m_display.get(), attributes);
0648         } else if (const ShmAttributes *attributes = graphicsBuffer->shmAttributes()) {
0649             handle = importShmBuffer(m_display.get(), attributes);
0650         } else {
0651             qCWarning(KWIN_WAYLAND_BACKEND) << graphicsBuffer << "has unknown type";
0652             return nullptr;
0653         }
0654 
0655         buffer = std::make_unique<WaylandBuffer>(handle, graphicsBuffer);
0656         connect(buffer.get(), &WaylandBuffer::defunct, this, [this, graphicsBuffer]() {
0657             m_buffers.erase(graphicsBuffer);
0658         });
0659 
0660         static const wl_buffer_listener listener = {
0661             .release = [](void *userData, wl_buffer *buffer) {
0662                 WaylandBuffer *slot = static_cast<WaylandBuffer *>(userData);
0663                 slot->unlock();
0664             },
0665         };
0666         wl_buffer_add_listener(handle, &listener, buffer.get());
0667     }
0668 
0669     buffer->lock();
0670     return buffer->handle();
0671 }
0672 
0673 void WaylandBackend::setEglDisplay(std::unique_ptr<EglDisplay> &&display)
0674 {
0675     m_eglDisplay = std::move(display);
0676 }
0677 
0678 EglDisplay *WaylandBackend::sceneEglDisplayObject() const
0679 {
0680     return m_eglDisplay.get();
0681 }
0682 
0683 WaylandBuffer::WaylandBuffer(wl_buffer *handle, GraphicsBuffer *graphicsBuffer)
0684     : m_graphicsBuffer(graphicsBuffer)
0685     , m_handle(handle)
0686 {
0687     connect(graphicsBuffer, &GraphicsBuffer::destroyed, this, &WaylandBuffer::defunct);
0688 }
0689 
0690 WaylandBuffer::~WaylandBuffer()
0691 {
0692     m_graphicsBuffer->disconnect(this);
0693     if (m_locked) {
0694         m_graphicsBuffer->unref();
0695     }
0696     wl_buffer_destroy(m_handle);
0697 }
0698 
0699 wl_buffer *WaylandBuffer::handle() const
0700 {
0701     return m_handle;
0702 }
0703 
0704 void WaylandBuffer::lock()
0705 {
0706     if (!m_locked) {
0707         m_locked = true;
0708         m_graphicsBuffer->ref();
0709     }
0710 }
0711 
0712 void WaylandBuffer::unlock()
0713 {
0714     if (m_locked) {
0715         m_locked = false;
0716         m_graphicsBuffer->unref();
0717     }
0718 }
0719 }
0720 
0721 } // KWin
0722 
0723 #include "moc_wayland_backend.cpp"