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:
parent
af7c1db43b
commit
3d5b5844d0
6 changed files with 47 additions and 39 deletions
|
@ -1090,7 +1090,7 @@ void PointerInputTest::testCursorImage()
|
||||||
input()->pointer()->warp(QPointF(800, 800));
|
input()->pointer()->warp(QPointF(800, 800));
|
||||||
auto p = input()->pointer();
|
auto p = input()->pointer();
|
||||||
// at the moment it should be the fallback cursor
|
// at the moment it should be the fallback cursor
|
||||||
const QImage fallbackCursor = cursor->image();
|
const QImage fallbackCursor = kwinApp()->cursorImage().image();
|
||||||
QVERIFY(!fallbackCursor.isNull());
|
QVERIFY(!fallbackCursor.isNull());
|
||||||
|
|
||||||
// create a window
|
// 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
|
// 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());
|
input()->pointer()->warp(window->frameGeometry().center());
|
||||||
QCOMPARE(p->focus(), window);
|
QCOMPARE(p->focus(), window);
|
||||||
QCOMPARE(cursor->image(), fallbackCursor);
|
QCOMPARE(kwinApp()->cursorImage().image(), fallbackCursor);
|
||||||
QVERIFY(enteredSpy.wait());
|
QVERIFY(enteredSpy.wait());
|
||||||
|
|
||||||
// create a cursor on the pointer
|
// create a cursor on the pointer
|
||||||
|
@ -1121,13 +1121,13 @@ void PointerInputTest::testCursorImage()
|
||||||
cursorSurface->commit();
|
cursorSurface->commit();
|
||||||
pointer->setCursor(cursorSurface.get(), QPoint(5, 5));
|
pointer->setCursor(cursorSurface.get(), QPoint(5, 5));
|
||||||
QVERIFY(cursorRenderedSpy.wait());
|
QVERIFY(cursorRenderedSpy.wait());
|
||||||
QCOMPARE(cursor->image(), red);
|
QCOMPARE(kwinApp()->cursorImage().image(), red);
|
||||||
QCOMPARE(cursor->hotspot(), QPoint(5, 5));
|
QCOMPARE(cursor->hotspot(), QPoint(5, 5));
|
||||||
// change hotspot
|
// change hotspot
|
||||||
pointer->setCursor(cursorSurface.get(), QPoint(6, 6));
|
pointer->setCursor(cursorSurface.get(), QPoint(6, 6));
|
||||||
Test::flushWaylandConnection();
|
Test::flushWaylandConnection();
|
||||||
QTRY_COMPARE(cursor->hotspot(), QPoint(6, 6));
|
QTRY_COMPARE(cursor->hotspot(), QPoint(6, 6));
|
||||||
QCOMPARE(cursor->image(), red);
|
QCOMPARE(kwinApp()->cursorImage().image(), red);
|
||||||
|
|
||||||
// change the buffer
|
// change the buffer
|
||||||
QImage blue = QImage(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
|
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->damage(QRect(0, 0, 10, 10));
|
||||||
cursorSurface->commit();
|
cursorSurface->commit();
|
||||||
QVERIFY(cursorRenderedSpy.wait());
|
QVERIFY(cursorRenderedSpy.wait());
|
||||||
QTRY_COMPARE(cursor->image(), blue);
|
QTRY_COMPARE(kwinApp()->cursorImage().image(), blue);
|
||||||
QCOMPARE(cursor->hotspot(), QPoint(6, 6));
|
QCOMPARE(cursor->hotspot(), QPoint(6, 6));
|
||||||
|
|
||||||
// scaled cursor
|
// scaled cursor
|
||||||
|
@ -1150,19 +1150,19 @@ void PointerInputTest::testCursorImage()
|
||||||
cursorSurface->damage(QRect(0, 0, 20, 20));
|
cursorSurface->damage(QRect(0, 0, 20, 20));
|
||||||
cursorSurface->commit();
|
cursorSurface->commit();
|
||||||
QVERIFY(cursorRenderedSpy.wait());
|
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)
|
QCOMPARE(cursor->hotspot(), QPoint(6, 6)); // surface-local (so not changed)
|
||||||
|
|
||||||
// hide the cursor
|
// hide the cursor
|
||||||
pointer->setCursor(nullptr);
|
pointer->setCursor(nullptr);
|
||||||
Test::flushWaylandConnection();
|
Test::flushWaylandConnection();
|
||||||
QTRY_VERIFY(cursor->image().isNull());
|
QTRY_VERIFY(kwinApp()->cursorImage().image().isNull());
|
||||||
|
|
||||||
// move cursor somewhere else, should reset to fallback cursor
|
// move cursor somewhere else, should reset to fallback cursor
|
||||||
input()->pointer()->warp(window->frameGeometry().bottomLeft() + QPoint(20, 20));
|
input()->pointer()->warp(window->frameGeometry().bottomLeft() + QPoint(20, 20));
|
||||||
QVERIFY(!p->focus());
|
QVERIFY(!p->focus());
|
||||||
QVERIFY(!cursor->image().isNull());
|
QVERIFY(!kwinApp()->cursorImage().image().isNull());
|
||||||
QCOMPARE(cursor->image(), fallbackCursor);
|
QCOMPARE(kwinApp()->cursorImage().image(), fallbackCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
class HelperEffect : public Effect
|
class HelperEffect : public Effect
|
||||||
|
@ -1183,7 +1183,6 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
||||||
|
|
||||||
// we need a pointer to get the enter event and set a cursor
|
// we need a pointer to get the enter event and set a cursor
|
||||||
auto pointer = m_seat->createPointer(m_seat);
|
auto pointer = m_seat->createPointer(m_seat);
|
||||||
auto cursor = Cursors::self()->mouse();
|
|
||||||
QVERIFY(pointer);
|
QVERIFY(pointer);
|
||||||
QVERIFY(pointer->isValid());
|
QVERIFY(pointer->isValid());
|
||||||
QSignalSpy enteredSpy(pointer, &KWayland::Client::Pointer::entered);
|
QSignalSpy enteredSpy(pointer, &KWayland::Client::Pointer::entered);
|
||||||
|
@ -1191,7 +1190,7 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
||||||
// move cursor somewhere the new window won't open
|
// move cursor somewhere the new window won't open
|
||||||
input()->pointer()->warp(QPointF(800, 800));
|
input()->pointer()->warp(QPointF(800, 800));
|
||||||
// here we should have the fallback cursor
|
// here we should have the fallback cursor
|
||||||
const QImage fallback = cursor->image();
|
const QImage fallback = kwinApp()->cursorImage().image();
|
||||||
QVERIFY(!fallback.isNull());
|
QVERIFY(!fallback.isNull());
|
||||||
|
|
||||||
// now let's create a window
|
// now let's create a window
|
||||||
|
@ -1210,33 +1209,33 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
||||||
input()->pointer()->warp(window->frameGeometry().center());
|
input()->pointer()->warp(window->frameGeometry().center());
|
||||||
QVERIFY(enteredSpy.wait());
|
QVERIFY(enteredSpy.wait());
|
||||||
// cursor image should still be fallback
|
// cursor image should still be fallback
|
||||||
QCOMPARE(cursor->image(), fallback);
|
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
|
||||||
|
|
||||||
// now create an effect and set an override cursor
|
// now create an effect and set an override cursor
|
||||||
std::unique_ptr<HelperEffect> effect(new HelperEffect);
|
std::unique_ptr<HelperEffect> effect(new HelperEffect);
|
||||||
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
|
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
|
||||||
const QImage sizeAll = cursor->image();
|
const QImage sizeAll = kwinApp()->cursorImage().image();
|
||||||
QVERIFY(!sizeAll.isNull());
|
QVERIFY(!sizeAll.isNull());
|
||||||
QVERIFY(sizeAll != fallback);
|
QVERIFY(sizeAll != fallback);
|
||||||
QVERIFY(leftSpy.wait());
|
QVERIFY(leftSpy.wait());
|
||||||
|
|
||||||
// let's change to arrow cursor, this should be our fallback
|
// let's change to arrow cursor, this should be our fallback
|
||||||
effects->defineCursor(Qt::ArrowCursor);
|
effects->defineCursor(Qt::ArrowCursor);
|
||||||
QCOMPARE(cursor->image(), fallback);
|
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
|
||||||
|
|
||||||
// back to size all
|
// back to size all
|
||||||
effects->defineCursor(Qt::SizeAllCursor);
|
effects->defineCursor(Qt::SizeAllCursor);
|
||||||
QCOMPARE(cursor->image(), sizeAll);
|
QCOMPARE(kwinApp()->cursorImage().image(), sizeAll);
|
||||||
|
|
||||||
// move cursor outside the window area
|
// move cursor outside the window area
|
||||||
input()->pointer()->warp(QPointF(800, 800));
|
input()->pointer()->warp(QPointF(800, 800));
|
||||||
// and end the override, which should switch to fallback
|
// and end the override, which should switch to fallback
|
||||||
effects->stopMouseInterception(effect.get());
|
effects->stopMouseInterception(effect.get());
|
||||||
QCOMPARE(cursor->image(), fallback);
|
QCOMPARE(kwinApp()->cursorImage().image(), fallback);
|
||||||
|
|
||||||
// start mouse interception again
|
// start mouse interception again
|
||||||
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
|
effects->startMouseInterception(effect.get(), Qt::SizeAllCursor);
|
||||||
QCOMPARE(cursor->image(), sizeAll);
|
QCOMPARE(kwinApp()->cursorImage().image(), sizeAll);
|
||||||
|
|
||||||
// move cursor to area of window
|
// move cursor to area of window
|
||||||
input()->pointer()->warp(window->frameGeometry().center());
|
input()->pointer()->warp(window->frameGeometry().center());
|
||||||
|
@ -1247,7 +1246,7 @@ void PointerInputTest::testEffectOverrideCursorImage()
|
||||||
// after ending the interception we should get an enter event
|
// after ending the interception we should get an enter event
|
||||||
effects->stopMouseInterception(effect.get());
|
effects->stopMouseInterception(effect.get());
|
||||||
QVERIFY(enteredSpy.wait());
|
QVERIFY(enteredSpy.wait());
|
||||||
QVERIFY(cursor->image().isNull());
|
QVERIFY(kwinApp()->cursorImage().image().isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointerInputTest::testPopup()
|
void PointerInputTest::testPopup()
|
||||||
|
|
|
@ -175,14 +175,6 @@ bool Cursor::isOnOutput(Output *output) const
|
||||||
return geometry().intersects(output->geometry());
|
return geometry().intersects(output->geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage Cursor::image() const
|
|
||||||
{
|
|
||||||
if (Q_UNLIKELY(!m_source)) {
|
|
||||||
return QImage();
|
|
||||||
}
|
|
||||||
return m_source->image();
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointF Cursor::hotspot() const
|
QPointF Cursor::hotspot() const
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(!m_source)) {
|
if (Q_UNLIKELY(!m_source)) {
|
||||||
|
|
|
@ -168,7 +168,6 @@ public:
|
||||||
*/
|
*/
|
||||||
xcb_cursor_t x11Cursor(const QByteArray &name);
|
xcb_cursor_t x11Cursor(const QByteArray &name);
|
||||||
|
|
||||||
QImage image() const;
|
|
||||||
QPointF hotspot() const;
|
QPointF hotspot() const;
|
||||||
QRectF geometry() const;
|
QRectF geometry() const;
|
||||||
QRectF rect() const;
|
QRectF rect() const;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "core/outputbackend.h"
|
#include "core/outputbackend.h"
|
||||||
#include "core/session.h"
|
#include "core/session.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
|
#include "cursorsource.h"
|
||||||
#include "effects.h"
|
#include "effects.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "inputmethod.h"
|
#include "inputmethod.h"
|
||||||
|
@ -641,7 +642,10 @@ ScreenLockerWatcher *Application::screenLockerWatcher() const
|
||||||
PlatformCursorImage Application::cursorImage() const
|
PlatformCursorImage Application::cursorImage() const
|
||||||
{
|
{
|
||||||
Cursor *cursor = Cursors::self()->currentCursor();
|
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)
|
void Application::startInteractiveWindowSelection(std::function<void(KWin::Window *)> callback, const QByteArray &cursorName)
|
||||||
|
|
|
@ -413,10 +413,12 @@ bool ScreenCastStream::createStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded) {
|
if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded) {
|
||||||
|
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &ScreenCastStream::invalidateCursor);
|
||||||
connect(Cursors::self(), &Cursors::positionChanged, this, [this] {
|
connect(Cursors::self(), &Cursors::positionChanged, this, [this] {
|
||||||
recordFrame({});
|
recordFrame({});
|
||||||
});
|
});
|
||||||
} else if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Metadata) {
|
} else if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Metadata) {
|
||||||
|
connect(Cursors::self(), &Cursors::currentCursorChanged, this, &ScreenCastStream::invalidateCursor);
|
||||||
connect(Cursors::self(), &Cursors::positionChanged, this, &ScreenCastStream::recordCursor);
|
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);
|
QImage dest(data, size.width(), size.height(), stride, hasAlpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGB888);
|
||||||
QPainter painter(&dest);
|
QPainter painter(&dest);
|
||||||
const auto position = (cursor->pos() - m_cursor.viewport.topLeft() - cursor->hotspot()) * m_cursor.scale;
|
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 {
|
} else {
|
||||||
auto &buf = m_dmabufDataForPwBuffer[buffer];
|
auto &buf = m_dmabufDataForPwBuffer[buffer];
|
||||||
|
@ -542,7 +545,16 @@ void ScreenCastStream::recordFrame(const QRegion &_damagedRegion)
|
||||||
|
|
||||||
auto cursor = Cursors::self()->currentCursor();
|
auto cursor = Cursors::self()->currentCursor();
|
||||||
if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded && exclusiveContains(m_cursor.viewport, cursor->pos())) {
|
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());
|
GLFramebuffer::pushFramebuffer(buf->framebuffer());
|
||||||
|
|
||||||
QRect r(QPoint(), size);
|
QRect r(QPoint(), size);
|
||||||
|
@ -552,13 +564,9 @@ void ScreenCastStream::recordFrame(const QRegion &_damagedRegion)
|
||||||
mvp.ortho(r);
|
mvp.ortho(r);
|
||||||
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
|
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());
|
m_cursor.texture->setContentTransform(TextureTransforms());
|
||||||
const auto cursorRect = cursorGeometry(cursor);
|
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);
|
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
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()
|
void ScreenCastStream::recordCursor()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_stopped);
|
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->hotspot.y = cursor->hotspot().y() * m_cursor.scale;
|
||||||
spa_meta_cursor->bitmap_offset = 0;
|
spa_meta_cursor->bitmap_offset = 0;
|
||||||
|
|
||||||
const QImage image = cursor->image();
|
if (!m_cursor.invalid) {
|
||||||
if (image.cacheKey() == m_cursor.lastKey) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cursor.lastKey = image.cacheKey();
|
m_cursor.invalid = false;
|
||||||
spa_meta_cursor->bitmap_offset = sizeof(struct spa_meta_cursor);
|
spa_meta_cursor->bitmap_offset = sizeof(struct spa_meta_cursor);
|
||||||
|
|
||||||
const QSize targetSize = (cursor->rect().size() * m_cursor.scale).toSize();
|
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);
|
QImage::Format_RGBA8888_Premultiplied);
|
||||||
dest.fill(Qt::transparent);
|
dest.fill(Qt::transparent);
|
||||||
|
|
||||||
|
const QImage image = kwinApp()->cursorImage().image();
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
QPainter painter(&dest);
|
QPainter painter(&dest);
|
||||||
painter.drawImage(QRect({0, 0}, targetSize), image);
|
painter.drawImage(QRect({0, 0}, targetSize), image);
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
void setCursorMode(KWaylandServer::ScreencastV1Interface::CursorMode mode, qreal scale, const QRectF &viewport);
|
void setCursorMode(KWaylandServer::ScreencastV1Interface::CursorMode mode, qreal scale, const QRectF &viewport);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
void invalidateCursor();
|
||||||
void recordCursor();
|
void recordCursor();
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
@ -117,10 +118,10 @@ private:
|
||||||
const QSize bitmapSize = QSize(256, 256);
|
const QSize bitmapSize = QSize(256, 256);
|
||||||
qreal scale = 1;
|
qreal scale = 1;
|
||||||
QRectF viewport;
|
QRectF viewport;
|
||||||
qint64 lastKey = 0;
|
|
||||||
QRectF lastRect;
|
QRectF lastRect;
|
||||||
std::unique_ptr<GLTexture> texture;
|
std::unique_ptr<GLTexture> texture;
|
||||||
bool visible = false;
|
bool visible = false;
|
||||||
|
bool invalid = true;
|
||||||
} m_cursor;
|
} m_cursor;
|
||||||
QRectF cursorGeometry(Cursor *cursor) const;
|
QRectF cursorGeometry(Cursor *cursor) const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue