Add package, setup, and uninstall scripts, fix user-local setup, working on SteamOS

This commit is contained in:
wheaney 2025-08-24 15:26:07 -07:00
parent 37ecb879dd
commit 705d940a0d
17 changed files with 328 additions and 55 deletions

73
bin/breezy_kwin_setup Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env bash
# This setup script should do the minimum work required to download the release package, unzip it, and kick off the
# setup script contained within.
# exit when any command fails
set -e
if [ "$(id -u)" == "0" ]; then
echo "This script must not be run as root" 1>&2
exit 1
fi
check_command() {
if ! command -v "$1" &>/dev/null; then
echo "Please install \"$1\" and make sure it's available in your \$PATH, then rerun the setup."
exit 1
fi
}
check_command "curl"
ARCH=$(uname -m)
FILE_NAME="breezyKWin-$ARCH.tar.gz"
LATEST_RELEASE=$(curl -s "https://api.github.com/repos/wheaney/breezy-desktop/releases/latest")
echo "Performing setup for KWin ($ARCH)"
start_dir=$(pwd)
# create temp directory
tmp_dir=$(mktemp -d -t breezy-kwin-XXXXXXXXXX)
pushd $tmp_dir > /dev/null
echo "Created temp directory: ${tmp_dir}"
binary_download_url="https://github.com/wheaney/breezy-desktop/releases/latest/download/$FILE_NAME"
if [ "$1" = "-v" ]
then
metrics_version="$2"
binary_path_arg="$3"
elif [ "$1" = "--tag" ] && [ -n "$2" ]
then
binary_download_url="https://github.com/wheaney/breezy-desktop/releases/download/$2/$FILE_NAME"
else
binary_path_arg="$1"
fi
if [ -z "$binary_path_arg" ]
then
# download and unzip the binary
echo "Downloading to: ${tmp_dir}/$FILE_NAME"
curl -L "$binary_download_url" > "$FILE_NAME"
else
FILE_NAME=$(basename $binary_path_arg)
if [[ "$binary_path_arg" = /* ]]; then
abs_path="$binary_path_arg"
else
# Convert relative path to absolute path
abs_path=$(realpath "$start_dir/$binary_path_arg")
fi
cp $abs_path $tmp_dir
fi
echo "Extracting to: ${tmp_dir}/breezy_kwin"
tar -xf $FILE_NAME
pushd breezy_kwin > /dev/null
# run the setup script that comes with this release
bin/setup $metrics_version
echo "Deleting temp directory: ${tmp_dir}"
rm -rf $tmp_dir
cd "$(dirs -l -0)" && dirs -c

73
bin/package_kwin Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env bash
# exit when any command fails
set -e
ARCH=${ARCH:-$(uname -m)}
# https://stackoverflow.com/a/246128
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
ROOT_DIR=$(realpath $SCRIPT_DIR/..)
XR_DRIVER_DIR=$ROOT_DIR/modules/XRLinuxDriver
echo "Building Breezy KWin for $ARCH"
KWIN_DIR=$ROOT_DIR/kwin
BUILD_FILE_NAME=breezyKWin-$ARCH.tar.gz
TMP_DIR=$(mktemp -d -t breezy-kwin-XXXXXXXXXX)
PACKAGE_DIR=$TMP_DIR/breezy_kwin
mkdir -p $PACKAGE_DIR
source $XR_DRIVER_DIR/bin/inject_ua
# copy vulkan setup scripts and configs
mkdir -p $PACKAGE_DIR/bin
copy_and_inject_ua "$XR_DRIVER_DIR/bin/ua.sh" "$PACKAGE_DIR/bin" "$KWIN_DIR/bin/setup" "$KWIN_DIR/bin/breezy_kwin_uninstall"
XR_DRIVER_BINARY=$XR_DRIVER_DIR/out/xrDriver-$ARCH.tar.gz
if [ ! -e "$XR_DRIVER_BINARY" ] || [ "$1" == "--rebuild-driver" ] || [ "$1" == "--rebuild-all" ]; then
# if a file exists at custom_banner_config.yml, copy it to the xrealAirLinuxDriver directory
if [ -e "$VULKAN_DIR/custom_banner_config.yml" ]; then
cp $VULKAN_DIR/custom_banner_config.yml $XR_DRIVER_DIR
fi
pushd $XR_DRIVER_DIR
# strange issue where the base library produces a .so file if the build is not cleaned
rm -rf build/
docker-build/init.sh
docker-build/run-build.sh $ARCH
popd
fi
XR_DRIVER_TMP_DIR=$(mktemp -d -t xr-driver-XXXXXXXXXX)
pushd $XR_DRIVER_TMP_DIR
cp $XR_DRIVER_BINARY $XR_DRIVER_TMP_DIR/xrDriver.tar.gz
tar -xf $XR_DRIVER_TMP_DIR/xrDriver.tar.gz
XR_DRIVER_MANIFEST_LINE=$(sha256sum xr_driver/manifest)
popd
rm -rf $XR_DRIVER_TMP_DIR
cp $XR_DRIVER_BINARY $PACKAGE_DIR/xrDriver.tar.gz
cp $XR_DRIVER_DIR/bin/xr_driver_setup $PACKAGE_DIR/bin
pushd $KWIN_DIR
docker-build/init.sh
docker-build/run-build.sh $ARCH
popd
cp $KWIN_DIR/out/breezyKWinPlugin-$ARCH.tar.gz $PACKAGE_DIR/breezyKWinPlugin.tar.gz
pushd $TMP_DIR
tar -zcvf $BUILD_FILE_NAME breezy_kwin
popd
mkdir -p out
if [ -e "out/$BUILD_FILE_NAME" ]; then
rm out/$BUILD_FILE_NAME
fi
cp $TMP_DIR/$BUILD_FILE_NAME out
rm -rf $TMP_DIR

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(breezy_desktop_kwin_plugin VERSION 0.0.1 LANGUAGES CXX)
project(breezy_desktop VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

View File

@ -0,0 +1,60 @@
#!/usr/bin/env bash
for_install=0
if [[ -n "$1" ]] && [[ "$1" == "--for-install" ]]; then
for_install=1
fi
# we don't want the uninstall script to be able to cause a failure if being triggered by the setup script
[ "$for_install" -eq 0 ] && set -e
USER_HOME=$(realpath ~)
if [ "$for_install" -eq 0 ]; then
UA_EVENT_NAME="breezy_kwin_uninstall"
UA_CLIENT_ID="BreezyKWin"
#INJECT_UA_CALL
fi
if [ -z "$XDG_BIN_HOME" ]; then
XDG_BIN_HOME="$USER_HOME/.local/bin"
fi
if [ -z "$XDG_DATA_HOME" ]; then
XDG_DATA_HOME="$USER_HOME/.local/share"
fi
if [ -z "$LIB_HOME" ]; then
LIB_HOME="$USER_HOME/.local/lib"
fi
EFFECT_ID="breezy_desktop"
EFFECT_DIR="$XDG_DATA_HOME/kwin/effects/$EFFECT_ID"
PLUGIN_SO="$LIB_HOME/qt6/plugins/kwin/effects/plugins/${EFFECT_ID}.so"
CONFIG_SO="$LIB_HOME/qt6/plugins/kwin/effects/configs/${EFFECT_ID}_config.so"
if [[ -d "$EFFECT_DIR" ]]; then
[ "$for_install" -eq 0 ] && echo "Removing $EFFECT_DIR and its contents"
$SUDO rm -rf "$EFFECT_DIR"
fi
if [[ -f "$PLUGIN_SO" ]]; then
[ "$for_install" -eq 0 ] && echo "Removing $PLUGIN_SO"
$SUDO rm -f "$PLUGIN_SO"
fi
if [[ -f "$CONFIG_SO" ]]; then
[ "$for_install" -eq 0 ] && echo "Removing $CONFIG_SO"
$SUDO rm -f "$CONFIG_SO"
fi
if [ -e "$XDG_BIN_HOME/xr_driver_uninstall" ]; then
[ "$for_install" -eq 0 ] && echo "Uninstalling XRLinuxDriver"
if [ "$for_install" -eq 1 ]; then
sudo $XDG_BIN_HOME/xr_driver_uninstall --for-install
else
sudo $XDG_BIN_HOME/xr_driver_uninstall
fi
fi
# this script is self-deleting, leave this as the last command
rm -f $XDG_BIN_HOME/breezy_kwin_uninstall

View File

@ -7,6 +7,7 @@ ARCH=${ARCH:-$(uname -m)}
echo "Building Breezy KWin plugin for $ARCH"
BUILD_PATH=build
rm -rf $BUILD_PATH
mkdir $BUILD_PATH
pushd $BUILD_PATH
@ -16,7 +17,4 @@ cpack -G TGZ
popd
mkdir -p out
cp $BUILD_PATH/breezy_desktop_kwin_plugin.tar.gz out/breezyKWin-$ARCH.tar.gz
# build artifacts are needed for IDE header awareness with generated code
# rm -rf $BUILD_PATH
cp $BUILD_PATH/breezy_desktop.tar.gz out/breezyKWinPlugin-$ARCH.tar.gz

79
kwin/bin/setup Executable file
View File

@ -0,0 +1,79 @@
#!/usr/bin/env bash
set -e
if [ "$XDG_SESSION_TYPE" != "wayland" ]; then
printf "\033[1;33mWARNING:\033[0m Windowing system is %s\n" "$XDG_SESSION_TYPE"
printf "\033[1;33mWARNING:\033[0m Virtual display functionality requires Wayland\n"
fi
USER_HOME=$(realpath ~)
if [ -z "$XDG_BIN_HOME" ]; then
XDG_BIN_HOME="$USER_HOME/.local/bin"
fi
if [ -d "$XDG_BIN_HOME" ]; then
# check ownership and permissions before doing chown and chmod
XDG_BIN_USER=$(stat -c %U $XDG_BIN_HOME)
XDG_BIN_GROUP=$(stat -c %G $XDG_BIN_HOME)
USER=$(whoami)
GROUP=$(id -gn)
if [ "$XDG_BIN_USER" != "$USER" ] || [ "$XDG_BIN_GROUP" != "$GROUP" ]; then
echo "Fixing ownership and permissions of $XDG_BIN_HOME"
sudo chown -R $USER:$GROUP $XDG_BIN_HOME
sudo chmod -R 700 $XDG_BIN_HOME
fi
fi
UA_EVENT_NAME="breezy_kwin_install"
if [ -e "$XDG_BIN_HOME/breezy_kwin_uninstall" ]; then
echo "Cleaning up the previous installation"
# ` || true` will ensure that this can't cause a failure, even with `set -e`
$XDG_BIN_HOME/breezy_kwin_uninstall --for-install || true
UA_EVENT_NAME="breezy_kwin_update"
fi
UA_CLIENT_ID="BreezyKWin"
UA_EVENT_VERSION="$1"
#INJECT_UA_CALL
tar -xf $(pwd)/breezyKWinPlugin.tar.gz
pushd breezy_desktop/usr > /dev/null
# directory structure matches XDG, so just recursive copy
$SUDO cp -r . "$USER_HOME/.local/"
popd
# Install QT_PLUGIN_PATH snippet into ~/.bash_profile if not present
BASH_PROFILE="$HOME/.bash_profile"
QT_PLUGIN_DIR="$HOME/.local/lib/qt6/plugins"
QT_PLUGIN_EXPORT="export QT_PLUGIN_PATH=\"$QT_PLUGIN_DIR\""
if [[ ! -f "$BASH_PROFILE" ]] || ! grep -Fq "$QT_PLUGIN_EXPORT" "$BASH_PROFILE" 2>/dev/null; then
mkdir -p "$(dirname "$BASH_PROFILE")"
cat >> "$BASH_PROFILE" <<EOF
# Added by Breezy Desktop installer: QT plugin path setup
if [ -n "\$QT_PLUGIN_PATH" ]; then
export QT_PLUGIN_PATH="$QT_PLUGIN_DIR:\$QT_PLUGIN_PATH"
else
export QT_PLUGIN_PATH="$QT_PLUGIN_DIR"
fi
EOF
fi
# set up the XR driver using the local binary
echo "Installing xrDriver"
echo "BEGIN - xr_driver_setup"
if [ -z "$1" ]
then
sudo bin/xr_driver_setup $(pwd)/xrDriver.tar.gz
else
sudo bin/xr_driver_setup -v $1 $(pwd)/xrDriver.tar.gz
fi
echo "END - xr_driver_setup"

View File

@ -3,41 +3,34 @@
# docker run --rm -t -v ./:/source -v --platform linux/amd64 "breezy-kwin:amd64"
# docker run --rm -t -v ./:/source -v --platform linux/arm64 "breezy-kwin:arm64"
FROM --platform=$TARGETPLATFORM debian:trixie
FROM --platform=$TARGETPLATFORM ghcr.io/steamdeckhomebrew/holo-base:3.7@sha256:8da120a3e89c750abd0090c0aab86d543a55d667c3002c8d64960f7fd82ccdd6
ARG TARGETPLATFORM
RUN echo "Target platform: $TARGETPLATFORM"
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
RUN pacman -Sy --noconfirm --needed \
ca-certificates \
build-essential \
base-devel \
cmake \
pkg-config \
pkgconf \
git \
curl \
wget \
extra-cmake-modules \
qt6-base-dev \
qt6-base-dev-tools \
qt6-declarative-dev \
qt6-tools-dev \
qt6-tools-dev-tools \
libkf6config-dev \
libkf6configwidgets-dev \
libkf6coreaddons-dev \
libkf6globalaccel-dev \
libkf6i18n-dev \
libkf6kcmutils-dev \
libkf6xmlgui-dev \
libkf6windowsystem-dev \
kwayland-dev \
plasma-wayland-protocols \
libwayland-dev \
kwin-dev \
&& rm -rf /var/lib/apt/lists/*
qt6-base \
qt6-declarative \
qt6-tools \
kconfig \
kconfigwidgets \
kcoreaddons \
kglobalaccel \
ki18n \
kcmutils \
kxmlgui \
kwindowsystem \
kwin \
&& pacman -Scc --noconfirm
WORKDIR /source
CMD bin/package
CMD bin/package_kwin_plugin

View File

@ -19,4 +19,4 @@ fi
echo "Building docker image"
docker buildx build --platform linux/amd64 -f ./docker-build/Dockerfile -t "breezy-kwin:amd64" --load .
docker buildx build --platform linux/arm64 -f ./docker-build/Dockerfile -t "breezy-kwin:arm64" --load .
# docker buildx build --platform linux/arm64 -f ./docker-build/Dockerfile -t "breezy-kwin:arm64" --load .

View File

@ -19,4 +19,4 @@ if [[ "$1" == "aarch64" || -z "$1" ]]; then
fi
# build directory structure is all owned by root because of docker, delete it all now
sudo rm -rf build/
sudo chown -R $USER:$GROUP build/

View File

@ -1,14 +1,14 @@
add_subdirectory(kcm)
kcoreaddons_add_plugin(breezy_desktop_effect INSTALL_NAMESPACE "kwin/effects/plugins/")
target_sources(breezy_desktop_effect PRIVATE
kcoreaddons_add_plugin(breezy_desktop INSTALL_NAMESPACE "kwin/effects/plugins/")
target_sources(breezy_desktop PRIVATE
breezydesktopeffect.cpp
main.cpp
)
kconfig_add_kcfg_files(breezy_desktop_effect breezydesktopconfig.kcfgc)
kconfig_add_kcfg_files(breezy_desktop breezydesktopconfig.kcfgc)
target_include_directories(breezy_desktop_effect PRIVATE /usr/include/kwin)
target_link_libraries(breezy_desktop_effect
target_include_directories(breezy_desktop PRIVATE /usr/include/kwin)
target_link_libraries(breezy_desktop
Qt6::Core
Qt6::Gui
Qt6::Quick
@ -23,5 +23,4 @@ target_link_libraries(breezy_desktop_effect
KWin::kwin
)
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop_effect)
install(FILES metadata.json DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop_effect)
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/breezy_desktop)

View File

@ -4,7 +4,7 @@
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="kwinrc"/>
<group name="Effect-breezy_desktop_effect">
<group name="Effect-breezy_desktop">
<entry name="FocusedDisplayDistance" type="Int">
<default>85</default>
<min>20</min>

View File

@ -69,7 +69,7 @@ BreezyDesktopEffect::BreezyDesktopEffect()
: m_shutdownTimer(new QTimer(this))
{
qCCritical(KWIN_XR) << "\t\t\tBreezy - constructor";
qmlRegisterUncreatableType<BreezyDesktopEffect>("org.kde.kwin.effect.breezy_desktop_effect", 1, 0, "BreezyDesktopEffect", QStringLiteral("BreezyDesktop 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);
connect(m_shutdownTimer, &QTimer::timeout, this, &BreezyDesktopEffect::realDeactivate);
@ -91,7 +91,7 @@ BreezyDesktopEffect::BreezyDesktopEffect()
updateCursorImage();
reconfigure(ReconfigureAll);
setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/breezy_desktop_effect/qml/main.qml"))));
setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/breezy_desktop/qml/main.qml"))));
// Monitor the IMU file for changes, even if it doesn't exist at startup
m_shmDirectoryWatcher = new QFileSystemWatcher(this);
@ -234,7 +234,7 @@ void BreezyDesktopEffect::addVirtualDisplay(QSize size)
++virtualDisplayCount;
QString name = QStringLiteral("BreezyDesktop_VirtualDisplay_%1x%2_%3").arg(size.width()).arg(size.height()).arg(virtualDisplayCount);
QString description = QStringLiteral("Breezy Display %1x%2 (%3)").arg(size.width()).arg(size.height()).arg(virtualDisplayCount);
auto output = KWin::kwinApp()->outputBackend()->createVirtualOutput(name, description, size, 1.0);
auto output = KWin::kwinApp()->outputBackend()->createVirtualOutput(name, size, 1.0);
if (output) {
m_virtualOutputs.append(output);
}

View File

@ -17,7 +17,7 @@
Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr")
static const char EFFECT_GROUP[] = "Effect-breezy_desktop_effect";
static const char EFFECT_GROUP[] = "Effect-breezy_desktop";
void addShortcutAction(KActionCollection *collection, const BreezyShortcuts::Shortcut &shortcut)
{
@ -54,7 +54,7 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
auto actionCollection = new KActionCollection(this, QStringLiteral("kwin"));
actionCollection->setComponentDisplayName(i18n("KWin"));
actionCollection->setConfigGroup(QStringLiteral("breezy_desktop_effect"));
actionCollection->setConfigGroup(QStringLiteral("breezy_desktop"));
actionCollection->setConfigGlobal(true);
addShortcutAction(actionCollection, BreezyShortcuts::TOGGLE);
@ -88,7 +88,7 @@ void BreezyDesktopEffectConfig::save()
updateUnmanagedState();
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus());
interface.reconfigureEffect(QStringLiteral("breezy_desktop_effect"));
interface.reconfigureEffect(QStringLiteral("breezy_desktop"));
}
void BreezyDesktopEffectConfig::defaults()

View File

@ -3,7 +3,7 @@
namespace KWin
{
KWIN_EFFECT_FACTORY_SUPPORTED(BreezyDesktopEffect, "metadata.json", return BreezyDesktopEffect::supported();)
KWIN_EFFECT_FACTORY(BreezyDesktopEffect, "metadata.json")
} // namespace KWin

View File

@ -10,13 +10,9 @@
"Category": "Tools",
"Description": "Breezy Desktop XR Effect",
"EnabledByDefault": true,
"Id": "breezy_desktop_effect",
"Id": "breezy_desktop",
"License": "GPL",
"Name": "Breezy Desktop XR",
"ServiceTypes": [
"KWin/Effect"
]
"Name": "Breezy Desktop XR"
},
"X-Plasma-API-Minimum-Version": "6.0",
"X-KDE-ConfigModule": "breezy_desktop_config"
}

View File

@ -90,7 +90,9 @@ Node {
}
}
FrameAnimation {
Timer {
interval: 500 // 500ms - 2x per second to avoid running this check too frequently
repeat: true
running: true
onTriggered: {
if (breezyDesktop.imuRotations && breezyDesktop.imuRotations.length > 0) {

View File

@ -1,7 +1,7 @@
import QtQuick
import QtQuick3D
import org.kde.kwin as KWinComponents
import org.kde.kwin.effect.breezy_desktop_effect
import org.kde.kwin.effect.breezy_desktop
Item {
id: root