Initial commit

This commit is contained in:
wackyideas 2024-06-13 16:59:18 +02:00
commit 93f678358d
715 changed files with 103197 additions and 0 deletions

View file

@ -0,0 +1,15 @@
{
"KPlugin": {
"Authors": [
{
"Name": "Souris"
}
],
"Category": "Appearance",
"Description": "Show an animation when a resizable window is dragged to a screen edge",
"EnabledByDefault": false,
"Id": "smodsnap",
"License": "GPL",
"Name": "SMOD Snap"
}
}

View file

@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2024 Souris
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "smodsnap.h"
namespace KWin
{
KWIN_EFFECT_FACTORY_SUPPORTED(
SmodSnapEffect, "metadata.json",
{
return SmodSnapEffect::supported();
}
)
}
#include "plugin.moc"

View file

@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2024 Souris
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
/*
* Generic reusable code for SMOD
*/
#include <QDir>
#include <QFileInfo>
#include <QResource>
#include <QString>
namespace SMOD
{
const QString SMOD_EXTENSION = QStringLiteral(".smod.rcc");
inline void registerResource(const QString &name)
{
QResource::registerResource(QDir::homePath() + QStringLiteral("/.local/share/smod/") + name + SMOD_EXTENSION);
}
inline bool resourceExists(const QString &name)
{
QFileInfo resource(QDir::homePath() + QStringLiteral("/.local/share/smod/") + name + SMOD_EXTENSION);
return resource.exists();
}
}

View file

@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2024 Souris
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "smodsnap.h"
#include <KConfig>
#include <KConfigGroup>
namespace KWin
{
void SmodSnapEffect::loadTextures()
{
KConfig config(":/effects/smodsnap/animation/animrc");
KConfigGroup generalGroup(&config, "General");
m_frames = generalGroup.readEntry("frames", 0);
m_speed = generalGroup.readEntry("speed", 0);
m_scale = generalGroup.readEntry("scale", 1.0);
int width = generalGroup.readEntry("width", 0);
int height = generalGroup.readEntry("height", 0);
m_size = QPoint(width, height);
m_texture.resize(m_frames);
for (int i = 0; i < m_frames; ++i)
{
m_texture[i].reset(new GLTexture(QPixmap(":/effects/smodsnap/animation/frame" + QString::number(i + 1))));
m_texture[i]->setFilter(GL_LINEAR);
m_texture[i]->setWrapMode(GL_CLAMP_TO_EDGE);
}
}
void SmodSnapEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &data)
{
effects->paintScreen(mask, region, data);
if (anim1->m_active || anim2->m_active)
{
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
ShaderManager::instance()->pushShader(m_shader.get());
const auto scale = effects->renderTargetScale();
if (!anim1->m_finished)
{
QMatrix4x4 mvp = data.projectionMatrix();
mvp.translate(anim1->m_rect.x() * scale, anim1->m_rect.y() * scale);
m_shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
GLTexture *texture = m_texture[anim1->m_frame].get();
texture->bind();
texture->render(anim1->m_rect, scale);
texture->unbind();
}
if (!anim2->m_finished)
{
QMatrix4x4 mvp = data.projectionMatrix();
mvp.translate(anim2->m_rect.x() * scale, anim2->m_rect.y() * scale);
m_shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
GLTexture *texture = m_texture[anim2->m_frame].get();
texture->bind();
texture->render(anim2->m_rect, scale);
texture->unbind();
}
ShaderManager::instance()->popShader();
glDisable(GL_BLEND);
}
}
}

View file

