make software cursors work per output

This commit is contained in:
Xaver Hugl 2021-12-25 18:12:12 +01:00
parent 8a2f64fbe1
commit 6a99bfd2f4
34 changed files with 165 additions and 388 deletions

View file

@ -1736,27 +1736,27 @@ void PointerInputTest::testMoveCursor()
void PointerInputTest::testHideShowCursor()
{
QCOMPARE(kwinApp()->platform()->isCursorHidden(), false);
kwinApp()->platform()->hideCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
kwinApp()->platform()->showCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), false);
QCOMPARE(Cursors::self()->isCursorHidden(), false);
Cursors::self()->hideCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), true);
Cursors::self()->showCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), false);
kwinApp()->platform()->hideCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
kwinApp()->platform()->hideCursor();
kwinApp()->platform()->hideCursor();
kwinApp()->platform()->hideCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
Cursors::self()->hideCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), true);
Cursors::self()->hideCursor();
Cursors::self()->hideCursor();
Cursors::self()->hideCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), true);
kwinApp()->platform()->showCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
kwinApp()->platform()->showCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
kwinApp()->platform()->showCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
kwinApp()->platform()->showCursor();
QCOMPARE(kwinApp()->platform()->isCursorHidden(), false);
Cursors::self()->showCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), true);
Cursors::self()->showCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), true);
Cursors::self()->showCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), true);
Cursors::self()->showCursor();
QCOMPARE(Cursors::self()->isCursorHidden(), false);
}
void PointerInputTest::testDefaultInputRegion()

View file

@ -122,26 +122,26 @@ AbstractClient *TouchInputTest::showWindow(bool decorated)
void TouchInputTest::testTouchHidesCursor()
{
QCOMPARE(kwinApp()->platform()->isCursorHidden(), false);
QCOMPARE(Cursors::self()->isCursorHidden(), false);
quint32 timestamp = 1;
kwinApp()->platform()->touchDown(1, QPointF(125, 125), timestamp++);
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
QCOMPARE(Cursors::self()->isCursorHidden(), true);
kwinApp()->platform()->touchDown(2, QPointF(130, 125), timestamp++);
kwinApp()->platform()->touchUp(2, timestamp++);
kwinApp()->platform()->touchUp(1, timestamp++);
// now a mouse event should show the cursor again
kwinApp()->platform()->pointerMotion(QPointF(0, 0), timestamp++);
QCOMPARE(kwinApp()->platform()->isCursorHidden(), false);
QCOMPARE(Cursors::self()->isCursorHidden(), false);
// touch should hide again
kwinApp()->platform()->touchDown(1, QPointF(125, 125), timestamp++);
kwinApp()->platform()->touchUp(1, timestamp++);
QCOMPARE(kwinApp()->platform()->isCursorHidden(), true);
QCOMPARE(Cursors::self()->isCursorHidden(), true);
// wheel should also show
kwinApp()->platform()->pointerAxisVertical(1.0, timestamp++);
QCOMPARE(kwinApp()->platform()->isCursorHidden(), false);
QCOMPARE(Cursors::self()->isCursorHidden(), false);
}
void TouchInputTest::testMultipleTouchPoints_data()

View file

@ -166,4 +166,9 @@ std::chrono::milliseconds AbstractOutput::dimAnimationTime()
return std::chrono::milliseconds (KSharedConfig::openConfig()->group("Effect-Kscreen").readEntry("Duration", 250));
}
bool AbstractOutput::usesSoftwareCursor() const
{
return true;
}
} // namespace KWin

View file

