前言

在上一篇文章中,我们已经成功创建了一个 kwin 特效插件,在本篇中,我们将开始绘制一些内容。

准备文件

在 KWin 中有两种方式在屏幕上绘制内容,一种是直接调用 OpenGL 接口绘制,另一种是调用封装好的接口,绘制一个 QML 文件的内容,本篇文章为了体现教学的乐趣,选择使用 QML 的方式(才不是因为我不会 OpenGL)

output.qml

在项目目录创建一个 output.qml 用作绘制的内容。

import QtQuick

Grid {
anchors.fill: parent
rows: Math.ceil(height / 100)
columns: Math.ceil(width / 200)
spacing: 50

Repeater {
model: parent.rows * parent.columns

Text {
text: "我是水印"
font.pixelSize: 24
font.bold: true
color: "black"
opacity: 0.3
rotation: 45
width: 200
height: 100
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}

这个文件会在绘制范围内平铺显示 我是水印 的文字。

watermark.h

Effect 有多个虚函数用来实现各种功能,在本示例中,只需要重写 paintScreen 函数完成画面绘制即可。

KWin 使用 EffectFrameEx 对象加载 QML,并提供离屏渲染的封装。

#pragma once

#include <kwineffects.h>
#include <kwineffectsex.h>
#include <memory.h>

class KWINEFFECTS_EXPORT WaterMarkEffect : public KWin::Effect
{
Q_OBJECT
public:
WaterMarkEffect(QObject *parent = nullptr);
~WaterMarkEffect() override = default;

void paintScreen(int mask, const QRegion &region,
KWin::ScreenPaintData &data) override;

private:
std::unique_ptr<KWin::EffectFrameEx> m_maskFrame;
};

watermark.cpp

#include "watermark.h"

#include <QLoggingCategory>

using namespace KWin;

Q_LOGGING_CATEGORY(watermark, "kwin.effects.watermark")

WaterMarkEffect::WaterMarkEffect(QObject *parent)
: Effect(parent)
, m_maskFrame(effectsEx->effectFrameEx("kwin/effects/watermark/output.qml"))
{
qCDebug(watermark) << "init watermark effect.";
}

void paintScreen(int mask, const QRegion &region,
KWin::ScreenPaintData &data)
{
effects->paintScreen(mask, region, data);
}

到目前为止,我们已经接近成功了,只需要在 paintScreen 中调用绘制就可以了。

void WaterMarkEffect::paintScreen(int mask, const QRegion &region,
KWin::ScreenPaintData &data)
{
effects->paintScreen(mask, region, data);

m_maskFrame->setGeometry(data.screen()->geometry());
m_maskFrame->render(infiniteRegion(), 1, 0);
}

这里简单解释一下为什么必须先调用 effects->paintScreen 再调用我们的绘制,在 KWin 中,画面是从底部到顶部一层一层绘制的,而 paintScreen 是一个链式调用,每个插件都必须调用一次,否则绘制将会终止,而本示例想要做的是在屏幕最上方绘制水印,所以需要先调用执行链,完成所有画面的绘制,再开始绘制我们的内容。

成果展示

现在可以按照第一篇的内容,完成构建、安装和加载了。