Rename all to Breezy

This commit is contained in:
wheaney 2025-07-03 15:31:02 -07:00
parent faf35e0cd4
commit 47e5fe5e01
14 changed files with 138 additions and 314 deletions

View File

@ -1,111 +0,0 @@
# Cube effect
![Screenshot](data/screenshot.avif)
This is a basic desktop cube effect for KWin. It's primarily intended to help you
impress your friends with what one can do on "Linux."
<p align="center">
<img src="https://raw.githubusercontent.com/zzag/kwin-effects-cube/main/data/demo.gif" />
</p>
## How to use it
Go to desktop effect settings, and enable the Cube effect. Once you've done that,
the Cube effect can be activated by pressing `Meta+C` shortcut.
Note that you will need at least 3 virtual desktops in order to activate the effect.
Key navigation:
- `Escape` - quit the effect
- `Left` and `Right` arrow keys - rotate the cube left or right, respectively
- `Enter`/`Space`/`Return` - switch to the currently viewed desktop
Mouse navigation:
- LMB click - switch to the currently viewed desktop
- Press LMB and drag - rotate the cube
- Wheel up and down - move the cube farther or closer, respectively
## Installation
Arch Linux:
For users who are using KF6/Plasma 6
```sh
yay -S kwin-effects-cube-git
```
For users who are using Plasma 5
```sh
yay -S kwin-effects-cube
```
## Building from Git
You will need the following dependencies to build this effect:
* CMake
* any C++14 enabled compiler
* Qt
- qtbase
- qtdeclarative
- qtquick3d
* libkwineffects
* KDE Frameworks 5:
- Config
- CoreAddons
- Extra CMake Modules
- GlobalAccel
- WindowSystem
On Arch Linux
```sh
sudo pacman -S cmake extra-cmake-modules kwin qt5-quick3d
```
On Fedora
```sh
sudo dnf install cmake extra-cmake-modules kf5-kconfig-devel kf5-kcoreaddons-devel \
kf5-kglobalaccel-devel kf5-ki18n-devel kf5-kwindowsystem-devel kf5-kxmlgui-devel \
kwin-devel libepoxy-devel qt5-qtbase-devel
```
On Ubuntu
```sh
sudo apt install cmake extra-cmake-modules gettext kwin-dev libkf5config-dev \
libkf5configwidgets-dev libkf5coreaddons-dev libkf5globalaccel-dev
libkf5windowsystem-dev libkf5xmlgui-dev qtbase5-dev qtdeclarative5-dev
```
After you installed all the required dependencies, you can build
the effect:
```sh
git clone https://github.com/zzag/kwin-effects-cube.git
cd kwin-effects-cube
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr
cmake --build build --parallel
cmake --install build
```
## Building QtQuick 3D from source code
Note that some distributions (e.g. Ubuntu or Fedora) don't package QtQuick 3D.
If you use such a distro, you will have to build QtQuick 3D from source code.
Go to https://download.qt.io/official_releases/qt/ and download qtquick3d source
tarball (it's in `submodules/` folder) for 5.15, unpack it and run the following commands
```
qmake qtquick3d.pro
make
make install
```

View File

@ -1,10 +1,6 @@
# SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
kcoreaddons_add_plugin(breezy_desktop_effect INSTALL_NAMESPACE "kwin/effects/plugins/") kcoreaddons_add_plugin(breezy_desktop_effect INSTALL_NAMESPACE "kwin/effects/plugins/")
target_sources(breezy_desktop_effect PRIVATE target_sources(breezy_desktop_effect PRIVATE
cubeeffect.cpp breezydesktopeffect.cpp
main.cpp main.cpp
) )
@ -22,4 +18,4 @@ target_link_libraries(breezy_desktop_effect
KWin::kwin KWin::kwin
) )
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/cube) install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop)

View File

@ -1,2 +1,2 @@
#! /usr/bin/env bash #! /usr/bin/env bash
$XGETTEXT `find . -name \*.qml-o -name \*.cpp` -o $podir/kwin_effect_cube.pot $XGETTEXT `find . -name \*.qml-o -name \*.cpp` -o $podir/kwin_effect_breezy_desktop.pot

View File

