Drop Cursor::image()

Use CursorSource::image() instead.

Cursor caching in the ScreenCastStream has been changed so
QImage::cacheKey() is not being used. This is rather a preparation for
making kwin grab the contents of the cursor scene.
This commit is contained in:
Vlad Zahorodnii 2023-05-07 19:41:00 +03:00
parent af7c1db43b
commit 3d5b5844d0
6 changed files with 47 additions and 39 deletions

View file

@ -1090,7 +1090,7 @@ void PointerInputTest::testCursorImage()
input()->pointer()->warp(QPointF(800, 800));
auto p = input()->pointer();
// at the moment it should be the fallback cursor
const QImage fallbackCursor = cursor->image();
const QImage fallbackCursor = kwinApp()->cursorImage().image();
QVERIFY(!fallbackCursor.isNull());
// create a window
@ -1107,7 +1107,7 @@ void PointerInputTest::testCursorImage()
// move cursor to center of window, this should first set a null pointer, so we still show old cursor
input()->pointer()->warp(window->frameGeometry().center());
QCOMPARE(p->focus(), window);
QCOMPARE(cursor->image(), fallbackCursor);
QCOMPARE(kwinApp()->cursorImage().image(), fallbackCursor);
QVERIFY(enteredSpy.wait());
// create a cursor on the pointer
@ -1121,13 +1121,13 @@ void PointerInputTest::testCursorImage()
cursorSurface->commit();
pointer->setCursor(cursorSurface.get(), QPoint(5, 5));
QVERIFY(cursorRenderedSpy.wait());
QCOMPARE(cursor->image(), red);
QCOMPARE(kwinApp()->cursorImage().image(), red);
QCOMPARE(cursor->hotspot(), QPoint(5, 5));
// change hotspot
pointer->setCursor(cursorSurface.get(), QPoint(6, 6));
Test::flushWaylandConnection();
QTRY_COMPARE(cursor->hotspot(), QPoint(6, 6));
QCOMPARE(cursor->image(), red);
QCOMPARE(kwinApp()->cursorImage().image(), red);
// change the buffer
QImage blue = QImage(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
@ -1137,7 +1137,7 @@ void PointerInputTest::testCursorImage()
cursorSurface->damage(QRect(0, 0, 10, 10));
cursorSurface->commit();
QVERIFY(cursorRenderedSpy.wait());
QTRY_COMPARE(cursor->image(), blue);
QTRY_COMPARE(kwinApp()->cursorImage().image(), blue);
QCOMPARE(cursor->hotspot(), QPoint(6, 6));
// scaled cursor
@ -1150,19 +1150,19 @@ void PointerInputTest::testCursorImage()
cursorSurface->damage(QRect(0, 0, 20, 20));
cursorSurface->commit();
QVERIFY(cursorRenderedSpy.wait());
QTRY_COMPARE(cursor->image(), blueScaled);
QTRY_COMPARE(kwinApp()->cursorImage().image(), blueScaled);
QCOMPARE(cursor->hotspot(), QPoint(6, 6)); // surface-local (so not changed)
// hide the cursor
pointer->setCursor(nullptr);
Test::flushWaylandConnection();
QTRY_VERIFY(cursor->image().isNull());
QTRY_VERIFY(kwinApp()->cursorImage().image().isNull());
// move cursor somewhere else, should reset to fallback cursor
input()->pointer()->warp(window->frameGeometry().bottomLeft() + QPoint(20, 20));
QVERIFY(!p->focus());
QVERIFY(!cursor->image().isNull());
QCOMPARE(cursor->image(), fallbackCursor);
QVERIFY(!kwinApp()->cursorImage().image().isNull());
QCOMPARE(kwinApp()->cursorImage().image(), fallbackCursor);
}
class HelperEffect : public Effect
@ -1183,7 +1183,6 @@ void PointerInputTest::testEffectOverrideCursorImage()
// we need a pointer to get the enter event and set a cursor
auto pointer = m_seat->createPointer(m_seat);
auto cursor = Cursors::self()->mouse();
QVERIFY(pointer);
QVERIFY(pointer->isValid());
QSignalSpy enteredSpy(pointer, &KWayland::Client::Pointer::entered);
@ -1191,7 +1190,7 @@ void PointerInputTest::testEffectOverrideCursorImage()
// move cursor somewhere the new window won't open
input()->pointer()->warp(QPointF(800, 800));
// here we should have the fallback cursor
const QImage fallback = cursor->image();
const QImage fallback = kwinApp()->cursorImage().image();
QVERIFY(!fallback.isNull());
// now let's create a window
@ -1210,33 +1209,33 @@ void PointerInputTest::testEffectOverrideCursorImage()
input()->pointer()->warp(window->frameGeometry().center());
QVERIFY(enteredSpy.wait());
// cursor image should still be fallback
QCOMPARE(cursor->image(), fallback);
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
// now create an effect and set an override cursor
std::unique_ptr<HelperEffect> effect(new HelperEffect);
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
const QImage sizeAll = cursor->image();
const QImage sizeAll = kwinApp()->cursorImage().image();
QVERIFY(!sizeAll.isNull());
QVERIFY(sizeAll != fallback);
QVERIFY(leftSpy.wait());
// let's change to arrow cursor, this should be our fallback
effects->defineCursor(Qt::ArrowCursor);
QCOMPARE(cursor->image(), fallback);
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
// back to size all
effects->defineCursor(Qt::SizeAllCursor);
QCOMPARE(cursor->image(), sizeAll);
QCOMPARE(kwinApp()->cursorImage().image(), sizeAll);
// move cursor outside the window area
input()->pointer()->warp(QPointF(800, 800));
// and end the override, which should switch to fallback
effects->stopMouseInterception(effect.get());
QCOMPARE(cursor->image(), fallback);
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
// start mouse interception again
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
QCOMPARE(cursor->image(), sizeAll);
QCOMPARE(kwinApp()->cursorImage().image(), sizeAll);
// move cursor to area of window
input()->pointer()->warp(window->frameGeometry().center());
@ -1247,7 +1246,7 @@ void PointerInputTest::testEffectOverrideCursorImage()
// after ending the interception we should get an enter event
effects->stopMouseInterception(effect.get());
QVERIFY(enteredSpy.wait());
QVERIFY(cursor->image().isNull());
QVERIFY(kwinApp()->cursorImage().image().isNull());
}
void PointerInputTest::testPopup()

