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.
This commit is contained in:
parent
6e0012a3c9
commit
35a99ec9ad
13 changed files with 143 additions and 118 deletions
|
@ -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<DrmOutput *> &outputs)
|
||||
|
|
|
@ -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<EglGbmBackend *>(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<std::shared_ptr<OutputMode>> 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_ptr<ColorTransformation
|
|||
void DrmOutput::renderCursorOpengl(const RenderTarget &renderTarget, const QSize &cursorSize)
|
||||
{
|
||||
auto allocateTexture = [this]() {
|
||||
const QImage img = Cursors::self()->currentCursor()->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<GLTexture>(m_cursor.image);
|
||||
m_cursor.texture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
m_cursor.cacheKey = m_cursor.image.cacheKey();
|
||||
}
|
||||
m_cursorTexture = std::make_unique<GLTexture>(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<QImage *>(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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<uint32_t> &objectList);
|
||||
|
@ -75,10 +74,17 @@ private:
|
|||
|
||||
bool m_setCursorSuccessful = false;
|
||||
bool m_moveCursorSuccessful = false;
|
||||
bool m_cursorTextureDirty = true;
|
||||
std::unique_ptr<GLTexture> m_cursorTexture;
|
||||
QTimer m_turnOffTimer;
|
||||
DrmLease *m_lease = nullptr;
|
||||
|
||||
struct {
|
||||
QImage image;
|
||||
QPoint hotspot;
|
||||
QPoint position;
|
||||
|
||||
std::unique_ptr<GLTexture> texture;
|
||||
qint64 cacheKey = 0;
|
||||
} m_cursor;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <errno.h>
|
||||
|
||||
#include "core/session.h"
|
||||
#include "cursor.h"
|
||||
#include "drm_backend.h"
|
||||
#include "drm_buffer.h"
|
||||
#include "drm_buffer_gbm.h"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "core/output.h"
|
||||
|
||||
#include <KWayland/Client/buffer.h>
|
||||
#include <KWayland/Client/xdgshell.h>
|
||||
|
||||
#include <QObject>
|
||||
|
@ -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<KWayland::Client::Surface> 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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,8 +34,6 @@ public:
|
|||
|
||||
void updateEnabled(bool enabled);
|
||||
|
||||
bool usesSoftwareCursor() const override;
|
||||
|
||||
RenderLoop *renderLoop() const override;
|
||||
void setRenderLoop(RenderLoop *loop);
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <config-kwin.h>
|
||||
|
||||
#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<X11WindowedCursor>(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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<ColorTransformation> &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.
|
||||
|
|
Loading…
Reference in a new issue