@ -1,10 +1,4 @@
/* #include "breezydesktopeffect.h"
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "cubeeffect.h"
#include "effect/effect.h" #include "effect/effect.h"
#include "effect/effecthandler.h" #include "effect/effecthandler.h"
@ -22,41 +16,43 @@ Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr")
namespace KWin namespace KWin
{ {
CubeEffect::CubeEffect() BreezyDesktopEffect::BreezyDesktopEffect()
: m_shutdownTimer(new QTimer(this)) : m_shutdownTimer(new QTimer(this))
{ {
qCCritical(KWIN_XR) << "\t\t\tBreezy - constructor"; qCCritical(KWIN_XR) << "\t\t\tBreezy - constructor";
qmlRegisterUncreatableType<CubeEffect>("org.kde.kwin.effect.cube", 1, 0, "CubeEffect", QStringLiteral("Cube cannot be created in QML")); qmlRegisterUncreatableType<BreezyDesktopEffect>("org.kde.kwin.effect.breezy_desktop", 1, 0, "BreezyDesktopEffect", QStringLiteral("BreezyDesktop cannot be created in QML"));
m_shutdownTimer->setSingleShot(true); m_shutdownTimer->setSingleShot(true);
connect(m_shutdownTimer, &QTimer::timeout, this, &CubeEffect::realDeactivate); connect(m_shutdownTimer, &QTimer::timeout, this, &BreezyDesktopEffect::realDeactivate);
connect(effects, &EffectsHandler::screenAboutToLock, this, &CubeEffect::realDeactivate); connect(effects, &EffectsHandler::screenAboutToLock, this, &BreezyDesktopEffect::realDeactivate);
const QKeySequence defaultToggleShortcut = Qt::META | Qt::Key_C; const QKeySequence defaultToggleShortcut = Qt::META | Qt::Key_B;
m_toggleAction = new QAction(this); m_toggleAction = new QAction(this);
m_toggleAction->setObjectName(QStringLiteral("Cube")); m_toggleAction->setObjectName(QStringLiteral("BreezyDesktop"));
m_toggleAction->setText(i18n("Toggle Cube")); m_toggleAction->setText(i18n("Toggle BreezyDesktop"));
KGlobalAccel::self()->setDefaultShortcut(m_toggleAction, {defaultToggleShortcut}); KGlobalAccel::self()->setDefaultShortcut(m_toggleAction, {defaultToggleShortcut});
KGlobalAccel::self()->setShortcut(m_toggleAction, {defaultToggleShortcut}); KGlobalAccel::self()->setShortcut(m_toggleAction, {defaultToggleShortcut});
m_toggleShortcut = KGlobalAccel::self()->shortcut(m_toggleAction); m_toggleShortcut = KGlobalAccel::self()->shortcut(m_toggleAction);
connect(m_toggleAction, &QAction::triggered, this, &CubeEffect::toggle); connect(m_toggleAction, &QAction::triggered, this, &BreezyDesktopEffect::toggle);
connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, [this](QAction *action, const QKeySequence &seq) { connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, [this](QAction *action, const QKeySequence &seq) {
if (action->objectName() == QStringLiteral("Cube")) { if (action->objectName() == QStringLiteral("BreezyDesktop")) {
m_toggleShortcut.clear(); m_toggleShortcut.clear();
m_toggleShortcut.append(seq); m_toggleShortcut.append(seq);
} }
}); });
setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/cube/qml/main.qml")))); setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/breezy_desktop/qml/main.qml"))));
m_xrRotationTimer = new QTimer(this); m_xrRotationTimer = new QTimer(this);
m_xrRotationTimer->setInterval(16); // ~60Hz m_xrRotationTimer->setInterval(16); // ~60Hz
connect(m_xrRotationTimer, &QTimer::timeout, this, &CubeEffect::updateXrRotation); connect(m_xrRotationTimer, &QTimer::timeout, this, &BreezyDesktopEffect::updateXrRotation);
m_xrRotationTimer->start(); m_xrRotationTimer->start();
toggle();
} }
QVariantMap CubeEffect::initialProperties(Output *screen) QVariantMap BreezyDesktopEffect::initialProperties(Output *screen)
{ {
return QVariantMap{ return QVariantMap{
{QStringLiteral("effect"), QVariant::fromValue(this)}, {QStringLiteral("effect"), QVariant::fromValue(this)},
@ -64,32 +60,12 @@ QVariantMap CubeEffect::initialProperties(Output *screen)
}; };
} }
int CubeEffect::requestedEffectChainPosition() const int BreezyDesktopEffect::requestedEffectChainPosition() const
{ {
return 70; return 70;
} }
void CubeEffect::grabbedKeyboardEvent(QKeyEvent *e) void BreezyDesktopEffect::toggle()
{
if (e->type() == QEvent::KeyPress) {
if (m_toggleShortcut.contains(e->key() | e->modifiers())) {
toggle();
return;
}
}
QuickSceneEffect::grabbedKeyboardEvent(e);
}
bool CubeEffect::borderActivated(ElectricBorder border)
{
if (m_borderActivate.contains(border)) {
toggle();
return true;
}
return false;
}
void CubeEffect::toggle()
{ {
if (isRunning()) { if (isRunning()) {
deactivate(); deactivate();
@ -99,7 +75,7 @@ void CubeEffect::toggle()
} }
} }
void CubeEffect::activate() void BreezyDesktopEffect::activate()
{ {
if (effects->isScreenLocked()) { if (effects->isScreenLocked()) {
return; return;
@ -114,7 +90,7 @@ void CubeEffect::activate()
effects->stopMouseInterception(this); effects->stopMouseInterception(this);
} }
void CubeEffect::deactivate() void BreezyDesktopEffect::deactivate()
{ {
if (m_shutdownTimer->isActive()) { if (m_shutdownTimer->isActive()) {
return; return;
@ -130,51 +106,51 @@ void CubeEffect::deactivate()
m_shutdownTimer->start(animationDuration()); m_shutdownTimer->start(animationDuration());
} }
void CubeEffect::realDeactivate() void BreezyDesktopEffect::realDeactivate()
{ {
setRunning(false); setRunning(false);
} }
int CubeEffect::animationDuration() const int BreezyDesktopEffect::animationDuration() const
{ {
return 200; return 200;
} }
qreal CubeEffect::cubeFaceDisplacement() const qreal BreezyDesktopEffect::faceDisplacement() const
{ {
return 100; return 100;
} }
qreal CubeEffect::distanceFactor() const qreal BreezyDesktopEffect::distanceFactor() const
{ {
return 1.5; return 1.5;
} }
bool CubeEffect::mouseInvertedX() const bool BreezyDesktopEffect::mouseInvertedX() const
{ {
return false; return false;
} }
bool CubeEffect::mouseInvertedY() const bool BreezyDesktopEffect::mouseInvertedY() const
{ {
return false; return false;
} }
CubeEffect::BackgroundMode CubeEffect::backgroundMode() const BreezyDesktopEffect::BackgroundMode BreezyDesktopEffect::backgroundMode() const
{ {
return BackgroundMode::Color; return BackgroundMode::Color;
} }
QColor CubeEffect::backgroundColor() const QColor BreezyDesktopEffect::backgroundColor() const
{ {
return QColor(Qt::black); return QColor(Qt::black);
} }
QQuaternion CubeEffect::xrRotation() const { QQuaternion BreezyDesktopEffect::xrRotation() const {
return m_xrRotation; return m_xrRotation;
} }
void CubeEffect::updateXrRotation() { void BreezyDesktopEffect::updateXrRotation() {
const QString shmPath = QStringLiteral("/dev/shm/breezy_desktop_imu"); const QString shmPath = QStringLiteral("/dev/shm/breezy_desktop_imu");
QFile shmFile(shmPath); QFile shmFile(shmPath);
@ -219,6 +195,11 @@ void CubeEffect::updateXrRotation() {
const bool enabled = (enabledFlag != 0) && (version == expectedVersion) && validData; const bool enabled = (enabledFlag != 0) && (version == expectedVersion) && validData;
if (!enabled) { if (!enabled) {
if (isRunning()) {
qCCritical(KWIN_XR) << "\t\t\tBreezy - deactivate due to disabled";
deactivate();
}
return; return;
} }
@ -227,6 +208,11 @@ void CubeEffect::updateXrRotation() {
imuData[2] == 0.0f && imuData[3] == 1.0f); imuData[2] == 0.0f && imuData[3] == 1.0f);
if (imuResetState) { if (imuResetState) {
if (isRunning()) {
qCCritical(KWIN_XR) << "\t\t\tBreezy - deactivate due to reset state";
deactivate();
}
return; return;
} }
@ -235,6 +221,12 @@ void CubeEffect::updateXrRotation() {
if (quat != m_xrRotation) { if (quat != m_xrRotation) {
m_xrRotation = quat; m_xrRotation = quat;
if (!isRunning()) {
qCCritical(KWIN_XR) << "\t\t\tBreezy - activate";
activate();
}
Q_EMIT xrRotationChanged(); Q_EMIT xrRotationChanged();
} }
} }

View File

@ -0,0 +1,78 @@
#pragma once
#include <effect/quickeffect.h>
#include <QAction>
#include <QKeySequence>
#include <QQuaternion>
namespace KWin
{
class BreezyDesktopEffect : public QuickSceneEffect
{
Q_OBJECT
Q_PROPERTY(int animationDuration READ animationDuration NOTIFY animationDurationChanged)
Q_PROPERTY(qreal faceDisplacement READ faceDisplacement NOTIFY faceDisplacementChanged)
Q_PROPERTY(qreal distanceFactor READ distanceFactor NOTIFY distanceFactorChanged)
Q_PROPERTY(bool mouseInvertedX READ mouseInvertedX NOTIFY mouseInvertedXChanged)
Q_PROPERTY(bool mouseInvertedY READ mouseInvertedY NOTIFY mouseInvertedYChanged)
Q_PROPERTY(BackgroundMode backgroundMode READ backgroundMode NOTIFY backgroundModeChanged)
Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundColorChanged)
Q_PROPERTY(QQuaternion xrRotation READ xrRotation NOTIFY xrRotationChanged)
public:
enum class BackgroundMode
{
Color,
Skybox,
};
Q_ENUM(BackgroundMode)
BreezyDesktopEffect();
int requestedEffectChainPosition() const override;
int animationDuration() const;
qreal faceDisplacement() const;
qreal distanceFactor() const;
bool mouseInvertedX() const;
bool mouseInvertedY() const;
BackgroundMode backgroundMode() const;
QColor backgroundColor() const;
QQuaternion xrRotation() const;
public Q_SLOTS:
void activate();
void deactivate();
void toggle();
void updateXrRotation();
Q_SIGNALS:
void faceDisplacementChanged();
void distanceFactorChanged();
void mouseInvertedXChanged();
void mouseInvertedYChanged();
void animationDurationChanged();
void skyboxChanged();
void backgroundModeChanged();
void backgroundColorChanged();
void xrRotationChanged();
protected:
QVariantMap initialProperties(Output *screen) override;
private:
void realDeactivate();
QTimer *m_shutdownTimer;
QAction *m_toggleAction = nullptr;
QList<QKeySequence> m_toggleShortcut;
QList<ElectricBorder> m_borderActivate;
QList<ElectricBorder> m_touchBorderActivate;
QQuaternion m_xrRotation;
QTimer *m_xrRotationTimer = nullptr;
};
} // namespace KWin

View File

@ -1,85 +0,0 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <effect/quickeffect.h>
#include <QAction>
#include <QKeySequence>
#include <QQuaternion>
namespace KWin
{
class CubeEffect : public QuickSceneEffect
{
Q_OBJECT
Q_PROPERTY(int animationDuration READ animationDuration NOTIFY animationDurationChanged)
Q_PROPERTY(qreal cubeFaceDisplacement READ cubeFaceDisplacement NOTIFY cubeFaceDisplacementChanged)
Q_PROPERTY(qreal distanceFactor READ distanceFactor NOTIFY distanceFactorChanged)
Q_PROPERTY(bool mouseInvertedX READ mouseInvertedX NOTIFY mouseInvertedXChanged)
Q_PROPERTY(bool mouseInvertedY READ mouseInvertedY NOTIFY mouseInvertedYChanged)
Q_PROPERTY(BackgroundMode backgroundMode READ backgroundMode NOTIFY backgroundModeChanged)
Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundColorChanged)
Q_PROPERTY(QQuaternion xrRotation READ xrRotation NOTIFY xrRotationChanged)
public:
enum class BackgroundMode {
Color,
Skybox,
};
Q_ENUM(BackgroundMode)
CubeEffect();
int requestedEffectChainPosition() const override;
void grabbedKeyboardEvent(QKeyEvent *e) override;
bool borderActivated(ElectricBorder border) override;
int animationDuration() const;
qreal cubeFaceDisplacement() const;
qreal distanceFactor() const;
bool mouseInvertedX() const;
bool mouseInvertedY() const;
BackgroundMode backgroundMode() const;
QColor backgroundColor() const;
QQuaternion xrRotation() const;
public Q_SLOTS:
void activate();
void deactivate();
void toggle();
void updateXrRotation();
Q_SIGNALS:
void cubeFaceDisplacementChanged();
void distanceFactorChanged();
void mouseInvertedXChanged();
void mouseInvertedYChanged();
void animationDurationChanged();
void skyboxChanged();
void backgroundModeChanged();
void backgroundColorChanged();
void xrRotationChanged();
protected:
QVariantMap initialProperties(Output *screen) override;
private:
void realDeactivate();
QTimer *m_shutdownTimer;
QAction *m_toggleAction = nullptr;
QList<QKeySequence> m_toggleShortcut;
QList<ElectricBorder> m_borderActivate;
QList<ElectricBorder> m_touchBorderActivate;
QQuaternion m_xrRotation;
QTimer *m_xrRotationTimer = nullptr;
};
} // namespace KWin

View File

@ -1,15 +1,9 @@
/* #include "breezydesktopeffect.h"
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "cubeeffect.h"
namespace KWin namespace KWin
{ {
KWIN_EFFECT_FACTORY_SUPPORTED(CubeEffect, "metadata.json", return CubeEffect::supported();) KWIN_EFFECT_FACTORY_SUPPORTED(BreezyDesktopEffect, "metadata.json", return BreezyDesktopEffect::supported();)
} // namespace KWin } // namespace KWin

View File

@ -1,17 +1,9 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick import QtQuick
import QtQuick3D import QtQuick3D
import org.kde.kwin as KWinComponents import org.kde.kwin as KWinComponents
Node { Node {
id: cube
readonly property var supportedModels: [ readonly property var supportedModels: [
"VITURE", "VITURE",
"nreal air", "nreal air",
@ -61,9 +53,8 @@ Node {
} }
Repeater3D { Repeater3D {
id: faceRepeater
model: screens.length model: screens.length
delegate: CubeFace { delegate: BreezyDesktopDisplay {
screen: screens[index] screen: screens[index]
property real screenRotation: { property real screenRotation: {

View File

@ -1,14 +1,8 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick import QtQuick
import QtQuick3D import QtQuick3D
Model { Model {
id: face id: display
required property QtObject screen required property QtObject screen
required property int index required property int index
@ -20,9 +14,9 @@ Model {
lighting: DefaultMaterial.NoLighting lighting: DefaultMaterial.NoLighting
diffuseMap: Texture { diffuseMap: Texture {
sourceItem: DesktopView { sourceItem: DesktopView {
screen: face.screen screen: display.screen
width: face.screen.geometry.width width: display.screen.geometry.width
height: face.screen.geometry.height height: display.screen.geometry.height
} }
} }
} }

View File

@ -1,9 +1,3 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick import QtQuick
import QtQuick3D import QtQuick3D

View File

@ -1,9 +1,3 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick import QtQuick
import org.kde.kwin as KWinComponents import org.kde.kwin as KWinComponents

View File

@ -1,13 +1,7 @@
/*
SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick import QtQuick
import QtQuick3D import QtQuick3D
import org.kde.kwin as KWinComponents import org.kde.kwin as KWinComponents
import org.kde.kwin.effect.cube import org.kde.kwin.effect.breezy_desktop
Item { Item {
id: root id: root
@ -26,13 +20,6 @@ Item {
function stop() { function stop() {
} }
function switchToSelected() {
// const eulerRotation = cameraController.rotation.toEulerAngles();
// const desktop = cube.screenAt(eulerRotation.y);
// KWinComponents.Workspace.currentDesktop = desktop;
// effect.deactivate();
}
View3D { View3D {
id: view id: view
anchors.fill: parent anchors.fill: parent
@ -42,18 +29,18 @@ Item {
fieldOfView: 22.55 fieldOfView: 22.55
} }
Cube { BreezyDesktop {
id: cube id: breezyDesktop
viewportFOVHorizontal: 40.09 viewportFOVHorizontal: 40.09
viewportWidth: 1920 viewportWidth: 1920
viewportHeight: 1080 viewportHeight: 1080
} }
CubeCameraController { CameraController {
id: cameraController id: cameraController
anchors.fill: parent anchors.fill: parent
camera: camera camera: camera
radius: 0.5 * cube.viewportHeight / Math.tan(camera.fieldOfView * Math.PI / 360) radius: 0.5 * breezyDesktop.viewportHeight / Math.tan(camera.fieldOfView * Math.PI / 360)
Behavior on rotation { Behavior on rotation {
enabled: !cameraController.busy && root.animationEnabled enabled: !cameraController.busy && root.animationEnabled