@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: 2024 Souris
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "smodsnap.h"
#include <KConfig>
#include <KConfigGroup>
namespace KWin
{
void SmodSnapEffect::loadTextures()
{
KConfig config(QStringLiteral(":/effects/smodsnap/animation/animrc"));
KConfigGroup generalGroup(&config, QStringLiteral("General"));
m_frames = generalGroup.readEntry("frames", 0);
m_speed = generalGroup.readEntry("speed", 0);
m_scale = generalGroup.readEntry("scale", 1.0);
int width = generalGroup.readEntry("width", 0);
int height = generalGroup.readEntry("height", 0);
m_size = QPoint(width, height);
m_texture.resize(m_frames);
for (int i = 0; i < m_frames; ++i)
{
m_texture[i] = GLTexture::upload(QPixmap(QStringLiteral(":/effects/smodsnap/animation/frame") + QString::number(i + 1)));
m_texture[i]->setFilter(GL_LINEAR);
m_texture[i]->setWrapMode(GL_CLAMP_TO_EDGE);
}
}
void SmodSnapEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen)
{
effects->paintScreen(renderTarget, viewport, mask, region, screen);
if (anim1->m_active || anim2->m_active)
{
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
ShaderManager::instance()->pushShader(m_shader.get());
const auto scale = viewport.scale();
if (!anim1->m_finished)
{
const QRectF pixelGeometry = snapToPixelGridF(scaledRect(anim1->m_rect, scale));
QMatrix4x4 mvp = viewport.projectionMatrix();
mvp.translate(anim1->m_rect.x(), anim1->m_rect.y());
m_shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
GLTexture *texture = m_texture[anim1->m_frame].get();
texture->render(pixelGeometry.size());
}
if (!anim2->m_finished)
{
const QRectF pixelGeometry = snapToPixelGridF(scaledRect(anim2->m_rect, scale));
QMatrix4x4 mvp = viewport.projectionMatrix();
mvp.translate(anim2->m_rect.x(), anim2->m_rect.y());
m_shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
GLTexture *texture = m_texture[anim2->m_frame].get();
texture->render(pixelGeometry.size());
}
ShaderManager::instance()->popShader();
glDisable(GL_BLEND);
}
}
}

View file