@ -213,6 +213,8 @@ public:
Q_ENUM(Transform)
virtual Transform transform() const { return Transform::Normal; }
virtual bool usesSoftwareCursor() const;
Q_SIGNALS:
/**
* This signal is emitted when the geometry of this output has changed.

View file

@ -20,26 +20,6 @@ DrmAbstractOutput::DrmAbstractOutput(DrmGpu *gpu)
{
}
bool DrmAbstractOutput::showCursor()
{
return true;
}
bool DrmAbstractOutput::hideCursor()
{
return true;
}
bool DrmAbstractOutput::updateCursor()
{
return true;
}
bool DrmAbstractOutput::moveCursor()
{
return true;
}
DrmGpu *DrmAbstractOutput::gpu() const
{
return m_gpu;

View file

@ -22,11 +22,6 @@ class DrmAbstractOutput : public AbstractWaylandOutput
{
Q_OBJECT
public:
virtual bool showCursor();
virtual bool hideCursor();
virtual bool updateCursor();
virtual bool moveCursor();
virtual bool present(const QSharedPointer<DrmBuffer> &buffer, QRegion damagedRegion) = 0;
virtual bool needsSoftwareTransformation() const = 0;

View file

@ -158,7 +158,6 @@ void DrmBackend::reactivate()
// While the session had been inactive, an output could have been added or
// removed, we need to re-scan outputs.
updateOutputs();
updateCursor();
Q_EMIT activeChanged();
}
@ -210,8 +209,6 @@ bool DrmBackend::initialize()
return false;
}
initCursor();
// setup udevMonitor
if (m_udevMonitor) {
m_udevMonitor->filterSubsystemDevType("drm");
@ -240,7 +237,6 @@ void DrmBackend::handleUdevEvent()
qCDebug(KWIN_DRM) << "New gpu found:" << device->devNode();
if (addGpu(device->devNode())) {
updateOutputs();
updateCursor();
}
} else if (device->action() == QStringLiteral("remove")) {
DrmGpu *gpu = findGpu(device->devNum());
@ -255,7 +251,6 @@ void DrmBackend::handleUdevEvent()
m_gpus.removeOne(gpu);
delete gpu;
updateOutputs();
updateCursor();
}
}
} else if (device->action() == QStringLiteral("change")) {
@ -266,7 +261,6 @@ void DrmBackend::handleUdevEvent()
if (gpu) {
qCDebug(KWIN_DRM) << "Received change event for monitored drm device" << gpu->devNode();
updateOutputs();
updateCursor();
}
}
}
@ -517,85 +511,6 @@ void DrmBackend::enableOutput(DrmAbstractOutput *output, bool enable)
}
}
void DrmBackend::initCursor()
{
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &DrmBackend::updateCursor);
connect(Cursors::self(), &Cursors::positionChanged, this, &DrmBackend::moveCursor);
}
void DrmBackend::updateCursor()
{
if (isSoftwareCursorForced() || isCursorHidden()) {
return;
}
auto cursor = Cursors::self()->currentCursor();
if (cursor->image().isNull()) {
doHideCursor();
return;
}
bool success = true;
for (DrmAbstractOutput *output : qAsConst(m_outputs)) {
success = output->updateCursor();
if (!success) {
qCDebug(KWIN_DRM) << "Failed to update cursor on output" << output->name();
break;
}
success = output->showCursor();
if (!success) {
qCDebug(KWIN_DRM) << "Failed to show cursor on output" << output->name();
break;
}
success = output->moveCursor();
if (!success) {
qCDebug(KWIN_DRM) << "Failed to move cursor on output" << output->name();
break;
}
}
setSoftwareCursor(!success);
}
void DrmBackend::doShowCursor()
{
if (usesSoftwareCursor()) {
return;
}
updateCursor();
}
void DrmBackend::doHideCursor()
{
if (usesSoftwareCursor()) {
return;
}
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
(*it)->hideCursor();
}
}
void DrmBackend::doSetSoftwareCursor()
{
if (isCursorHidden() || !usesSoftwareCursor()) {
return;
}
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
(*it)->hideCursor();
}
}
void DrmBackend::moveCursor()
{
if (isCursorHidden() || usesSoftwareCursor()) {
return;
}
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
(*it)->moveCursor();
}
}
InputBackend *DrmBackend::createInputBackend()
{
return new LibinputBackend();
@ -723,7 +638,6 @@ bool DrmBackend::applyOutputChanges(const WaylandOutputConfig &config)
output->applyChanges(config);
}
};
updateCursor();
if (Compositor::compositing()) {
Compositor::self()->scene()->addRepaintFull();
}

View file

@ -76,9 +76,6 @@ Q_SIGNALS:
void gpuAdded(DrmGpu *gpu);
protected:
void doHideCursor() override;
void doShowCursor() override;
void doSetSoftwareCursor() override;
bool applyOutputChanges(const WaylandOutputConfig &config) override;
private:
@ -89,9 +86,6 @@ private:
void reactivate();
void deactivate();
void updateOutputs();
void updateCursor();
void moveCursor();
void initCursor();
void readOutputsConfiguration(const QVector<DrmAbstractOutput*> &outputs);
void handleUdevEvent();
DrmGpu *addGpu(const QString &fileName);

View file

@ -25,6 +25,7 @@
#include "session.h"
#include "waylandoutputconfig.h"
#include "dumb_swapchain.h"
#include "cursor.h"
// Qt
#include <QMatrix4x4>
#include <QCryptographicHash>
@ -69,6 +70,9 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline)
connect(&m_turnOffTimer, &QTimer::timeout, this, [this] {
setDrmDpmsMode(DpmsMode::Off);
});
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &DrmOutput::updateCursor);
connect(Cursors::self(), &Cursors::positionChanged, this, &DrmOutput::moveCursor);
}
DrmOutput::~DrmOutput()
@ -76,23 +80,6 @@ DrmOutput::~DrmOutput()
m_pipeline->setOutput(nullptr);
}
bool DrmOutput::hideCursor()
{
if (!isEnabled() || !m_connector->isConnected()) {
return true;
}
return m_pipeline->setCursor(nullptr);
}
bool DrmOutput::showCursor()
{
if (!isEnabled() || !m_connector->isConnected()) {
return true;
}
const Cursor * const cursor = Cursors::self()->currentCursor();
return m_pipeline->setCursor(m_cursor->currentBuffer(), logicalToNativeMatrix(cursor->rect(), scale(), transform()).map(cursor->hotspot()));
}
static bool isCursorSpriteCompatible(const QImage *buffer, const QImage *sprite)
{
// Note that we need compare the rects in the device independent pixels because the
@ -103,23 +90,24 @@ static bool isCursorSpriteCompatible(const QImage *buffer, const QImage *sprite)
return bufferRect.contains(spriteRect);
}
bool DrmOutput::updateCursor()
void DrmOutput::updateCursor()
{
if (!isEnabled() || !m_connector->isConnected()) {
return true;
return;
}
const Cursor *cursor = Cursors::self()->currentCursor();
if (!cursor) {
hideCursor();
return true;
m_pipeline->setCursor(nullptr);
return;
}
const QImage cursorImage = cursor->image();
if (cursorImage.isNull()) {
hideCursor();
return true;
m_pipeline->setCursor(nullptr);
return;
}
if (m_cursor && m_cursor->isEmpty()) {
return false;
m_pipeline->setCursor(nullptr);
return;
}
const auto plane = m_pipeline->pending.crtc->cursorPlane();
if (!m_cursor || (plane && !plane->formats()[m_cursor->drmFormat()].contains(DRM_FORMAT_MOD_LINEAR))) {
@ -135,14 +123,13 @@ bool DrmOutput::updateCursor()
break;
}
}
if (!m_cursor || m_cursor->isEmpty()) {
return false;
}
} else {
m_cursor = QSharedPointer<DumbSwapchain>::create(m_gpu, m_gpu->cursorSize(), DRM_FORMAT_XRGB8888, QImage::Format::Format_ARGB32_Premultiplied);
if (m_cursor->isEmpty()) {
return false;
}
}
if (!m_cursor || m_cursor->isEmpty()) {
m_pipeline->setCursor(nullptr);
m_setCursorSuccessful = false;
return;
}
}
m_cursor->releaseBuffer(m_cursor->currentBuffer());
@ -151,7 +138,9 @@ bool DrmOutput::updateCursor()
c->setDevicePixelRatio(scale());
if (!isCursorSpriteCompatible(c, &cursorImage)) {
// If the cursor image is too big, fall back to rendering the software cursor.
return false;
m_pipeline->setCursor(nullptr);
m_setCursorSuccessful = false;
return;
}
c->fill(Qt::transparent);
QPainter p;
@ -160,18 +149,22 @@ bool DrmOutput::updateCursor()
p.setRenderHint(QPainter::SmoothPixmapTransform);
p.drawImage(QPoint(0, 0), cursorImage);
p.end();
return m_pipeline->setCursor(m_cursor->currentBuffer(), logicalToNativeMatrix(cursor->rect(), scale(), transform()).map(cursor->hotspot()));
m_setCursorSuccessful = m_pipeline->setCursor(m_cursor->currentBuffer(), logicalToNativeMatrix(cursor->rect(), scale(), transform()).map(cursor->hotspot()));
moveCursor();
}
bool DrmOutput::moveCursor()
void DrmOutput::moveCursor()
{
if (!isEnabled() || !m_connector->isConnected()) {
return true;
if (!m_setCursorSuccessful) {
return;
}
Cursor *cursor = Cursors::self()->currentCursor();
const QMatrix4x4 monitorMatrix = logicalToNativeMatrix(geometry(), scale(), transform());
const QMatrix4x4 hotspotMatrix = logicalToNativeMatrix(cursor->rect(), scale(), transform());
return m_pipeline->moveCursor(monitorMatrix.map(cursor->pos()) - hotspotMatrix.map(cursor->hotspot()));
m_moveCursorSuccessful = m_pipeline->moveCursor(monitorMatrix.map(cursor->pos()) - hotspotMatrix.map(cursor->hotspot()));
if (!m_moveCursorSuccessful) {
m_pipeline->setCursor(nullptr);
}
}
QVector<AbstractWaylandOutput::Mode> DrmOutput::getModes() const
@ -491,4 +484,9 @@ int DrmOutput::maxBpc() const
return prop ? prop->maxValue() : 8;
}
bool DrmOutput::usesSoftwareCursor() const
{
return !m_setCursorSuccessful || !m_moveCursorSuccessful;
}
}

View file

@ -43,11 +43,6 @@ public:
DrmOutput(DrmPipeline *pipeline);
~DrmOutput() override;
bool showCursor() override;
bool hideCursor() override;
bool updateCursor() override;
bool moveCursor() override;
bool present(const QSharedPointer<DrmBuffer> &buffer, QRegion damagedRegion) override;
DrmConnector *connector() const;
@ -66,6 +61,7 @@ public:
void pageFlipped(std::chrono::nanoseconds timestamp);
void presentFailed();
bool usesSoftwareCursor() const override;
private:
void initOutputDevice();
@ -80,11 +76,16 @@ private:
int gammaRampSize() const override;
bool setGammaRamp(const GammaRamp &gamma) override;
void updateCursor();
void moveCursor();
DrmPipeline *m_pipeline;
DrmConnector *m_connector;
QSharedPointer<DumbSwapchain> m_cursor;
bool m_setCursorSuccessful = false;
bool m_moveCursorSuccessful = false;
QRect m_lastCursorGeometry;
QTimer m_turnOffTimer;
};

View file

@ -773,7 +773,7 @@ QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *output
bool EglGbmBackend::directScanoutAllowed(AbstractOutput *output) const
{
return !m_backend->usesSoftwareCursor() && !output->directScanoutInhibited();
return !output->usesSoftwareCursor() && !output->directScanoutInhibited();
}
bool EglGbmBackend::hasOutput(AbstractOutput *output) const

View file

@ -108,8 +108,6 @@ Session *FramebufferBackend::session() const
bool FramebufferBackend::initialize()
{
setSoftwareCursorForced(true);
QString framebufferDevice = deviceIdentifier();
if (framebufferDevice.isEmpty()) {
const auto fbs = Udev().listFramebuffers();

View file

@ -195,8 +195,6 @@ bool VirtualBackend::initialize()
Q_EMIT outputAdded(dummyOutput);
Q_EMIT outputEnabled(dummyOutput);
}
setSoftwareCursorForced(true);
setReady(true);
Q_EMIT screensQueried();

View file

@ -703,8 +703,6 @@ bool WaylandBackend::initialize()
return;
}
m_waylandCursor->installImage();
auto c = Cursors::self()->currentCursor();
Q_EMIT c->rendered(c->geometry());
}
);
connect(Cursors::self(), &Cursors::positionChanged, this,
@ -1051,6 +1049,7 @@ void WaylandBackend::removeVirtualOutput(AbstractOutput *output)
delete waylandOutput;
}
}
}
} // KWin

View file

@ -98,4 +98,9 @@ QSize X11Output::pixelSize() const
return geometry().size();
}
bool X11Output::usesSoftwareCursor() const
{
return false;
}
}

View file

@ -48,6 +48,7 @@ public:
void setPhysicalSize(const QSize &size);
QSize pixelSize() const override;
bool usesSoftwareCursor() const override;
private:
void setCrtc(xcb_randr_crtc_t crtc);

View file

@ -142,6 +142,8 @@ bool X11StandalonePlatform::initialize()
if (Xcb::Extensions::self()->isRandrAvailable()) {
m_randrEventFilter.reset(new XrandrEventFilter(this));
}
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &X11StandalonePlatform::updateCursor);
updateCursor();
return true;
}
@ -333,14 +335,13 @@ PlatformCursorImage X11StandalonePlatform::cursorImage() const
return PlatformCursorImage(qcursorimg.copy(), QPoint(cursor->xhot, cursor->yhot));
}
void X11StandalonePlatform::doHideCursor()
void X11StandalonePlatform::updateCursor()
{
xcb_xfixes_hide_cursor(kwinApp()->x11Connection(), kwinApp()->x11RootWindow());
}
void X11StandalonePlatform::doShowCursor()
{
xcb_xfixes_show_cursor(kwinApp()->x11Connection(), kwinApp()->x11RootWindow());
if (Cursors::self()->isCursorHidden()) {
xcb_xfixes_hide_cursor(kwinApp()->x11Connection(), kwinApp()->x11RootWindow());
} else {
xcb_xfixes_show_cursor(kwinApp()->x11Connection(), kwinApp()->x11RootWindow());
}
}
void X11StandalonePlatform::startInteractiveWindowSelection(std::function<void(KWin::Toplevel*)> callback, const QByteArray &cursorName)

View file

@ -68,10 +68,6 @@ public:
Outputs outputs() const override;
Outputs enabledOutputs() const override;
protected:
void doHideCursor() override;
void doShowCursor() override;
private:
/**
* Tests whether GLX is supported and returns @c true
@ -88,6 +84,7 @@ private:
template <typename T>
void doUpdateOutputs();
void updateRefreshRate();
void updateCursor();
Session *m_session;
XInputIntegration *m_xinputIntegration = nullptr;

View file

@ -180,4 +180,9 @@ void X11WindowedOutput::vblank(std::chrono::nanoseconds timestamp)
renderLoopPrivate->notifyFrameCompleted(timestamp);
}
bool X11WindowedOutput::usesSoftwareCursor() const
{
return false;
}
}

View file

@ -65,6 +65,8 @@ public:
*/
QPointF mapFromGlobal(const QPointF &pos) const;
bool usesSoftwareCursor() const override;
private:
void initXInputForWindow();
void vblank(std::chrono::nanoseconds timestamp);

