scripting: Add qml effect bindings
This allows creating third party qtquick scene effects without linking to libkwineffects and thus rebuilding the effect every kwin release.master
parent
793a0e72bf
commit
264ebe6377
@ -0,0 +1 @@
|
||||
build
|
@ -0,0 +1,14 @@
|
||||
# SPDX-FileCopyrightText: None
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(quick-effect)
|
||||
|
||||
find_package(ECM 5.240 REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
||||
|
||||
find_package(KF6 5.240 REQUIRED COMPONENTS
|
||||
Package
|
||||
)
|
||||
|
||||
kpackage_install_package(package quick-effect effects kwin)
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile name=""/>
|
||||
<group name="">
|
||||
<entry name="BackgroundColor" type="Color">
|
||||
<default>#ff00ff</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
@ -0,0 +1,2 @@
|
||||
SPDX-FileCopyrightText: None
|
||||
SPDX-License-Identifier: CC0-1.0
|
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QuickEffectConfig</class>
|
||||
<widget class="QWidget" name="QuickEffectConfig">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>455</width>
|
||||
<height>177</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Background color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="KColorButton" name="kcfg_BackgroundColor">
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -0,0 +1,2 @@
|
||||
SPDX-FileCopyrightText: None
|
||||
SPDX-License-Identifier: CC0-1.0
|
@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: None
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import QtQuick
|
||||
import org.kde.kwin
|
||||
|
||||
SceneEffect {
|
||||
id: effect
|
||||
|
||||
delegate: Rectangle {
|
||||
color: effect.configuration.BackgroundColor
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: SceneView.screen.name
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: effect.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
ScreenEdgeHandler {
|
||||
enabled: true
|
||||
edge: ScreenEdgeHandler.TopEdge
|
||||
onActivated: effect.visible = !effect.visible
|
||||
}
|
||||
|
||||
ShortcutHandler {
|
||||
name: "Toggle Quick Effect"
|
||||
text: "Toggle Quick Effect"
|
||||
sequence: "Meta+Ctrl+Q"
|
||||
onActivated: effect.visible = !effect.visible
|
||||
}
|
||||
|
||||
PinchGestureHandler {
|
||||
direction: PinchGestureHandler.Direction.Contracting
|
||||
fingerCount: 3
|
||||
onActivated: effect.visible = !effect.visible
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"KPackageStructure": "KWin/Effect",
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "user@example.com",
|
||||
"Name": "Real Name"
|
||||
}
|
||||
],
|
||||
"Category": "Appearance",
|
||||
"Description": "Quick Effect",
|
||||
"EnabledByDefault": true,
|
||||
"Id": "quick-effect",
|
||||
"License": "GPL",
|
||||
"Name": "Quick Effect"
|
||||
},
|
||||
"X-KDE-Ordering": 60,
|
||||
"X-KDE-PluginKeyword": "quick-effect",
|
||||
"X-Plasma-API": "declarativescript"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
SPDX-FileCopyrightText: None
|
||||
SPDX-License-Identifier: CC0-1.0
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "scripting/scriptedquicksceneeffect.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <KConfigGroup>
|
||||
#include <KConfigLoader>
|
||||
|
||||
#include <QFile>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
ScriptedQuickSceneEffect::ScriptedQuickSceneEffect()
|
||||
{
|
||||
m_visibleTimer.setSingleShot(true);
|
||||
connect(&m_visibleTimer, &QTimer::timeout, this, [this]() {
|
||||
setRunning(false);
|
||||
});
|
||||
}
|
||||
|
||||
ScriptedQuickSceneEffect::~ScriptedQuickSceneEffect()
|
||||
{
|
||||
}
|
||||
|
||||
int ScriptedQuickSceneEffect::requestedEffectChainPosition() const
|
||||
{
|
||||
return m_requestedEffectChainPosition;
|
||||
}
|
||||
|
||||
void ScriptedQuickSceneEffect::setMetaData(const KPluginMetaData &metaData)
|
||||
{
|
||||
m_requestedEffectChainPosition = metaData.value(QStringLiteral("X-KDE-Ordering"), 50);
|
||||
|
||||
KConfigGroup cg = kwinApp()->config()->group(QStringLiteral("Effect-%1").arg(metaData.pluginId()));
|
||||
const QString configFilePath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("kwin/effects/") + metaData.pluginId() + QLatin1String("/contents/config/main.xml"));
|
||||
if (configFilePath.isNull()) {
|
||||
m_configLoader = new KConfigLoader(cg, nullptr, this);
|
||||
} else {
|
||||
QFile xmlFile(configFilePath);
|
||||
m_configLoader = new KConfigLoader(cg, &xmlFile, this);
|
||||
m_configLoader->load();
|
||||
}
|
||||
|
||||
m_configuration = new KConfigPropertyMap(m_configLoader, this);
|
||||
connect(m_configLoader, &KConfigLoader::configChanged, this, &ScriptedQuickSceneEffect::configurationChanged);
|
||||
}
|
||||
|
||||
bool ScriptedQuickSceneEffect::isVisible() const
|
||||
{
|
||||
return m_isVisible;
|
||||
}
|
||||
|
||||
void ScriptedQuickSceneEffect::setVisible(bool visible)
|
||||
{
|
||||
if (m_isVisible == visible) {
|
||||
return;
|
||||
}
|
||||
m_isVisible = visible;
|
||||
|
||||
if (m_isVisible) {
|
||||
m_visibleTimer.stop();
|
||||
setRunning(true);
|
||||
} else {
|
||||
// Delay setRunning(false) to avoid destroying views while still executing JS code.
|
||||
m_visibleTimer.start();
|
||||
}
|
||||
|
||||
Q_EMIT visibleChanged();
|
||||
}
|
||||
|
||||
KConfigPropertyMap *ScriptedQuickSceneEffect::configuration() const
|
||||
{
|
||||
return m_configuration;
|
||||
}
|
||||
|
||||
QQmlListProperty<QObject> ScriptedQuickSceneEffect::data()
|
||||
{
|
||||
return QQmlListProperty<QObject>(this, nullptr,
|
||||
data_append,
|
||||
data_count,
|
||||
data_at,
|
||||
data_clear);
|
||||
}
|
||||
|
||||
void ScriptedQuickSceneEffect::data_append(QQmlListProperty<QObject> *objects, QObject *object)
|
||||
{
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptedQuickSceneEffect *effect = static_cast<ScriptedQuickSceneEffect *>(objects->object);
|
||||
if (!effect->m_children.contains(object)) {
|
||||
object->setParent(effect);
|
||||
effect->m_children.append(object);
|
||||
}
|
||||
}
|
||||
|
||||
qsizetype ScriptedQuickSceneEffect::data_count(QQmlListProperty<QObject> *objects)
|
||||
{
|
||||
ScriptedQuickSceneEffect *effect = static_cast<ScriptedQuickSceneEffect *>(objects->object);
|
||||
return effect->m_children.count();
|
||||
}
|
||||
|
||||
QObject *ScriptedQuickSceneEffect::data_at(QQmlListProperty<QObject> *objects, qsizetype index)
|
||||
{
|
||||
ScriptedQuickSceneEffect *effect = static_cast<ScriptedQuickSceneEffect *>(objects->object);
|
||||
return effect->m_children.value(index);
|
||||
}
|
||||
|
||||
void ScriptedQuickSceneEffect::data_clear(QQmlListProperty<QObject> *objects)
|
||||
{
|
||||
ScriptedQuickSceneEffect *effect = static_cast<ScriptedQuickSceneEffect *>(objects->object);
|
||||
while (!effect->m_children.isEmpty()) {
|
||||
QObject *child = effect->m_children.takeLast();
|
||||
child->setParent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
#include "moc_scriptedquicksceneeffect.cpp"
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libkwineffects/kwinquickeffect.h"
|
||||
|
||||
#include <KConfigPropertyMap>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
class KConfigLoader;
|
||||
class KConfigPropertyMap;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
/**
|
||||
* The SceneEffect type provides a way to implement effects that replace the default scene with
|
||||
* a custom one.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* SceneEffect {
|
||||
* id: root
|
||||
*
|
||||
* delegate: Rectangle {
|
||||
* color: "blue"
|
||||
* }
|
||||
*
|
||||
* ShortcutHandler {
|
||||
* name: "Toggle Effect"
|
||||
* text: i18n("Toggle Effect")
|
||||
* sequence: "Meta+E"
|
||||
* onActivated: root.visible = !root.visible;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class ScriptedQuickSceneEffect : public QuickSceneEffect
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
|
||||
Q_CLASSINFO("DefaultProperty", "data")
|
||||
|
||||
/**
|
||||
* The key-value store with the effect settings.
|
||||
*/
|
||||
Q_PROPERTY(KConfigPropertyMap *configuration READ configuration NOTIFY configurationChanged)
|
||||
|
||||
/**
|
||||
* Whether the effect is shown. Setting this property to @c true activates the effect; setting
|
||||
* this property to @c false will deactivate the effect and the screen views will be unloaded at
|
||||
* the next available time.
|
||||
*/
|
||||
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
|
||||
|
||||
public:
|
||||
explicit ScriptedQuickSceneEffect();
|
||||
~ScriptedQuickSceneEffect() override;
|
||||
|
||||
void setMetaData(const KPluginMetaData &metaData);
|
||||
|
||||
int requestedEffectChainPosition() const override;
|
||||
|
||||
bool isVisible() const;
|
||||
void setVisible(bool visible);
|
||||
|
||||
QQmlListProperty<QObject> data();
|
||||
KConfigPropertyMap *configuration() const;
|
||||
|
||||
static void data_append(QQmlListProperty<QObject> *objects, QObject *object);
|
||||
static qsizetype data_count(QQmlListProperty<QObject> *objects);
|
||||
static QObject *data_at(QQmlListProperty<QObject> *objects, qsizetype index);
|
||||
static void data_clear(QQmlListProperty<QObject> *objects);
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleChanged();
|
||||
void configurationChanged();
|
||||
|
||||
private:
|
||||
KConfigLoader *m_configLoader = nullptr;
|
||||
KConfigPropertyMap *m_configuration = nullptr;
|
||||
QObjectList m_children;
|
||||
QTimer m_visibleTimer;
|
||||
bool m_isVisible = false;
|
||||
int m_requestedEffectChainPosition = 0;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
Loading…
Reference in New Issue