@ -0,0 +1,194 @@
/*
* SPDX-FileCopyrightText: 2024 Souris
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "smodsnap.h"
#include "smod.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
static void ensureResources()
{
Q_INIT_RESOURCE(smodsnap);
}
namespace KWin
{
SmodSnapEffect::SmodSnapEffect()
{
connect(effects, &EffectsHandler::windowAdded, this, &SmodSnapEffect::windowAdded);
reconfigure(ReconfigureAll);
// NOTE is this needed?
//effects->makeOpenGLContextCurrent();
anim1 = new SnapAnimation();
anim2 = new SnapAnimation();
loadTextures();
m_shader = ShaderManager::instance()->generateShaderFromFile(
ShaderTrait::MapTexture,
QString(),
QStringLiteral(":/effects/smodsnap/shaders/shader.frag")
);
}
SmodSnapEffect::~SmodSnapEffect()
{
if (anim1) delete anim1;
if (anim2) delete anim2;
}
bool SmodSnapEffect::supported()
{
return effects->isOpenGLCompositing() && SMOD::resourceExists(QStringLiteral("snapeffecttextures"));
}
void SmodSnapEffect::reconfigure(Effect::ReconfigureFlags flags)
{
Q_UNUSED(flags)
SMOD::registerResource(QStringLiteral("snapeffecttextures"));
if (effects->compositingType() == OpenGLCompositing)
{
ensureResources();
}
}
void SmodSnapEffect::windowAdded(KWin::EffectWindow *w)
{
auto min = [&](int a, int b) -> int
{
return a > b ? b : a;
};
if (w->isOutline())
{
if (!anim1->m_active)
{
anim1->m_active = true;
anim1->m_finished = false;
anim1->m_frame = 0;
anim1->m_progress = 0;
anim1->m_lastPresentTime = std::chrono::milliseconds{0};
const QPoint framesize = m_size * m_scale;
#if IS_KF6
const QPoint pos = effects->cursorPos().toPoint() - (framesize / 2);
#else
const QPoint pos = effects->cursorPos() - (framesize / 2);
#endif
int dx = w->screen()->geometry().width() - effects->cursorPos().toPoint().x();
int dy = w->screen()->geometry().height() - effects->cursorPos().toPoint().y();
printf("%d, %d, %d, %d\n", dx, dy, effects->cursorPos().toPoint().x(), effects->cursorPos().toPoint().y());
//right side: dx < pos.x
//bottom side: dy < pos.y
int rightSide = min(dx, pos.x());
int bottomSide = min(dy, pos.y());
anim1->m_rect = QRect(pos, QSize(framesize.x(), framesize.y()));
}
else if (!anim2->m_active)
{
anim2->m_active = true;
anim2->m_finished = false;
anim2->m_frame = 0;
anim2->m_progress = 0;
anim2->m_lastPresentTime = std::chrono::milliseconds{0};
const QPoint framesize = m_size * m_scale;
#if IS_KF6
const QPoint pos = effects->cursorPos().toPoint() - (framesize / 2);
#else
const QPoint pos = effects->cursorPos() - (framesize / 2);
#endif
anim2->m_rect = QRect(pos, QSize(framesize.x(), framesize.y()));
}
}
}
void SmodSnapEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
{
if (anim1->m_active)
{
int time = 0;
if (anim1->m_lastPresentTime.count()) {
time = (presentTime - anim1->m_lastPresentTime).count();
}
anim1->m_lastPresentTime = presentTime;
// NOTE we need to do (m_frames + 1) here so the last frame
// will play for the same amount of time as the rest
anim1->m_progress = (anim1->m_progress + time) % (m_speed * (m_frames + 1));
anim1->m_frame = (int)((qreal)anim1->m_progress / (qreal)m_speed) % (m_frames + 1);
if (anim1->m_frame == m_frames)
{
anim1->m_finished = true;
}
else
{
data.paint = data.paint.united(anim1->m_rect);
}
}
if (anim2->m_active)
{
int time = 0;
if (anim2->m_lastPresentTime.count()) {
time = (presentTime - anim2->m_lastPresentTime).count();
}
anim2->m_lastPresentTime = presentTime;
// NOTE we need to do (m_frames + 1) here so the last animation frame
// will play for the same amount of time as the rest
anim2->m_progress = (anim2->m_progress + time) % (m_speed * (m_frames + 1));
anim2->m_frame = qRound((qreal)anim2->m_progress / (qreal)m_speed) % (m_frames + 1);
if (anim2->m_frame == m_frames)
{
anim2->m_finished = true;
}
else
{
data.paint = data.paint.united(anim2->m_rect);
}
}
effects->prePaintScreen(data, presentTime);
}
void SmodSnapEffect::postPaintScreen()
{
if (anim1->m_active)
{
effects->addRepaint(anim1->m_rect);
if (anim1->m_finished)
{
anim1->m_active = false;
}
}
if (anim2->m_active)
{
effects->addRepaint(anim2->m_rect);
if (anim2->m_finished)
{
anim2->m_active = false;
}
}
effects->postPaintScreen();
}
}

View file

@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2024 Souris
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <chrono>
#include <QObject>
#define IS_KF6 QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#if IS_KF6
#include <kwin/effect/effecthandler.h>
#include <kwin/effect/effectwindow.h>
#include <kwin/opengl/glshadermanager.h>
#include <kwin/opengl/glshader.h>
#include <kwin/opengl/gltexture.h>
#include <kwin/core/renderviewport.h>
#include <kwin/core/pixelgrid.h>
#else
#include <kwineffects.h>
#include <kwinglutils.h>
#endif
namespace KWin
{
class SnapAnimation : public QObject
{
Q_OBJECT
public:
SnapAnimation() {};
bool m_active = false;
bool m_finished = false;
int m_frame = 0;
int m_progress = 0;
std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds{0};
QRect m_rect = QRect();
};
class SmodSnapEffect : public Effect
{
Q_OBJECT
public:
SmodSnapEffect();
~SmodSnapEffect() override;
void reconfigure(ReconfigureFlags flags) override;
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override;
#if IS_KF6
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen) override;
#else
void paintScreen(int mask, const QRegion &region, ScreenPaintData &data) override;
#endif
void postPaintScreen() override;
static bool supported();
bool isActive() const override
{
return true;
}
int requestedEffectChainPosition() const override
{
return 90;
}
private Q_SLOTS:
void windowAdded(KWin::EffectWindow *w);
private:
void loadTextures();
SnapAnimation *anim1 = nullptr, *anim2 = nullptr;
int m_frames = 0;
int m_speed = 0;
qreal m_scale = 1.0;
QPoint m_size = QPoint();
bool needsToMoveAway = false;
std::vector<std::unique_ptr<GLTexture>> m_texture;
std::unique_ptr<GLShader> m_shader;
KWin::EffectWindow *m_window = nullptr;
bool m_window_valid = false;
bool m_window_checked_valid = false;
};
}

View file

@ -0,0 +1,7 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/effects/smodsnap/shaders">
<file alias="shader.frag">../shaders/shader.frag</file>
<file alias="shader_core.frag">../shaders/shader_core.frag</file>
</qresource>
</RCC>