View file

@ -649,9 +649,6 @@ void Compositor::composite(RenderLoop *renderLoop)
surface->frameRendered(frameTime.count());
}
}
if (!kwinApp()->platform()->isCursorHidden()) {
Cursors::self()->currentCursor()->markAsRendered();
}
}
}

View file

@ -15,6 +15,9 @@
#include "platform.h"
#include "utils.h"
#include "xcbutils.h"
#include "abstract_output.h"
#include "composite.h"
#include "scene.h"
// KDE
#include <KConfig>
#include <KConfigGroup>
@ -60,6 +63,27 @@ void Cursors::removeCursor(Cursor* cursor)
}
}
void Cursors::hideCursor()
{
m_cursorHideCounter++;
if (m_cursorHideCounter == 1) {
Q_EMIT currentCursorChanged(m_currentCursor);
}
}
void Cursors::showCursor()
{
m_cursorHideCounter--;
if (m_cursorHideCounter == 0) {
Q_EMIT currentCursorChanged(m_currentCursor);
}
}
bool Cursors::isCursorHidden() const
{
return m_cursorHideCounter > 0;
}
void Cursors::setCurrentCursor(Cursor* cursor)
{
if (m_currentCursor == cursor)
@ -68,11 +92,9 @@ void Cursors::setCurrentCursor(Cursor* cursor)
Q_ASSERT(m_cursors.contains(cursor) || !cursor);
if (m_currentCursor) {
disconnect(m_currentCursor, &Cursor::rendered, this, &Cursors::currentCursorRendered);
disconnect(m_currentCursor, &Cursor::cursorChanged, this, &Cursors::emitCurrentCursorChanged);
}
m_currentCursor = cursor;
connect(m_currentCursor, &Cursor::rendered, this, &Cursors::currentCursorRendered);
connect(m_currentCursor, &Cursor::cursorChanged, this, &Cursors::emitCurrentCursorChanged);
Q_EMIT currentCursorChanged(m_currentCursor);

View file

@ -166,9 +166,6 @@ public:
QRect rect() const;
void updateCursor(const QImage &image, const QPoint &hotspot);
void markAsRendered() {
Q_EMIT rendered(geometry());
}
Q_SIGNALS:
void posChanged(const QPoint& pos);
@ -186,8 +183,6 @@ Q_SIGNALS:
void cursorChanged();
void themeChanged();
void rendered(const QRect &geometry);
protected:
/**
* Performs the actual warping of the cursor.
@ -275,11 +270,14 @@ public:
return m_currentCursor;
}
void hideCursor();
void showCursor();
bool isCursorHidden() const;
static Cursors* self();
Q_SIGNALS:
void currentCursorChanged(Cursor* cursor);
void currentCursorRendered(const QRect &geometry);
void positionChanged(Cursor* cursor, const QPoint &position);
private:
@ -290,6 +288,7 @@ private:
Cursor* m_currentCursor = nullptr;
Cursor* m_mouse = nullptr;
QVector<Cursor*> m_cursors;
int m_cursorHideCounter = 0;
};
class InputConfig

View file

@ -1595,12 +1595,12 @@ PlatformCursorImage EffectsHandlerImpl::cursorImage() const
void EffectsHandlerImpl::hideCursor()
{
kwinApp()->platform()->hideCursor();
Cursors::self()->hideCursor();
}
void EffectsHandlerImpl::showCursor()
{
kwinApp()->platform()->showCursor();
Cursors::self()->showCursor();
}
void EffectsHandlerImpl::startInteractiveWindowSelection(std::function<void(KWin::EffectWindow*)> callback)

View file

@ -10,6 +10,7 @@
#include "main.h"
#include "platform.h"
#include "input_event.h"
#include "cursor.h"
namespace KWin
{
@ -49,7 +50,7 @@ void HideCursorSpy::showCursor()
return;
}
m_cursorHidden = false;
kwinApp()->platform()->showCursor();
Cursors::self()->showCursor();
}
void HideCursorSpy::hideCursor()
@ -58,7 +59,7 @@ void HideCursorSpy::hideCursor()
return;
}
m_cursorHidden = true;
kwinApp()->platform()->hideCursor();
Cursors::self()->hideCursor();
}
}

View file

@ -39,9 +39,6 @@ Platform::Platform(QObject *parent)
: QObject(parent)
, m_eglDisplay(EGL_NO_DISPLAY)
{
setSoftwareCursorForced(false);
connect(Cursors::self(), &Cursors::currentCursorRendered, this, &Platform::cursorRendered);
connect(this, &Platform::outputDisabled, this, [this] (AbstractOutput *output) {
if (m_primaryOutput == output) {
setPrimaryOutput(enabledOutputs().value(0, nullptr));
@ -64,30 +61,6 @@ PlatformCursorImage Platform::cursorImage() const
return PlatformCursorImage(cursor->image(), cursor->hotspot());
}
void Platform::hideCursor()
{
m_hideCursorCounter++;
if (m_hideCursorCounter == 1) {
doHideCursor();
}
}
void Platform::doHideCursor()
{
}
void Platform::showCursor()
{
m_hideCursorCounter--;
if (m_hideCursorCounter == 0) {
doShowCursor();
}
}
void Platform::doShowCursor()
{
}
InputBackend *Platform::createInputBackend()
{
return nullptr;
@ -236,55 +209,6 @@ AbstractOutput *Platform::outputAt(const QPoint &pos) const
return bestOutput;
}
bool Platform::usesSoftwareCursor() const
{
return m_softwareCursor;
}
void Platform::setSoftwareCursor(bool set)
{
if (m_softwareCursor == set) {
return;
}
m_softwareCursor = set;
doSetSoftwareCursor();
if (m_softwareCursor) {
connect(Cursors::self(), &Cursors::positionChanged, this, &Platform::triggerCursorRepaint);
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &Platform::triggerCursorRepaint);
} else {
disconnect(Cursors::self(), &Cursors::positionChanged, this, &Platform::triggerCursorRepaint);
disconnect(Cursors::self(), &Cursors::currentCursorChanged, this, &Platform::triggerCursorRepaint);
}
triggerCursorRepaint();
}
void Platform::doSetSoftwareCursor()
{
}
bool Platform::isSoftwareCursorForced() const
{
return m_softwareCursorForced;
}
void Platform::setSoftwareCursorForced(bool forced)
{
if (qEnvironmentVariableIsSet("KWIN_FORCE_SW_CURSOR")) {
forced = true;
}
if (m_softwareCursorForced == forced) {
return;
}
m_softwareCursorForced = forced;
if (m_softwareCursorForced) {
setSoftwareCursor(true);
} else {
// Do not unset the software cursor yet, the platform will choose the right
// moment when it can be done. There is still a chance that we must continue
// using the software cursor.
}
}
void Platform::triggerCursorRepaint()
{
if (Compositor::compositing()) {
@ -295,9 +219,7 @@ void Platform::triggerCursorRepaint()
void Platform::cursorRendered(const QRect &geometry)
{
if (m_softwareCursor) {
m_cursor.lastRenderedGeometry = geometry;
}
m_cursor.lastRenderedGeometry = geometry;
}
void Platform::keyboardKeyPressed(quint32 key, quint32 time)

View file

@ -219,26 +219,6 @@ public:
*/
virtual void setupActionForGlobalAccel(QAction *action);
/**
* Returns @c true if the software cursor is being used; otherwise returns @c false.
*/
bool usesSoftwareCursor() const;
/**
* Returns @c true if the software cursor is being forced; otherwise returns @c false.
*
* Note that the value returned by this function not always matches usesSoftwareCursor().
* If this function returns @c true, then it is guaranteed that the compositor will
* use the software cursor. However, this doesn't apply vice versa.
*
* If the compositor uses a software cursor, this function may return @c false. This
* is typically the case if the current cursor image can't be displayed using hardware
* cursors, for example due to buffer size limitations, etc.
*
* @see usesSoftwareCursor()
*/
bool isSoftwareCursorForced() const;
/**
* Returns a PlatformCursorImage. By default this is created by softwareCursor and
* softwareCursorHotspot. An implementing subclass can use this to provide a better
@ -250,33 +230,6 @@ public:
*/
virtual PlatformCursorImage cursorImage() const;
/**
* The Platform cursor image should be hidden.
* @see showCursor
* @see doHideCursor
* @see isCursorHidden
* @since 5.9
*/
void hideCursor();
/**
* The Platform cursor image should be shown again.
* @see hideCursor
* @see doShowCursor
* @see isCursorHidden
* @since 5.9
*/
void showCursor();
/**
* Whether the cursor is currently hidden.
* @see showCursor
* @see hideCursor
* @since 5.9
*/
bool isCursorHidden() const {
return m_hideCursorCounter > 0;
}
bool isReady() const {
return m_ready;
}
@ -478,8 +431,6 @@ Q_SIGNALS:
protected:
explicit Platform(QObject *parent = nullptr);
void setSoftwareCursor(bool set);
void setSoftwareCursorForced(bool forced);
void repaint(const QRect &rect);
void setReady(bool ready);
void setPerScreenRenderingEnabled(bool enabled);
@ -503,35 +454,8 @@ protected:
m_supportsOutputChanges = true;
}
/**
* Actual platform specific way to hide the cursor.
* Sub-classes need to implement if they support hiding the cursor.
*
* This method is invoked by hideCursor if the cursor needs to be hidden.
* The default implementation does nothing.
*
* @see doShowCursor
* @see hideCursor
* @see showCursor
*/
virtual void doHideCursor();
/**
* Actual platform specific way to show the cursor.
* Sub-classes need to implement if they support showing the cursor.
*
* This method is invoked by showCursor if the cursor needs to be shown again.
*
* @see doShowCursor
* @see hideCursor
* @see showCursor
*/
virtual void doShowCursor();
virtual void doSetSoftwareCursor();
private:
void triggerCursorRepaint();
bool m_softwareCursor = false;
bool m_softwareCursorForced = false;
struct {
QRect lastRenderedGeometry;
} m_cursor;
@ -543,7 +467,6 @@ private:
qreal m_initialOutputScale = 1;
EGLDisplay m_eglDisplay;
EGLContext m_globalShareContext = EGL_NO_CONTEXT;
int m_hideCursorCounter = 0;
bool m_supportsGammaControl = false;
bool m_supportsOutputChanges = false;
bool m_isPerScreenRenderingEnabled = false;