View file

@ -175,14 +175,6 @@ bool Cursor::isOnOutput(Output *output) const
return geometry().intersects(output->geometry());
}
QImage Cursor::image() const
{
if (Q_UNLIKELY(!m_source)) {
return QImage();
}
return m_source->image();
}
QPointF Cursor::hotspot() const
{
if (Q_UNLIKELY(!m_source)) {

View file

@ -168,7 +168,6 @@ public:
*/
xcb_cursor_t x11Cursor(const QByteArray &name);
QImage image() const;
QPointF hotspot() const;
QRectF geometry() const;
QRectF rect() const;

View file

@ -17,6 +17,7 @@
#include "core/outputbackend.h"
#include "core/session.h"
#include "cursor.h"
#include "cursorsource.h"
#include "effects.h"
#include "input.h"
#include "inputmethod.h"
@ -641,7 +642,10 @@ ScreenLockerWatcher *Application::screenLockerWatcher() const
PlatformCursorImage Application::cursorImage() const
{
Cursor *cursor = Cursors::self()->currentCursor();
return PlatformCursorImage(cursor->image(), cursor->hotspot());
if (CursorSource *source = cursor->source()) {
return PlatformCursorImage(source->image(), source->hotspot());
}
return PlatformCursorImage();
}
void Application::startInteractiveWindowSelection(std::function<void(KWin::Window *)> callback, const QByteArray &cursorName)

View file

@ -413,10 +413,12 @@ bool ScreenCastStream::createStream()
}
if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded) {
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &ScreenCastStream::invalidateCursor);
connect(Cursors::self(), &Cursors::positionChanged, this, [this] {
recordFrame({});
});
} else if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Metadata) {
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &ScreenCastStream::invalidateCursor);
connect(Cursors::self(), &Cursors::positionChanged, this, &ScreenCastStream::recordCursor);
}
@ -524,7 +526,8 @@ void ScreenCastStream::recordFrame(const QRegion &_damagedRegion)
QImage dest(data, size.width(), size.height(), stride, hasAlpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGB888);
QPainter painter(&dest);
const auto position = (cursor->pos() - m_cursor.viewport.topLeft() - cursor->hotspot()) * m_cursor.scale;
painter.drawImage(QRect{position.toPoint(), cursor->image().size()}, cursor->image());
const PlatformCursorImage cursorImage = kwinApp()->cursorImage();
painter.drawImage(QRect{position.toPoint(), cursorImage.image().size()}, cursorImage.image());
}
} else {
auto &buf = m_dmabufDataForPwBuffer[buffer];
@ -542,7 +545,16 @@ void ScreenCastStream::recordFrame(const QRegion &_damagedRegion)
auto cursor = Cursors::self()->currentCursor();
if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded && exclusiveContains(m_cursor.viewport, cursor->pos())) {
if (!cursor->image().isNull()) {
if (m_cursor.invalid) {
m_cursor.invalid = false;
const PlatformCursorImage cursorImage = kwinApp()->cursorImage();
if (cursorImage.isNull()) {
m_cursor.texture = nullptr;
} else {
m_cursor.texture = std::make_unique<GLTexture>(cursorImage.image());
}
}
if (m_cursor.texture) {
GLFramebuffer::pushFramebuffer(buf->framebuffer());
QRect r(QPoint(), size);
@ -552,13 +564,9 @@ void ScreenCastStream::recordFrame(const QRegion &_damagedRegion)
mvp.ortho(r);
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
if (!m_cursor.texture || m_cursor.lastKey != cursor->image().cacheKey()) {
m_cursor.texture.reset(new GLTexture(cursor->image()));
}
m_cursor.texture->setContentTransform(TextureTransforms());
const auto cursorRect = cursorGeometry(cursor);
mvp.translate(cursorRect.left(), r.height() - cursorRect.top() - cursor->image().height());
mvp.translate(cursorRect.left(), r.height() - cursorRect.top() - m_cursor.texture->height());
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
glEnable(GL_BLEND);
@ -626,6 +634,11 @@ void ScreenCastStream::addDamage(spa_buffer *spaBuffer, const QRegion &damagedRe
}
}
void ScreenCastStream::invalidateCursor()
{
m_cursor.invalid = true;
}
void ScreenCastStream::recordCursor()
{
Q_ASSERT(!m_stopped);
@ -815,12 +828,11 @@ void ScreenCastStream::sendCursorData(Cursor *cursor, spa_meta_cursor *spa_meta_
spa_meta_cursor->hotspot.y = cursor->hotspot().y() * m_cursor.scale;
spa_meta_cursor->bitmap_offset = 0;
const QImage image = cursor->image();
if (image.cacheKey() == m_cursor.lastKey) {
if (!m_cursor.invalid) {
return;
}
m_cursor.lastKey = image.cacheKey();
m_cursor.invalid = false;
spa_meta_cursor->bitmap_offset = sizeof(struct spa_meta_cursor);
const QSize targetSize = (cursor->rect().size() * m_cursor.scale).toSize();
@ -842,6 +854,7 @@ void ScreenCastStream::sendCursorData(Cursor *cursor, spa_meta_cursor *spa_meta_
QImage::Format_RGBA8888_Premultiplied);
dest.fill(Qt::transparent);
const QImage image = kwinApp()->cursorImage().image();
if (!image.isNull()) {
QPainter painter(&dest);
painter.drawImage(QRect({0, 0}, targetSize), image);

View file

@ -65,6 +65,7 @@ public:
void setCursorMode(KWaylandServer::ScreencastV1Interface::CursorMode mode, qreal scale, const QRectF &viewport);
public Q_SLOTS:
void invalidateCursor();
void recordCursor();
Q_SIGNALS:
@ -117,10 +118,10 @@ private:
const QSize bitmapSize = QSize(256, 256);
qreal scale = 1;
QRectF viewport;
qint64 lastKey = 0;
QRectF lastRect;
std::unique_ptr<GLTexture> texture;
bool visible = false;
bool invalid = true;
} m_cursor;
QRectF cursorGeometry(Cursor *cursor) const;