plugins/shakecursor: Port to CursorItem

It reduces the amount of manual OpenGL code, and it's better to use
ImageItem because that way the ItemRenderer will take care of snapping
to the pixel grid or colorspaces.
wilder/Plasma/6.2
Vlad Zahorodnii 2 years ago
parent bcba59a7f5
commit 191b0e7b6d
  1. 144
      src/plugins/shakecursor/shakecursor.cpp
  2. 25
      src/plugins/shakecursor/shakecursor.h

@ -5,15 +5,13 @@
*/
#include "plugins/shakecursor/shakecursor.h"
#include "core/rendertarget.h"
#include "core/renderviewport.h"
#include "cursor.h"
#include "effect/effecthandler.h"
#include "input_event.h"
#include "opengl/gltexture.h"
#include "opengl/glutils.h"
#include "plugins/shakecursor/shakecursorconfig.h"
#include "pointer_input.h"
#include "scene/cursoritem.h"
#include "scene/workspacescene.h"
namespace KWin
{
@ -33,12 +31,7 @@ ShakeCursorEffect::ShakeCursorEffect()
});
connect(&m_resetCursorScaleAnimation, &QVariantAnimation::valueChanged, this, [this]() {
update(Transaction{
.position = m_cursor->pos(),
.hotspot = m_cursor->hotspot(),
.size = m_cursor->geometry().size(),
.magnification = m_resetCursorScaleAnimation.currentValue().toReal(),
});
magnify(m_resetCursorScaleAnimation.currentValue().toReal());
});
ShakeCursorConfig::instance(effects->config());
@ -47,7 +40,7 @@ ShakeCursorEffect::ShakeCursorEffect()
ShakeCursorEffect::~ShakeCursorEffect()
{
showCursor();
magnify(1.0);
}
bool ShakeCursorEffect::supported()
@ -82,130 +75,35 @@ void ShakeCursorEffect::pointerEvent(MouseEvent *event)
}
if (const auto shakeFactor = m_shakeDetector.update(event)) {
update(Transaction{
.position = m_cursor->pos(),
.hotspot = m_cursor->hotspot(),
.size = m_cursor->geometry().size(),
.magnification = std::max(m_cursorMagnification, 1.0 + ShakeCursorConfig::magnification() * shakeFactor.value()),
});
m_resetCursorScaleTimer.start(animationTime(2000));
m_resetCursorScaleAnimation.stop();
} else if (m_cursorMagnification != 1.0) {
update(Transaction{
.position = m_cursor->pos(),
.hotspot = m_cursor->hotspot(),
.size = m_cursor->geometry().size(),
.magnification = m_cursorMagnification,
});
}
}
GLTexture *ShakeCursorEffect::ensureCursorTexture()
{
if (!m_cursorTexture || m_cursorTextureDirty) {
m_cursorTexture.reset();
m_cursorTextureDirty = false;
const auto cursor = effects->cursorImage();
if (!cursor.image().isNull()) {
m_cursorTexture = GLTexture::upload(cursor.image());
if (!m_cursorTexture) {
return nullptr;
}
m_cursorTexture->setWrapMode(GL_CLAMP_TO_EDGE);
m_cursorTexture->setFilter(GL_LINEAR);
}
}
return m_cursorTexture.get();
}
void ShakeCursorEffect::markCursorTextureDirty()
{
m_cursorTextureDirty = true;
update(Transaction{
.position = m_cursor->pos(),
.hotspot = m_cursor->hotspot(),
.size = m_cursor->geometry().size(),
.magnification = m_cursorMagnification,
.damaged = true,
});
}
void ShakeCursorEffect::showCursor()
{
if (m_mouseHidden) {
disconnect(effects, &EffectsHandler::cursorShapeChanged, this, &ShakeCursorEffect::markCursorTextureDirty);
effects->showCursor();
if (m_cursorTexture) {
effects->makeOpenGLContextCurrent();
m_cursorTexture.reset();
}
m_cursorTextureDirty = false;
m_mouseHidden = false;
}
}
void ShakeCursorEffect::hideCursor()
{
if (!m_mouseHidden) {
effects->hideCursor();
connect(effects, &EffectsHandler::cursorShapeChanged, this, &ShakeCursorEffect::markCursorTextureDirty);
m_mouseHidden = true;
magnify(std::max(m_cursorMagnification, 1.0 + ShakeCursorConfig::magnification() * shakeFactor.value()));
}
}
void ShakeCursorEffect::update(const Transaction &transaction)
void ShakeCursorEffect::magnify(qreal magnification)
{
if (transaction.magnification == 1.0) {
if (m_cursorMagnification == 1.0) {
return;
}
const QRectF oldCursorGeometry = m_cursorGeometry;
showCursor();
m_cursorGeometry = QRectF();
if (magnification == 1.0) {
m_cursorMagnification = 1.0;
effects->addRepaint(oldCursorGeometry);
} else {
const QRectF oldCursorGeometry = m_cursorGeometry;
hideCursor();
m_cursorMagnification = transaction.magnification;
m_cursorGeometry = QRectF(transaction.position - transaction.hotspot * transaction.magnification, transaction.size * transaction.magnification);
if (transaction.damaged || oldCursorGeometry != m_cursorGeometry) {
effects->addRepaint(oldCursorGeometry.united(m_cursorGeometry));
if (m_cursorItem) {
m_cursorItem.reset();
effects->showCursor();
}
}
}
void ShakeCursorEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen)
{
effects->paintScreen(renderTarget, viewport, mask, region, screen);
} else {
m_cursorMagnification = magnification;
if (GLTexture *texture = ensureCursorTexture()) {
const bool clipping = region != infiniteRegion();
const QRegion clipRegion = clipping ? viewport.mapToRenderTarget(region) : infiniteRegion();
if (clipping) {
glEnable(GL_SCISSOR_TEST);
}
if (!m_cursorItem) {
effects->hideCursor();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
shader->setColorspaceUniformsFromSRGB(renderTarget.colorDescription());
QMatrix4x4 mvp = viewport.projectionMatrix();
mvp.translate(m_cursorGeometry.x() * viewport.scale(), m_cursorGeometry.y() * viewport.scale());
shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
texture->render(clipRegion, m_cursorGeometry.size() * viewport.scale(), clipping);
ShaderManager::instance()->popShader();
glDisable(GL_BLEND);
if (clipping) {
glDisable(GL_SCISSOR_TEST);
m_cursorItem = std::make_unique<CursorItem>(effects->scene());
m_cursorItem->setParentItem(effects->scene()->overlayItem());
m_cursorItem->setPosition(m_cursor->pos());
connect(m_cursor, &Cursor::posChanged, m_cursorItem.get(), [this]() {
m_cursorItem->setPosition(m_cursor->pos());
});
}
m_cursorItem->setTransform(QTransform::fromScale(magnification, magnification));
}
}

@ -17,7 +17,7 @@ namespace KWin
{
class Cursor;
class GLTexture;
class CursorItem;
class ShakeCursorEffect : public Effect, public InputEventSpy
{
@ -32,36 +32,17 @@ public:
void reconfigure(ReconfigureFlags flags) override;
void pointerEvent(MouseEvent *event) override;
bool isActive() const override;
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen) override;
private:
GLTexture *ensureCursorTexture();
void markCursorTextureDirty();
void showCursor();
void hideCursor();
struct Transaction
{
QPointF position;
QPointF hotspot;
QSizeF size;
qreal magnification;
bool damaged = false;
};
void update(const Transaction &transaction);
void magnify(qreal magnification);
QTimer m_resetCursorScaleTimer;
QVariantAnimation m_resetCursorScaleAnimation;
ShakeDetector m_shakeDetector;
Cursor *m_cursor;
QRectF m_cursorGeometry;
std::unique_ptr<CursorItem> m_cursorItem;
qreal m_cursorMagnification = 1.0;
std::unique_ptr<GLTexture> m_cursorTexture;
bool m_cursorTextureDirty = false;
bool m_mouseHidden = false;
};
} // namespace KWin

Loading…
Cancel
Save