View file

@ -121,13 +121,13 @@ void PointerInputRedirection::init()
InputDeviceHandler::init();
if (!input()->hasPointer()) {
kwinApp()->platform()->hideCursor();
Cursors::self()->hideCursor();
}
connect(input(), &InputRedirection::hasPointerChanged, this, [this]() {
connect(input(), &InputRedirection::hasPointerChanged, this, []() {
if (input()->hasPointer()) {
kwinApp()->platform()->showCursor();
Cursors::self()->showCursor();
} else {
kwinApp()->platform()->hideCursor();
Cursors::self()->hideCursor();
}
});
@ -138,8 +138,6 @@ void PointerInputRedirection::init()
});
Q_EMIT m_cursor->changed();
connect(Cursors::self()->mouse(), &Cursor::rendered, m_cursor, &CursorImage::markAsRendered);
connect(screens(), &Screens::changed, this, &PointerInputRedirection::updateAfterScreenChange);
if (waylandServer()->hasScreenLockerIntegration()) {
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this,

View file

@ -107,6 +107,23 @@ void Scene::initialize()
connect(workspace(), &Workspace::geometryChanged, this, [this]() {
setGeometry(workspace()->geometry());
});
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &Scene::addCursorRepaints);
connect(Cursors::self(), &Cursors::positionChanged, this, &Scene::addCursorRepaints);
}
void Scene::addCursorRepaints()
{
const auto outputs = kwinApp()->platform()->enabledOutputs();
QRegion repaintRegion = Cursors::self()->currentCursor()->geometry();
repaintRegion |= m_lastCursorGeometry;
for (const auto &output : outputs) {
auto intersection = repaintRegion.intersected(output->geometry());
if (!intersection.isEmpty() && output->usesSoftwareCursor()) {
addRepaint(intersection);
}
}
m_lastCursorGeometry = Cursors::self()->currentCursor()->geometry();
}
void Scene::addRepaintFull()

