From 35a99ec9ad063e5b2fbdfa751884c54af9bf6351 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 2 Dec 2022 23:17:40 +0200 Subject: [PATCH] Add explicit output cursor manipulation api Currently, output backends track the cursor behind the scenes. This results in some amount of code duplication, for example the handling of hidden cursors, every backend handles in its own unique way, some don't do it correctly. Another issue is that output backend interact with other components behind the back. This can be a problem for tasks such as backing the cursor with an output layer. This change introduces explicit output cursor manipulation APIs in the Output class. There's a good chance that it's going to be revised more in the future as part of streamlining output layer manipulation apis. With the proposed changes, the workspace would need to call Output::setCursor() or Output::moveCursor() to set/unset or move the cursor, respectively. --- src/backends/drm/drm_gpu.cpp | 3 - src/backends/drm/drm_output.cpp | 118 ++++++++---------- src/backends/drm/drm_output.h | 16 ++- src/backends/drm/drm_pipeline.cpp | 1 - src/backends/wayland/wayland_output.cpp | 46 ++++--- src/backends/wayland/wayland_output.h | 10 +- .../x11/standalone/x11_standalone_output.cpp | 5 - .../x11/standalone/x11_standalone_output.h | 2 - .../x11/windowed/x11_windowed_output.cpp | 16 +-- .../x11/windowed/x11_windowed_output.h | 3 +- src/composite.cpp | 21 +++- src/core/output.cpp | 15 ++- src/core/output.h | 5 +- 13 files changed, 143 insertions(+), 118 deletions(-) diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index 5e83d36b36..9a5916ad0d 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -780,9 +780,6 @@ void DrmGpu::recreateSurfaces() for (const auto &output : std::as_const(m_virtualOutputs)) { output->recreateSurface(); } - for (const auto &output : std::as_const(m_drmOutputs)) { - output->updateCursor(); - } } DrmLease::DrmLease(DrmGpu *gpu, FileDescriptor &&fd, uint32_t lesseeId, const QVector &outputs) diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 9801e538cc..14918d828f 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -18,7 +18,6 @@ #include "core/renderloop.h" #include "core/renderloop_p.h" #include "core/session.h" -#include "cursor.h" #include "drm_dumb_buffer.h" #include "drm_dumb_swapchain.h" #include "drm_egl_backend.h" @@ -95,12 +94,6 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline) connect(&m_turnOffTimer, &QTimer::timeout, this, [this] { setDrmDpmsMode(DpmsMode::Off); }); - - if (!conn->isNonDesktop()) { - connect(Cursors::self(), &Cursors::currentCursorChanged, this, &DrmOutput::updateCursor); - connect(Cursors::self(), &Cursors::hiddenChanged, this, &DrmOutput::updateCursor); - connect(Cursors::self(), &Cursors::positionChanged, this, &DrmOutput::moveCursor); - } } DrmOutput::~DrmOutput() @@ -139,35 +132,38 @@ DrmLease *DrmOutput::lease() const return m_lease; } -void DrmOutput::updateCursor() +bool DrmOutput::setCursor(const QImage &image, const QPoint &hotspot) { static bool valid; static const bool forceSoftwareCursor = qEnvironmentVariableIntValue("KWIN_FORCE_SW_CURSOR", &valid) == 1 && valid; // hardware cursors are broken with the NVidia proprietary driver if (forceSoftwareCursor || (!valid && m_gpu->isNVidia())) { m_setCursorSuccessful = false; - return; + return false; } const auto layer = m_pipeline->cursorLayer(); if (!m_pipeline->crtc() || !layer) { - return; + return false; } - const Cursor *cursor = Cursors::self()->currentCursor(); - if (!cursor || cursor->image().isNull() || Cursors::self()->isCursorHidden()) { + m_cursor.image = image; + m_cursor.hotspot = hotspot; + if (m_cursor.image.isNull()) { if (layer->isVisible()) { layer->setVisible(false); m_pipeline->setCursor(); } - return; + return true; } bool rendered = false; - const QMatrix4x4 monitorMatrix = logicalToNativeMatrix(geometry(), scale(), transform()); - const QRect cursorRect = monitorMatrix.mapRect(cursor->geometry()); - if (cursorRect.width() <= m_gpu->cursorSize().width() && cursorRect.height() <= m_gpu->cursorSize().height()) { + const QMatrix4x4 monitorMatrix = logicalToNativeMatrix(rect(), scale(), transform()); + const QSize cursorSize = m_cursor.image.size() / m_cursor.image.devicePixelRatio(); + const QRect cursorRect = QRect(m_cursor.position, cursorSize); + const QRect nativeCursorRect = monitorMatrix.mapRect(cursorRect); + if (nativeCursorRect.width() <= m_gpu->cursorSize().width() && nativeCursorRect.height() <= m_gpu->cursorSize().height()) { if (const auto beginInfo = layer->beginFrame()) { const auto &[renderTarget, repaint] = beginInfo.value(); if (dynamic_cast(m_gpu->platform()->renderBackend())) { - renderCursorOpengl(renderTarget, cursor->geometry().size() * scale()); + renderCursorOpengl(renderTarget, cursorSize * scale()); } else { renderCursorQPainter(renderTarget); } @@ -180,43 +176,49 @@ void DrmOutput::updateCursor() m_pipeline->setCursor(); } m_setCursorSuccessful = false; - return; + return false; } - const QSize surfaceSize = m_gpu->cursorSize() / scale(); - const QRect layerRect = monitorMatrix.mapRect(QRect(cursor->geometry().topLeft(), surfaceSize)); - layer->setPosition(layerRect.topLeft()); - layer->setVisible(cursor->geometry().intersects(geometry())); + const QSize layerSize = m_gpu->cursorSize() / scale(); + const QRect layerRect = monitorMatrix.mapRect(QRect(m_cursor.position, layerSize)); + layer->setVisible(cursorRect.intersects(rect())); if (layer->isVisible()) { - m_setCursorSuccessful = m_pipeline->setCursor(logicalToNativeMatrix(QRect(QPoint(), layerRect.size()), scale(), transform()).map(cursor->hotspot())); + m_setCursorSuccessful = m_pipeline->setCursor(logicalToNativeMatrix(QRect(QPoint(), layerRect.size()), scale(), transform()).map(m_cursor.hotspot)); layer->setVisible(m_setCursorSuccessful); } + return m_setCursorSuccessful; } -void DrmOutput::moveCursor() +bool DrmOutput::moveCursor(const QPoint &position) { if (!m_setCursorSuccessful || !m_pipeline->crtc()) { - return; + return false; } - const auto layer = m_pipeline->cursorLayer(); - Cursor *cursor = Cursors::self()->currentCursor(); - if (!cursor || cursor->image().isNull() || Cursors::self()->isCursorHidden() || !cursor->geometry().intersects(geometry())) { + m_cursor.position = position; + + const QSize cursorSize = m_cursor.image.size() / m_cursor.image.devicePixelRatio(); + const QRect cursorRect = QRect(m_cursor.position, cursorSize); + + if (m_cursor.image.isNull() || !cursorRect.intersects(rect())) { + const auto layer = m_pipeline->cursorLayer(); if (layer->isVisible()) { layer->setVisible(false); m_pipeline->setCursor(); } - return; + return true; } - const QMatrix4x4 monitorMatrix = logicalToNativeMatrix(geometry(), scale(), transform()); - const QSize surfaceSize = m_gpu->cursorSize() / scale(); - const QRect cursorRect = monitorMatrix.mapRect(QRect(cursor->geometry().topLeft(), surfaceSize)); + const QMatrix4x4 monitorMatrix = logicalToNativeMatrix(rect(), scale(), transform()); + const QSize layerSize = m_gpu->cursorSize() / scale(); + const QRect layerRect = monitorMatrix.mapRect(QRect(m_cursor.position, layerSize)); + const auto layer = m_pipeline->cursorLayer(); layer->setVisible(true); - layer->setPosition(cursorRect.topLeft()); + layer->setPosition(layerRect.topLeft()); m_moveCursorSuccessful = m_pipeline->moveCursor(); layer->setVisible(m_moveCursorSuccessful); if (!m_moveCursorSuccessful) { m_pipeline->setCursor(); } + return m_moveCursorSuccessful; } QList> DrmOutput::getModes() const @@ -439,8 +441,6 @@ void DrmOutput::applyQueuedChanges(const OutputConfiguration &config) if (isEnabled() && dpmsMode() == DpmsMode::On) { m_gpu->platform()->turnOutputsOn(); } - - updateCursor(); } void DrmOutput::revertQueuedChanges() @@ -448,11 +448,6 @@ void DrmOutput::revertQueuedChanges() m_pipeline->revertPendingChanges(); } -bool DrmOutput::usesSoftwareCursor() const -{ - return !m_setCursorSuccessful || !m_moveCursorSuccessful; -} - DrmOutputLayer *DrmOutput::primaryLayer() const { return m_pipeline->primaryLayer(); @@ -472,28 +467,22 @@ void DrmOutput::setColorTransformation(const std::shared_ptrcurrentCursor()->image(); - if (img.isNull()) { - m_cursorTextureDirty = false; - return; + if (m_cursor.image.isNull()) { + m_cursor.texture.reset(); + m_cursor.cacheKey = 0; + } else { + m_cursor.texture = std::make_unique(m_cursor.image); + m_cursor.texture->setWrapMode(GL_CLAMP_TO_EDGE); + m_cursor.cacheKey = m_cursor.image.cacheKey(); } - m_cursorTexture = std::make_unique(img); - m_cursorTexture->setWrapMode(GL_CLAMP_TO_EDGE); - m_cursorTextureDirty = false; }; - if (!m_cursorTexture) { + if (!m_cursor.texture) { allocateTexture(); - - // handle shape update on case cursor image changed - connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() { - m_cursorTextureDirty = true; - }); - } else if (m_cursorTextureDirty) { - const QImage image = Cursors::self()->currentCursor()->image(); - if (image.size() == m_cursorTexture->size()) { - m_cursorTexture->update(image); - m_cursorTextureDirty = false; + } else if (m_cursor.cacheKey != m_cursor.image.cacheKey()) { + if (m_cursor.image.size() == m_cursor.texture->size()) { + m_cursor.texture->update(m_cursor.image); + m_cursor.cacheKey = m_cursor.image.cacheKey(); } else { allocateTexture(); } @@ -508,18 +497,17 @@ void DrmOutput::renderCursorOpengl(const RenderTarget &renderTarget, const QSize glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_cursorTexture->bind(); + m_cursor.texture->bind(); ShaderBinder binder(ShaderTrait::MapTexture); binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); - m_cursorTexture->render(QRect(0, 0, cursorSize.width(), cursorSize.height()), renderTarget.devicePixelRatio()); - m_cursorTexture->unbind(); + m_cursor.texture->render(QRect(0, 0, cursorSize.width(), cursorSize.height()), renderTarget.devicePixelRatio()); + m_cursor.texture->unbind(); glDisable(GL_BLEND); } void DrmOutput::renderCursorQPainter(const RenderTarget &renderTarget) { - const Cursor *cursor = Cursors::self()->currentCursor(); - const QImage cursorImage = cursor->image(); + const QRect cursorRect(QPoint(0, 0), m_cursor.image.size() / m_cursor.image.devicePixelRatio()); QImage *c = std::get(renderTarget.nativeHandle()); c->setDevicePixelRatio(scale()); @@ -527,9 +515,9 @@ void DrmOutput::renderCursorQPainter(const RenderTarget &renderTarget) QPainter p; p.begin(c); - p.setWorldTransform(logicalToNativeMatrix(cursor->rect(), 1, transform()).toTransform()); + p.setWorldTransform(logicalToNativeMatrix(cursorRect, 1, transform()).toTransform()); p.setRenderHint(QPainter::SmoothPixmapTransform); - p.drawImage(QPoint(0, 0), cursorImage); + p.drawImage(QPoint(0, 0), m_cursor.image); p.end(); } } diff --git a/src/backends/drm/drm_output.h b/src/backends/drm/drm_output.h index ffb6e16fbc..015368c0f8 100644 --- a/src/backends/drm/drm_output.h +++ b/src/backends/drm/drm_output.h @@ -50,9 +50,8 @@ public: void updateModes(); void updateDpmsMode(DpmsMode dpmsMode); - bool usesSoftwareCursor() const override; - void updateCursor(); - void moveCursor(); + bool setCursor(const QImage &image, const QPoint &hotspot) override; + bool moveCursor(const QPoint &position) override; DrmLease *lease() const; bool addLeaseObjects(QVector &objectList); @@ -75,10 +74,17 @@ private: bool m_setCursorSuccessful = false; bool m_moveCursorSuccessful = false; - bool m_cursorTextureDirty = true; - std::unique_ptr m_cursorTexture; QTimer m_turnOffTimer; DrmLease *m_lease = nullptr; + + struct { + QImage image; + QPoint hotspot; + QPoint position; + + std::unique_ptr texture; + qint64 cacheKey = 0; + } m_cursor; }; } diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 4ba9d0ff24..315370557c 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -12,7 +12,6 @@ #include #include "core/session.h" -#include "cursor.h" #include "drm_backend.h" #include "drm_buffer.h" #include "drm_buffer_gbm.h" diff --git a/src/backends/wayland/wayland_output.cpp b/src/backends/wayland/wayland_output.cpp index 30279a27ac..00ba77916f 100644 --- a/src/backends/wayland/wayland_output.cpp +++ b/src/backends/wayland/wayland_output.cpp @@ -8,7 +8,6 @@ */ #include "wayland_output.h" #include "core/renderloop_p.h" -#include "cursor.h" #include "wayland_backend.h" #include "wayland_display.h" #include "wayland_server.h" @@ -60,7 +59,7 @@ void WaylandCursor::enable() { if (!m_enabled) { m_enabled = true; - update(); + sync(); } } @@ -68,23 +67,29 @@ void WaylandCursor::disable() { if (m_enabled) { m_enabled = false; - update(); + sync(); } } -void WaylandCursor::update() +void WaylandCursor::update(KWayland::Client::Buffer::Ptr buffer, qreal scale, const QPoint &hotspot) { - const QImage image = Cursors::self()->currentCursor()->image(); - if (!m_enabled || Cursors::self()->isCursorHidden() || image.isNull()) { + m_buffer = buffer; + m_scale = scale; + m_hotspot = hotspot; + + sync(); +} + +void WaylandCursor::sync() +{ + if (!m_enabled) { m_surface->attachBuffer(KWayland::Client::Buffer::Ptr()); m_surface->commit(KWayland::Client::Surface::CommitFlag::None); - m_hotspot = QPoint(); } else { - m_surface->attachBuffer(m_backend->display()->shmPool()->createBuffer(image)); - m_surface->setScale(std::ceil(image.devicePixelRatio())); - m_surface->damageBuffer(image.rect()); + m_surface->attachBuffer(m_buffer); + m_surface->setScale(std::ceil(m_scale)); + m_surface->damageBuffer(QRect(0, 0, INT32_MAX, INT32_MAX)); m_surface->commit(KWayland::Client::Surface::CommitFlag::None); - m_hotspot = Cursors::self()->currentCursor()->hotspot(); } if (m_pointer) { @@ -128,10 +133,6 @@ WaylandOutput::WaylandOutput(const QString &name, WaylandBackend *backend) connect(m_xdgShellSurface.get(), &XdgShellSurface::closeRequested, qApp, &QCoreApplication::quit); connect(this, &WaylandOutput::enabledChanged, this, &WaylandOutput::updateWindowTitle); connect(this, &WaylandOutput::dpmsModeChanged, this, &WaylandOutput::updateWindowTitle); - - connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() { - m_cursor->update(); - }); } WaylandOutput::~WaylandOutput() @@ -161,9 +162,20 @@ RenderLoop *WaylandOutput::renderLoop() const return m_renderLoop.get(); } -bool WaylandOutput::usesSoftwareCursor() const +bool WaylandOutput::setCursor(const QImage &image, const QPoint &hotspot) { - return m_hasPointerLock; + KWayland::Client::Buffer::Ptr buffer; + if (!image.isNull()) { + buffer = m_backend->display()->shmPool()->createBuffer(image); + } + m_cursor->update(buffer, image.devicePixelRatio(), hotspot); + return !m_hasPointerLock; +} + +bool WaylandOutput::moveCursor(const QPoint &position) +{ + // The cursor position is controlled by the host compositor. + return !m_hasPointerLock; } void WaylandOutput::init(const QSize &pixelSize, qreal scale) diff --git a/src/backends/wayland/wayland_output.h b/src/backends/wayland/wayland_output.h index 107f7bf53f..12051b95e4 100644 --- a/src/backends/wayland/wayland_output.h +++ b/src/backends/wayland/wayland_output.h @@ -10,6 +10,7 @@ #include "core/output.h" +#include #include #include @@ -43,13 +44,17 @@ public: void enable(); void disable(); - void update(); + void update(KWayland::Client::Buffer::Ptr buffer, qreal scale, const QPoint &hotspot); private: + void sync(); + WaylandBackend *const m_backend; KWayland::Client::Pointer *m_pointer = nullptr; std::unique_ptr m_surface; + KWayland::Client::Buffer::Ptr m_buffer; QPoint m_hotspot; + qreal m_scale = 1; bool m_enabled = true; }; @@ -61,7 +66,8 @@ public: ~WaylandOutput() override; RenderLoop *renderLoop() const override; - bool usesSoftwareCursor() const override; + bool setCursor(const QImage &image, const QPoint &hotspot) override; + bool moveCursor(const QPoint &position) override; void init(const QSize &pixelSize, qreal scale); diff --git a/src/backends/x11/standalone/x11_standalone_output.cpp b/src/backends/x11/standalone/x11_standalone_output.cpp index 3f9ef9ecba..eca9d30562 100644 --- a/src/backends/x11/standalone/x11_standalone_output.cpp +++ b/src/backends/x11/standalone/x11_standalone_output.cpp @@ -58,11 +58,6 @@ void X11Output::setGammaRampSize(int size) m_gammaRampSize = size; } -bool X11Output::usesSoftwareCursor() const -{ - return false; -} - void X11Output::updateEnabled(bool enabled) { State next = m_state; diff --git a/src/backends/x11/standalone/x11_standalone_output.h b/src/backends/x11/standalone/x11_standalone_output.h index 8eaac7e3b3..9dc25a21f9 100644 --- a/src/backends/x11/standalone/x11_standalone_output.h +++ b/src/backends/x11/standalone/x11_standalone_output.h @@ -34,8 +34,6 @@ public: void updateEnabled(bool enabled); - bool usesSoftwareCursor() const override; - RenderLoop *renderLoop() const override; void setRenderLoop(RenderLoop *loop); diff --git a/src/backends/x11/windowed/x11_windowed_output.cpp b/src/backends/x11/windowed/x11_windowed_output.cpp index 1bf3a34536..5469d23458 100644 --- a/src/backends/x11/windowed/x11_windowed_output.cpp +++ b/src/backends/x11/windowed/x11_windowed_output.cpp @@ -12,7 +12,6 @@ #include #include "core/renderloop_p.h" -#include "cursor.h" #include "softwarevsyncmonitor.h" #include "x11_windowed_backend.h" @@ -198,10 +197,6 @@ void X11WindowedOutput::init(const QSize &pixelSize, qreal scale) addIcon(QSize(48, 48)); m_cursor = std::make_unique(this); - connect(Cursors::self(), &Cursors::currentCursorChanged, this, [this]() { - KWin::Cursor *c = KWin::Cursors::self()->currentCursor(); - m_cursor->update(c->image(), c->hotspot()); - }); xcb_map_window(m_backend->connection(), m_window); } @@ -263,9 +258,16 @@ void X11WindowedOutput::vblank(std::chrono::nanoseconds timestamp) renderLoopPrivate->notifyFrameCompleted(timestamp); } -bool X11WindowedOutput::usesSoftwareCursor() const +bool X11WindowedOutput::setCursor(const QImage &image, const QPoint &hotspot) { - return false; + m_cursor->update(image, hotspot); + return true; +} + +bool X11WindowedOutput::moveCursor(const QPoint &position) +{ + // The cursor position is controlled by the host compositor. + return true; } void X11WindowedOutput::updateEnabled(bool enabled) diff --git a/src/backends/x11/windowed/x11_windowed_output.h b/src/backends/x11/windowed/x11_windowed_output.h index 72d7c085fb..43fff8b556 100644 --- a/src/backends/x11/windowed/x11_windowed_output.h +++ b/src/backends/x11/windowed/x11_windowed_output.h @@ -78,7 +78,8 @@ public: */ QPointF mapFromGlobal(const QPointF &pos) const; - bool usesSoftwareCursor() const override; + bool setCursor(const QImage &image, const QPoint &hotspot) override; + bool moveCursor(const QPoint &position) override; QRegion exposedArea() const; void addExposedArea(const QRect &rect); diff --git a/src/composite.cpp b/src/composite.cpp index f4c04f61e8..42ec9fbcec 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -430,15 +430,30 @@ void Compositor::addOutput(Output *output) auto updateCursorLayer = [output, cursorLayer]() { const Cursor *cursor = Cursors::self()->currentCursor(); - cursorLayer->setVisible(cursor->isOnOutput(output) && output->usesSoftwareCursor()); - cursorLayer->setGeometry(output->mapFromGlobal(cursor->geometry())); + const QRect layerRect = output->mapFromGlobal(cursor->geometry()); + bool usesHardwareCursor = false; + if (!Cursors::self()->isCursorHidden()) { + usesHardwareCursor = output->setCursor(cursor->image(), cursor->hotspot()) && output->moveCursor(layerRect.topLeft()); + } else { + usesHardwareCursor = output->setCursor(QImage(), QPoint()); + } + cursorLayer->setVisible(cursor->isOnOutput(output) && !usesHardwareCursor); + cursorLayer->setGeometry(layerRect); + cursorLayer->addRepaintFull(); + }; + auto moveCursorLayer = [output, cursorLayer]() { + const Cursor *cursor = Cursors::self()->currentCursor(); + const QRect layerRect = output->mapFromGlobal(cursor->geometry()); + const bool usesHardwareCursor = output->moveCursor(layerRect.topLeft()); + cursorLayer->setVisible(cursor->isOnOutput(output) && !usesHardwareCursor); + cursorLayer->setGeometry(layerRect); cursorLayer->addRepaintFull(); }; updateCursorLayer(); connect(output, &Output::geometryChanged, cursorLayer, updateCursorLayer); connect(Cursors::self(), &Cursors::currentCursorChanged, cursorLayer, updateCursorLayer); connect(Cursors::self(), &Cursors::hiddenChanged, cursorLayer, updateCursorLayer); - connect(Cursors::self(), &Cursors::positionChanged, cursorLayer, updateCursorLayer); + connect(Cursors::self(), &Cursors::positionChanged, cursorLayer, moveCursorLayer); addSuperLayer(workspaceLayer); } diff --git a/src/core/output.cpp b/src/core/output.cpp index 63029a3fe5..37958429de 100644 --- a/src/core/output.cpp +++ b/src/core/output.cpp @@ -144,11 +144,6 @@ std::chrono::milliseconds Output::dimAnimationTime() return std::chrono::milliseconds(KSharedConfig::openConfig()->group("Effect-Kscreen").readEntry("Duration", 250)); } -bool Output::usesSoftwareCursor() const -{ - return true; -} - QRect Output::mapFromGlobal(const QRect &rect) const { return rect.translated(-geometry().topLeft()); @@ -421,4 +416,14 @@ Output::Transform Output::panelOrientation() const return m_information.panelOrientation; } +bool Output::setCursor(const QImage &image, const QPoint &hotspot) +{ + return false; +} + +bool Output::moveCursor(const QPoint &position) +{ + return false; +} + } // namespace KWin diff --git a/src/core/output.h b/src/core/output.h index cc45723eb2..9eae8b27f6 100644 --- a/src/core/output.h +++ b/src/core/output.h @@ -229,8 +229,6 @@ public: Q_ENUM(Transform) Transform transform() const; - virtual bool usesSoftwareCursor() const; - void applyChanges(const OutputConfiguration &config); SubPixel subPixel() const; @@ -262,6 +260,9 @@ public: virtual void setColorTransformation(const std::shared_ptr &transformation); + virtual bool setCursor(const QImage &image, const QPoint &hotspot); + virtual bool moveCursor(const QPoint &position); + Q_SIGNALS: /** * This signal is emitted when the geometry of this output has changed.