From 705d940a0d4a7bf4ea5c6385d1e37b5a7c5a1d4e Mon Sep 17 00:00:00 2001 From: wheaney <42350981+wheaney@users.noreply.github.com> Date: Sun, 24 Aug 2025 15:26:07 -0700 Subject: [PATCH] Add package, setup, and uninstall scripts, fix user-local setup, working on SteamOS --- bin/breezy_kwin_setup | 73 +++++++++++++++++++++ bin/package_kwin | 73 +++++++++++++++++++++ kwin/CMakeLists.txt | 2 +- kwin/bin/breezy_kwin_uninstall | 60 +++++++++++++++++ kwin/bin/{package => package_kwin_plugin} | 6 +- kwin/bin/setup | 79 +++++++++++++++++++++++ kwin/docker-build/Dockerfile | 43 ++++++------ kwin/docker-build/init.sh | 2 +- kwin/docker-build/run-build.sh | 2 +- kwin/src/CMakeLists.txt | 13 ++-- kwin/src/breezydesktopconfig.kcfg | 2 +- kwin/src/breezydesktopeffect.cpp | 6 +- kwin/src/kcm/breezydesktopeffectkcm.cpp | 6 +- kwin/src/main.cpp | 2 +- kwin/src/metadata.json | 8 +-- kwin/src/qml/BreezyDesktop.qml | 4 +- kwin/src/qml/main.qml | 2 +- 17 files changed, 328 insertions(+), 55 deletions(-) create mode 100755 bin/breezy_kwin_setup create mode 100755 bin/package_kwin create mode 100644 kwin/bin/breezy_kwin_uninstall rename kwin/bin/{package => package_kwin_plugin} (57%) create mode 100755 kwin/bin/setup diff --git a/bin/breezy_kwin_setup b/bin/breezy_kwin_setup new file mode 100755 index 0000000..dcec99f --- /dev/null +++ b/bin/breezy_kwin_setup @@ -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 diff --git a/bin/package_kwin b/bin/package_kwin new file mode 100755 index 0000000..16f8d80 --- /dev/null +++ b/bin/package_kwin @@ -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 \ No newline at end of file diff --git a/kwin/CMakeLists.txt b/kwin/CMakeLists.txt index c3df9a4..8f3f7c6 100644 --- a/kwin/CMakeLists.txt +++ b/kwin/CMakeLists.txt @@ -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) diff --git a/kwin/bin/breezy_kwin_uninstall b/kwin/bin/breezy_kwin_uninstall new file mode 100644 index 0000000..b16003a --- /dev/null +++ b/kwin/bin/breezy_kwin_uninstall @@ -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 \ No newline at end of file diff --git a/kwin/bin/package b/kwin/bin/package_kwin_plugin similarity index 57% rename from kwin/bin/package rename to kwin/bin/package_kwin_plugin index 73fec0a..052cdf1 100755 --- a/kwin/bin/package +++ b/kwin/bin/package_kwin_plugin @@ -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 \ No newline at end of file +cp $BUILD_PATH/breezy_desktop.tar.gz out/breezyKWinPlugin-$ARCH.tar.gz \ No newline at end of file diff --git a/kwin/bin/setup b/kwin/bin/setup new file mode 100755 index 0000000..3cbbdce --- /dev/null +++ b/kwin/bin/setup @@ -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" < - + 85 20 diff --git a/kwin/src/breezydesktopeffect.cpp b/kwin/src/breezydesktopeffect.cpp index 5de06fb..9c26963 100644 --- a/kwin/src/breezydesktopeffect.cpp +++ b/kwin/src/breezydesktopeffect.cpp @@ -69,7 +69,7 @@ BreezyDesktopEffect::BreezyDesktopEffect() : m_shutdownTimer(new QTimer(this)) { qCCritical(KWIN_XR) << "\t\t\tBreezy - constructor"; - qmlRegisterUncreatableType("org.kde.kwin.effect.breezy_desktop_effect", 1, 0, "BreezyDesktopEffect", QStringLiteral("BreezyDesktop cannot be created in QML")); + qmlRegisterUncreatableType("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); } diff --git a/kwin/src/kcm/breezydesktopeffectkcm.cpp b/kwin/src/kcm/breezydesktopeffectkcm.cpp index 8df3273..28e1a3e 100644 --- a/kwin/src/kcm/breezydesktopeffectkcm.cpp +++ b/kwin/src/kcm/breezydesktopeffectkcm.cpp @@ -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() diff --git a/kwin/src/main.cpp b/kwin/src/main.cpp index cdab856..fd243a0 100644 --- a/kwin/src/main.cpp +++ b/kwin/src/main.cpp @@ -3,7 +3,7 @@ namespace KWin { -KWIN_EFFECT_FACTORY_SUPPORTED(BreezyDesktopEffect, "metadata.json", return BreezyDesktopEffect::supported();) +KWIN_EFFECT_FACTORY(BreezyDesktopEffect, "metadata.json") } // namespace KWin diff --git a/kwin/src/metadata.json b/kwin/src/metadata.json index 7bf93f5..9d12756 100644 --- a/kwin/src/metadata.json +++ b/kwin/src/metadata.json @@ -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" } diff --git a/kwin/src/qml/BreezyDesktop.qml b/kwin/src/qml/BreezyDesktop.qml index 7fb0b32..d5e26c9 100644 --- a/kwin/src/qml/BreezyDesktop.qml +++ b/kwin/src/qml/BreezyDesktop.qml @@ -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) { diff --git a/kwin/src/qml/main.qml b/kwin/src/qml/main.qml index 28c8741..6f27755 100644 --- a/kwin/src/qml/main.qml +++ b/kwin/src/qml/main.qml @@ -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