View file

@ -207,7 +207,7 @@ protected:
QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop,
const QMatrix4x4 &projection = QMatrix4x4());
// Render cursor texture in case hardware cursor is disabled/non-applicable
virtual void paintCursor(const QRegion &region) = 0;
virtual void paintCursor(AbstractOutput *output, const QRegion &region) = 0;
friend class EffectsHandlerImpl;
// called after all effects had their paintScreen() called
void finalPaintScreen(int mask, const QRegion &region, ScreenPaintData& data);
@ -261,12 +261,15 @@ protected:
QVector< Window* > stacking_order;
private:
void removeRepaints(AbstractOutput *output);
void addCursorRepaints();
std::chrono::milliseconds m_expectedPresentTimestamp = std::chrono::milliseconds::zero();
QHash< Toplevel*, Window* > m_windows;
QMap<AbstractOutput *, QRegion> m_repaints;
QRect m_geometry;
// how many times finalPaintScreen() has been called
int m_paintScreenCount = 0;
QRect m_lastCursorGeometry;
};
// The base class for windows representations in composite backends

View file

@ -151,14 +151,14 @@ void SceneOpenGL::handleGraphicsReset(GLenum status)
* Render cursor texture in case hardware cursor is disabled.
* Useful for screen recording apps or backends that can't do planes.
*/
void SceneOpenGL::paintCursor(const QRegion &rendered)
void SceneOpenGL::paintCursor(AbstractOutput *output, const QRegion &rendered)
{
Cursor* cursor = Cursors::self()->currentCursor();
// don't paint if we use hardware cursor or the cursor is hidden
if (!kwinApp()->platform()->usesSoftwareCursor() ||
kwinApp()->platform()->isCursorHidden() ||
cursor->image().isNull()) {
if (!output || !output->usesSoftwareCursor()
|| Cursors::self()->isCursorHidden()
|| cursor->image().isNull()) {
return;
}
@ -316,7 +316,7 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi
paintScreen(damage.intersected(geo), repaint, &update, &valid,
renderLoop, projectionMatrix()); // call generic implementation
paintCursor(valid);
paintCursor(output, valid);
if (!GLPlatform::instance()->isGLES() && !output) {
const QRegion displayRegion(geometry());

View file

@ -71,7 +71,7 @@ protected:
void paintGenericScreen(int mask, const ScreenPaintData &data) override;
Scene::Window *createWindow(Toplevel *t) override;
void finalDrawWindow(EffectWindowImpl* w, int mask, const QRegion &region, WindowPaintData& data) override;
void paintCursor(const QRegion &region) override;
void paintCursor(AbstractOutput *output, const QRegion &region) override;
private:
void doPaintBackground(const QVector< float >& vertices);

View file

@ -87,7 +87,7 @@ void SceneQPainter::paint(AbstractOutput *output, const QRegion &damage, const Q
QRegion updateRegion, validRegion;
paintScreen(damage.intersected(geometry), repaint, &updateRegion, &validRegion, renderLoop);
paintCursor(updateRegion);
paintCursor(output, updateRegion);
m_painter->end();
renderLoop->endFrame();
@ -105,9 +105,9 @@ void SceneQPainter::paintBackground(const QRegion &region)
}
}
void SceneQPainter::paintCursor(const QRegion &rendered)
void SceneQPainter::paintCursor(AbstractOutput *output, const QRegion &rendered)
{
if (!kwinApp()->platform()->usesSoftwareCursor()) {
if (!output || output->usesSoftwareCursor() || Cursors::self()->isCursorHidden()) {
return;
}

View file

@ -49,7 +49,7 @@ public:
protected:
void paintBackground(const QRegion &region) override;
Scene::Window *createWindow(Toplevel *toplevel) override;
void paintCursor(const QRegion &region) override;
void paintCursor(AbstractOutput *output, const QRegion &region) override;
void paintOffscreenQuickView(OffscreenQuickView *w) override;
private: