Compare commits

...

19 Commits
v2.9.3 ... main

Author SHA1 Message Date
wheaney a39535c948 Add VITURE Beast monitor names for GNOME and KWin, bump to v2.11.2 2026-08-14 19:55:47 -07:00
wheaney 5fd3a200ff Fix build issues caused by Arch/pacman gcc-libs split; bump to v2.11.1 2026-08-14 19:09:06 -07:00
wheaney 886ce0b9dc Pull in VITURE Beast and unfinished Pro 2 support, bump to v2.11.0 2026-08-14 16:28:16 -07:00
Wayne Heaney 013690580c
Update README.md 2026-06-30 13:49:25 -07:00
Wayne Heaney 595b614bb3
Update README with Breezy Box project info
Added a tip about the Breezy Box project and installation note.
2026-06-25 11:16:08 -07:00
Wayne Heaney f089404b14
Update README.md 2026-06-24 17:14:10 -07:00
Wayne Heaney c914fe7d23
Bump version to 2.9.13
Trigger a CI build to get the SteamOS 3.9 build artifact in the release
2026-05-28 21:11:46 -07:00
wheaney 0df496770c Fix CI release workflow for steamos-3.9 2026-04-27 22:02:18 -07:00
wheaney 01edb1ea58 Attempt to fix mouse summon, v2.9.12 2026-04-27 20:10:16 -07:00
wheaney cf8f4422df Add SteamOS 3.9 build support, lock in docker image hashes 2026-04-27 20:06:07 -07:00
wheaney 3ba62cfaf4 Fix another release workflow failure, v2.9.11 2026-03-20 13:38:30 -07:00
wheaney 3e9e6fed1e Fix release workflow failure, v2.9.10 2026-03-20 13:37:13 -07:00
wheaney 18f44a7b25 Add support for separate SteamOS builds, supporting 3.7 and 3.8 currently, v2.9.9 2026-03-20 13:35:41 -07:00
wheaney 2f165981a9 Add support for GNOME 50, v2.9.8 2026-03-19 10:51:10 -07:00
wheaney 557f450782 Fix missing verify line for breezy_vulkan_logs 2026-03-17 10:43:32 -07:00
wheaney 232c47781e Fix display spacing issue caused by display size adjustments, v2.9.7 2026-03-10 13:08:56 -07:00
wheaney e228d8d47a Update state/config polling in the GNOME UI, fix issue where display resolution dropdown was closing on state refresh, v2.9.6 2026-03-10 12:35:21 -07:00
wheaney b3bd2ccddc Fix vulkan setup so directory creation comes after uninstall, v2.9.5 2026-03-07 22:12:34 -08:00
wheaney 3e654f98c9 Update the GNOME uninstall script so it clears the GTK icon cache,
v2.9.4
2026-03-07 12:59:29 -08:00
27 changed files with 296 additions and 148 deletions

View File

@ -148,7 +148,7 @@ jobs:
name: release-artifacts-gnome-aarch64 name: release-artifacts-gnome-aarch64
path: out/*.tar.gz path: out/*.tar.gz
build-kwin-steamos: build-kwin-steamos-3_7:
needs: check-version-change needs: check-version-change
if: needs.check-version-change.outputs.should-release == 'true' if: needs.check-version-change.outputs.should-release == 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -163,16 +163,70 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Build Breezy KWin (steamos) - name: Build Breezy KWin (steamos-3.7)
run: | run: |
STEAMOS=1 bin/package_kwin STEAMOS=3.7 bin/package_kwin
env: env:
UA_API_SECRET: ${{ secrets.UA_API_SECRET }} UA_API_SECRET: ${{ secrets.UA_API_SECRET }}
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: release-artifacts-kwin-steamos name: release-artifacts-kwin-steamos-3.7
path: out/*.tar.gz
build-kwin-steamos-3_8:
needs: check-version-change
if: needs.check-version-change.outputs.should-release == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Breezy KWin (steamos-3.8)
run: |
STEAMOS=3.8 bin/package_kwin
env:
UA_API_SECRET: ${{ secrets.UA_API_SECRET }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts-kwin-steamos-3.8
path: out/*.tar.gz
build-kwin-steamos-3_9:
needs: check-version-change
if: needs.check-version-change.outputs.should-release == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Breezy KWin (steamos-3.9)
run: |
STEAMOS=3.9 bin/package_kwin
env:
UA_API_SECRET: ${{ secrets.UA_API_SECRET }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts-kwin-steamos-3.9
path: out/*.tar.gz path: out/*.tar.gz
build-vulkan-x86_64: build-vulkan-x86_64:
@ -208,7 +262,9 @@ jobs:
- build-libs - build-libs
- build-gnome-x86_64 - build-gnome-x86_64
- build-gnome-aarch64 - build-gnome-aarch64
- build-kwin-steamos - build-kwin-steamos-3_7
- build-kwin-steamos-3_8
- build-kwin-steamos-3_9
- build-vulkan-x86_64 - build-vulkan-x86_64
if: needs.check-version-change.outputs.should-release == 'true' if: needs.check-version-change.outputs.should-release == 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -8,6 +8,9 @@
## What is this? ## What is this?
> [!TIP]
> Interested in an XR desktop for **Windows**, **MacOS**, or **Android**? Star the work-in-progress [Breezy Box](https://github.com/wheaney/breezy-box) project ([watch the demo](https://youtu.be/AwEQXnabRxE)).
This repo contains a collection of tools to enable virtual desktop environments for gaming and productivity on Linux using [supported XR glasses](https://github.com/wheaney/XRLinuxDriver#supported-devices). This repo contains a collection of tools to enable virtual desktop environments for gaming and productivity on Linux using [supported XR glasses](https://github.com/wheaney/XRLinuxDriver#supported-devices).
There are two installations available. **Note: Don't manually install either of these if you're running the Decky plugin on the same machine, as they invalidate each other's installations. This is only temporary.** There are two installations available. **Note: Don't manually install either of these if you're running the Decky plugin on the same machine, as they invalidate each other's installations. This is only temporary.**
@ -16,7 +19,7 @@ There are two installations available. **Note: Don't manually install either of
## Breezy Desktop ## Breezy Desktop
Breezy Desktop is a virtual workspace solution for Linux desktops that use the KDE Plasma 6 or GNOME desktop environments (versions 42 through 49). It supports launching multiple virtual monitors alongside multiple physical monitors. Breezy Desktop is a virtual workspace solution for Linux desktops that use the KDE Plasma 6 or GNOME desktop environments (versions 45 through 50). It supports launching multiple virtual monitors alongside multiple physical monitors.
For the best performance, ensure you have the latest graphics drivers installed for your distro. For the best performance, ensure you have the latest graphics drivers installed for your distro.
@ -64,7 +67,7 @@ After setup, you'll have an application called `Breezy Desktop` installed. Launc
### GNOME Setup ### GNOME Setup
Breezy Desktop has best compatibility with GNOME versions 45 through 49. Breezy Desktop has best compatibility with GNOME versions 45 through 50.
**IMPORTANT** - Please read carefully through this list before you get started **IMPORTANT** - Please read carefully through this list before you get started
* **Make sure your glasses are in the [supported devices list](https://github.com/wheaney/XRLinuxDriver#supported-devices)** and are on the latest firmware. * **Make sure your glasses are in the [supported devices list](https://github.com/wheaney/XRLinuxDriver#supported-devices)** and are on the latest firmware.
@ -94,8 +97,6 @@ Breezy GNOME is in AUR. To install, run these commands from a terminal with your
After setup, you'll have an application called `Breezy Desktop` installed. Launch that and follow any instructions. You will need to log out and back in at least once to get the GNOME extension working. You can also configure keyboard shortcuts for the most common toggle actions. The Breezy Desktop app doesn't have to be running to use the virtual desktop or the keyboard shortcuts once you've configured everything to your liking. After setup, you'll have an application called `Breezy Desktop` installed. Launch that and follow any instructions. You will need to log out and back in at least once to get the GNOME extension working. You can also configure keyboard shortcuts for the most common toggle actions. The Breezy Desktop app doesn't have to be running to use the virtual desktop or the keyboard shortcuts once you've configured everything to your liking.
For a double-wide screen, enable "widescreen mode" using the toggle in the Breezy Desktop application. **Note: this can be significantly more resource intensive than non-widescreen, you may notice performance dips on older hardware.**
### Breezy Desktop Pricing ### Breezy Desktop Pricing
Breezy Desktop for GNOME and KDE comes with 2 free trial months. Trial access is granted automatically after setup (no token entry required), and you only need to be online once after setup so your device can activate/refresh access. Breezy Desktop for GNOME and KDE comes with 2 free trial months. Trial access is granted automatically after setup (no token entry required), and you only need to be online once after setup so your device can activate/refresh access.

View File

@ -1 +1 @@
2.9.3 2.11.2

View File

@ -49,7 +49,8 @@ LIBS_ARCH="$ARCH"
if [ -f /etc/os-release ]; then if [ -f /etc/os-release ]; then
. /etc/os-release . /etc/os-release
if [ "$ID" == "steamos" ]; then if [ "$ID" == "steamos" ]; then
ARCH="steamos" IFS=. read -r steamos_major steamos_minor _ <<< "$VERSION_ID"
ARCH="steamos-${steamos_major}.${steamos_minor}"
fi fi
fi fi
FILE_NAME="breezyKWin-$ARCH.tar.gz" FILE_NAME="breezyKWin-$ARCH.tar.gz"
@ -203,7 +204,7 @@ mv breezy_desktop_lib/* breezy_kwin/
pushd breezy_kwin > /dev/null pushd breezy_kwin > /dev/null
# run the setup script that comes with this release # run the setup script that comes with this release
bin/setup $metrics_version ARCH="$ARCH" bin/setup $metrics_version
echo "Deleting temp directory: ${tmp_dir}" echo "Deleting temp directory: ${tmp_dir}"
rm -rf $tmp_dir rm -rf $tmp_dir

View File

@ -7,7 +7,7 @@ ARCH=${ARCH:-$(uname -m)}
BUILD_ARCH=$ARCH BUILD_ARCH=$ARCH
if [ -n "${STEAMOS+x}" ]; then if [ -n "${STEAMOS+x}" ]; then
ARCH="x86_64" ARCH="x86_64"
BUILD_ARCH="steamos" BUILD_ARCH="steamos-$STEAMOS"
fi fi
# https://stackoverflow.com/a/246128 # https://stackoverflow.com/a/246128

View File

@ -44,6 +44,9 @@ rm -f $XDG_DATA_HOME/locale/*/LC_MESSAGES/breezydesktop.mo
rm -f $XDG_BIN_HOME/breezydesktop rm -f $XDG_BIN_HOME/breezydesktop
rm -f $XDG_BIN_HOME/virtualdisplay rm -f $XDG_BIN_HOME/virtualdisplay
[ "$for_install" -eq 0 ] && echo "Clearing Breezy Desktop icons from the GTK icon cache"
gtk-update-icon-cache -f -t "$XDG_DATA_HOME/icons/hicolor" >/dev/null 2>&1 || true
if [ -e "$XDG_BIN_HOME/xr_driver_uninstall" ]; then if [ -e "$XDG_BIN_HOME/xr_driver_uninstall" ]; then
[ "$for_install" -eq 0 ] && echo "Uninstalling XRLinuxDriver" [ "$for_install" -eq 0 ] && echo "Uninstalling XRLinuxDriver"
if [ "$for_install" -eq 1 ]; then if [ "$for_install" -eq 1 ]; then

View File

@ -146,8 +146,8 @@ sed -i -e "s/{bin_dir}/$ESCAPED_XDG_BIN_HOME/g" \
cp bin/breezy_gnome_verify $XDG_BIN_HOME cp bin/breezy_gnome_verify $XDG_BIN_HOME
echo "Copying the manifest file to ${BREEZY_GNOME_DATA_DIR}" echo "Copying the manifest file to ${BREEZY_GNOME_DATA_DIR}"
mkdir -p $BREEZY_GNOME_DATA_DIR mkdir -p "$BREEZY_GNOME_DATA_DIR"
cp manifest $BREEZY_GNOME_DATA_DIR cp manifest "$BREEZY_GNOME_DATA_DIR/manifest"
echo "Installing the breezydesktop@xronlinux.com GNOME extension" echo "Installing the breezydesktop@xronlinux.com GNOME extension"
gnome-extensions install --force breezydesktop@xronlinux.com.shell-extension.zip gnome-extensions install --force breezydesktop@xronlinux.com.shell-extension.zip

View File

@ -334,7 +334,7 @@ export const DeviceDataStream = GObject.registerClass({
} else if (this.breezy_desktop_running !== this.breezy_desktop_actually_running) { } else if (this.breezy_desktop_running !== this.breezy_desktop_actually_running) {
// update the breezy_desktop_running property if the state changes to trigger "notify::" events // update the breezy_desktop_running property if the state changes to trigger "notify::" events
this.breezy_desktop_running = this.breezy_desktop_actually_running; this.breezy_desktop_running = this.breezy_desktop_actually_running;
if (!this.breezy_desktop_running && keepalive_only) { if (!this.breezy_desktop_running) {
this.device_data = null; this.device_data = null;
this.imu_snapshots = null; this.imu_snapshots = null;
} }

View File

@ -5,7 +5,7 @@
"settings-schema": "com.xronlinux.BreezyDesktop", "settings-schema": "com.xronlinux.BreezyDesktop",
"session-modes": ["user"], "session-modes": ["user"],
"shell-version": [ "shell-version": [
"46", "47", "48", "49" "46", "47", "48", "49", "50"
], ],
"url": "https://github.com/wheaney/breezy-desktop" "url": "https://github.com/wheaney/breezy-desktop"
} }

View File

@ -27,6 +27,7 @@ export const NESTED_MONITOR_PRODUCT = 'MetaMonitor';
export const VIRTUAL_MONITOR_PRODUCT = 'Virtual remote monitor'; export const VIRTUAL_MONITOR_PRODUCT = 'Virtual remote monitor';
export const SUPPORTED_MONITOR_PRODUCTS = [ export const SUPPORTED_MONITOR_PRODUCTS = [
'VITURE', 'VITURE',
'VITURE Beast',
'nreal air', 'nreal air',
'Air', 'Air',
'Air 2', 'Air 2',

View File

@ -142,8 +142,14 @@ function findFocusedMonitor(quaternion, position, monitorVectors, currentFocused
* @returns {Object} - containing `begin`, `center`, and `end` radians for rotating the given monitor * @returns {Object} - containing `begin`, `center`, and `end` radians for rotating the given monitor
*/ */
function monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorBeginPixel, monitorLengthPixels, lengthToRadianFn) { function monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorBeginPixel, monitorLengthPixels, lengthToRadianFn) {
let closestWrapPixel = monitorBeginPixel; // Monitor coordinates can become fractional due to size adjustment.
let closestWrap = cachedMonitorRadians[monitorBeginPixel]; // If a monitor edge lands extremely close to a cached pixel key, snap to it;
// otherwise tiny negative gaps can cause us to subtract a full spacing interval.
let beginPixel = monitorBeginPixel;
const pixelEpsilon = Math.max(1e-6, Math.abs(monitorLengthPixels) * 1e-6);
let closestWrapPixel = beginPixel;
let closestWrap = cachedMonitorRadians[beginPixel];
if (closestWrap === undefined) { if (closestWrap === undefined) {
closestWrapPixel = Object.keys(cachedMonitorRadians).reduce((previousPixel, currentPixel) => { closestWrapPixel = Object.keys(cachedMonitorRadians).reduce((previousPixel, currentPixel) => {
if (previousPixel === undefined) return currentPixel; if (previousPixel === undefined) return currentPixel;
@ -167,10 +173,16 @@ function monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorBeginPix
closestWrap = cachedMonitorRadians[closestWrapPixel]; closestWrap = cachedMonitorRadians[closestWrapPixel];
} }
const closestWrapPixelNumber = Number(closestWrapPixel);
if (Number.isFinite(closestWrapPixelNumber) && Math.abs(closestWrapPixelNumber - beginPixel) < pixelEpsilon) {
beginPixel = closestWrapPixelNumber;
closestWrapPixel = closestWrapPixelNumber;
}
const spacingRadians = lengthToRadianFn(monitorSpacingPixels); const spacingRadians = lengthToRadianFn(monitorSpacingPixels);
if (closestWrapPixel !== monitorBeginPixel) { if (closestWrapPixel !== beginPixel) {
// there's a gap between the cached wrap value and this one // there's a gap between the cached wrap value and this one
const gapPixels = monitorBeginPixel - closestWrapPixel; const gapPixels = beginPixel - closestWrapPixel;
const gapRadians = lengthToRadianFn(gapPixels); const gapRadians = lengthToRadianFn(gapPixels);
// use Math.floor so if it's negative (this monitor is to the left of or above the closest) it will always // use Math.floor so if it's negative (this monitor is to the left of or above the closest) it will always
@ -179,7 +191,7 @@ function monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorBeginPix
// update the closestWrap value and cache it // update the closestWrap value and cache it
closestWrap = closestWrap + gapRadians + appliedSpacingRadians; closestWrap = closestWrap + gapRadians + appliedSpacingRadians;
closestWrapPixel = monitorBeginPixel; closestWrapPixel = beginPixel;
cachedMonitorRadians[closestWrapPixel] = closestWrap; cachedMonitorRadians[closestWrapPixel] = closestWrap;
} }
@ -188,7 +200,7 @@ function monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorBeginPix
const endRadians = closestWrap + monitorRadians; const endRadians = closestWrap + monitorRadians;
// since we're computing the end values for this monitor, cache them too in case they line up with a future monitor // since we're computing the end values for this monitor, cache them too in case they line up with a future monitor
const nextMonitorPixel = monitorBeginPixel + monitorLengthPixels; const nextMonitorPixel = beginPixel + monitorLengthPixels;
if (cachedMonitorRadians[nextMonitorPixel] === undefined) if (cachedMonitorRadians[nextMonitorPixel] === undefined)
cachedMonitorRadians[nextMonitorPixel] = endRadians + spacingRadians; cachedMonitorRadians[nextMonitorPixel] = endRadians + spacingRadians;
@ -301,7 +313,7 @@ function monitorsToPlacements(fovDetails, monitorDetailsList, monitorSpacing) {
centerNoRotate: [ centerNoRotate: [
monitorCenterRadius, monitorCenterRadius,
// west is flat when wrapping horizontally // west is flat when wrapping vertically
westCenterPixels, westCenterPixels,
// up is centered about the FOV center // up is centered about the FOV center

View File

@ -14,7 +14,7 @@ check_command "make"
ARCH=${ARCH:-$(uname -m)} ARCH=${ARCH:-$(uname -m)}
if [ -n "${STEAMOS+x}" ]; then if [ -n "${STEAMOS+x}" ]; then
ARCH="steamos" ARCH="steamos-$STEAMOS"
fi fi
echo "Building Breezy KWin plugin for $ARCH" echo "Building Breezy KWin plugin for $ARCH"

View File

@ -8,6 +8,10 @@ if [ "$XDG_SESSION_TYPE" != "wayland" ]; then
fi fi
install_steamos_shortcuts() { install_steamos_shortcuts() {
if [[ "${ARCH:-}" != "steamos-3.7" ]]; then
return
fi
local os_release="/etc/os-release" local os_release="/etc/os-release"
if [[ ! -r "$os_release" ]]; then if [[ ! -r "$os_release" ]]; then
return return

View File

@ -1,37 +0,0 @@
# To run the build from the package root:
# docker buildx build --platform linux/amd64,linux/arm64 -f ./docker-build/Dockerfile -t "breezy-kwin" .
# 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 archlinux:base-20250817.0.405639@sha256:31f0749bdb81517dc8f379feac0a3860b097f1da1f53c8315c1bae0817d6c0a1
ARG TARGETPLATFORM
RUN echo "Target platform: $TARGETPLATFORM"
RUN pacman -Sy --noconfirm --needed \
ca-certificates \
base-devel \
cmake \
pkgconf \
git \
curl \
wget \
extra-cmake-modules \
qt6-base \
qt6-declarative \
qt6-quick3d \
qt6-tools \
kconfig \
kconfigwidgets \
kcoreaddons \
kglobalaccel \
ki18n \
kcmutils \
kxmlgui \
kwindowsystem \
kwin \
&& pacman -Scc --noconfirm
WORKDIR /source
CMD bin/package_kwin_plugin

View File

@ -1,37 +0,0 @@
# To run the build from the package root:
# docker buildx build --platform linux/amd64,linux/arm64 -f ./docker-build/Dockerfile.steamos -t "breezy-kwin-steamos" .
# docker run --rm -t -v ./:/source -v --platform linux/amd64 "breezy-kwin-steamos:amd64"
# docker run --rm -t -v ./:/source -v --platform linux/arm64 "breezy-kwin-steamos:arm64"
FROM --platform=$TARGETPLATFORM ghcr.io/steamdeckhomebrew/holo-base:3.7@sha256:8da120a3e89c750abd0090c0aab86d543a55d667c3002c8d64960f7fd82ccdd6
ARG TARGETPLATFORM
ENV STEAMOS=1
RUN echo "SteamOS build - target platform: $TARGETPLATFORM"
RUN pacman -Sy --noconfirm --needed \
ca-certificates \
base-devel \
cmake \
pkgconf \
git \
curl \
wget \
extra-cmake-modules \
qt6-base \
qt6-declarative \
qt6-tools \
kconfig \
kconfigwidgets \
kcoreaddons \
kglobalaccel \
ki18n \
kcmutils \
kxmlgui \
kwindowsystem \
kwin \
&& pacman -Scc --noconfirm
WORKDIR /source
CMD bin/package_kwin_plugin

View File

@ -0,0 +1,41 @@
# To run the build from the package root:
# docker buildx build --platform linux/amd64,linux/arm64 -f ./docker-build/Dockerfile.steamos-3.7 -t "breezy-kwin-steamos-3.7" .
# docker run --rm -t -v ./:/source -v --platform linux/amd64 "breezy-kwin-steamos-3.7:amd64"
FROM --platform=$TARGETPLATFORM ghcr.io/wheaney/holo-base:3.7.20@sha256:1478200c51b8b287e294de6e98a1ab0fb79333503a5cc5681b58dfd209f17851
ARG TARGETPLATFORM
ENV STEAMOS=3.7
RUN echo "SteamOS 3.7 build - target platform: $TARGETPLATFORM"
# CheckSpace can't stat Docker's read-only /etc/hosts and /etc/resolv.conf bind mounts,
# which aborts the transaction; Arch's own container images disable it for this reason
RUN sed -i 's/^[[:space:]]*CheckSpace/#CheckSpace/' /etc/pacman.conf \
&& pacman -Syu --noconfirm --needed \
ca-certificates \
base-devel \
cmake \
pkgconf \
git \
curl \
wget \
extra-cmake-modules \
qt6-base \
qt6-declarative \
qt6-quick3d \
qt6-tools \
kconfig \
kconfigwidgets \
kcoreaddons \
kglobalaccel \
ki18n \
kcmutils \
kxmlgui \
kwindowsystem \
kwin \
vulkan-headers \
&& pacman -Scc --noconfirm
WORKDIR /source
CMD bin/package_kwin_plugin

View File

@ -0,0 +1,41 @@
# To run the build from the package root:
# docker buildx build --platform linux/amd64,linux/arm64 -f ./docker-build/Dockerfile.steamos-3.8 -t "breezy-kwin-steamos" .
# docker run --rm -t -v ./:/source -v --platform linux/amd64 "breezy-kwin-steamos-3.8:amd64"
FROM --platform=$TARGETPLATFORM ghcr.io/wheaney/holo-base:preview-3.8@sha256:a38cdf4ac0e9022ab55c2078381761b444362cfde63e61d988830b0aafb84850
ARG TARGETPLATFORM
ENV STEAMOS=3.8
RUN echo "SteamOS 3.8 build - target platform: $TARGETPLATFORM"
# CheckSpace can't stat Docker's read-only /etc/hosts and /etc/resolv.conf bind mounts,
# which aborts the transaction; Arch's own container images disable it for this reason
RUN sed -i 's/^[[:space:]]*CheckSpace/#CheckSpace/' /etc/pacman.conf \
&& pacman -Syu --noconfirm --needed \
ca-certificates \
base-devel \
cmake \
pkgconf \
git \
curl \
wget \
extra-cmake-modules \
qt6-base \
qt6-declarative \
qt6-quick3d \
qt6-tools \
kconfig \
kconfigwidgets \
kcoreaddons \
kglobalaccel \
ki18n \
kcmutils \
kxmlgui \
kwindowsystem \
kwin \
vulkan-headers \
&& pacman -Scc --noconfirm
WORKDIR /source
CMD bin/package_kwin_plugin

View File

@ -0,0 +1,41 @@
# To run the build from the package root:
# docker buildx build --platform linux/amd64,linux/arm64 -f ./docker-build/Dockerfile.steamos-3.9 -t "breezy-kwin-steamos" .
# docker run --rm -t -v ./:/source -v --platform linux/amd64 "breezy-kwin-steamos-3.9:amd64"
FROM --platform=$TARGETPLATFORM ghcr.io/wheaney/holo-base:main-3.9@sha256:a9e2c59fb1274cf31d544229134e6bc653f050661dd9b64b05795b964468fcbf
ARG TARGETPLATFORM
ENV STEAMOS=3.9
RUN echo "SteamOS 3.9 build - target platform: $TARGETPLATFORM"
# CheckSpace can't stat Docker's read-only /etc/hosts and /etc/resolv.conf bind mounts,
# which aborts the transaction; Arch's own container images disable it for this reason
RUN sed -i 's/^[[:space:]]*CheckSpace/#CheckSpace/' /etc/pacman.conf \
&& pacman -Syu --noconfirm --needed \
ca-certificates \
base-devel \
cmake \
pkgconf \
git \
curl \
wget \
extra-cmake-modules \
qt6-base \
qt6-declarative \
qt6-quick3d \
qt6-tools \
kconfig \
kconfigwidgets \
kcoreaddons \
kglobalaccel \
ki18n \
kcmutils \
kxmlgui \
kwindowsystem \
kwin \
vulkan-headers \
&& pacman -Scc --noconfirm
WORKDIR /source
CMD bin/package_kwin_plugin

View File

@ -18,6 +18,6 @@ else
fi fi
echo "Building docker image" echo "Building docker image"
# docker buildx build --platform linux/amd64 -f ./docker-build/Dockerfile -t "breezy-kwin:amd64" --load . docker buildx build --platform linux/amd64 -f ./docker-build/Dockerfile.steamos-3.7 -t "breezy-kwin-steamos-3.7:amd64" --load .
# docker buildx build --platform linux/arm64 -f ./docker-build/Dockerfile -t "breezy-kwin:arm64" --load . docker buildx build --platform linux/amd64 -f ./docker-build/Dockerfile.steamos-3.8 -t "breezy-kwin-steamos-3.8:amd64" --load .
docker buildx build --platform linux/amd64 -f ./docker-build/Dockerfile.steamos -t "breezy-kwin-steamos:amd64" --load . docker buildx build --platform linux/amd64 -f ./docker-build/Dockerfile.steamos-3.9 -t "breezy-kwin-steamos-3.9:amd64" --load .

View File

@ -5,22 +5,10 @@ set -e
USER=${SUDO_USER:-$USER} USER=${SUDO_USER:-$USER}
GROUP=$(id -gn $USER) GROUP=$(id -gn $USER)
# Run containers for each architecture # only SteamOS is pre-built
if [[ "$1" == "x86_64" || -z "$1" ]]; then if [[ "$1" == steamos-* || -z "$1" ]]; then
sudo rm -rf build/ sudo rm -rf build/
docker run --rm -t -v ./:/source --platform linux/amd64 "breezy-kwin:amd64" docker run --rm -t -v ./:/source --platform linux/amd64 "breezy-kwin-$1:amd64"
sudo chown -R $USER:$GROUP out/
fi
if [[ "$1" == "aarch64" || -z "$1" ]]; then
sudo rm -rf build/
docker run --rm -t -v ./:/source --platform linux/arm64 "breezy-kwin:arm64"
sudo chown -R $USER:$GROUP out/
fi
if [[ "$1" == "steamos" || -z "$1" ]]; then
sudo rm -rf build/
docker run --rm -t -v ./:/source --platform linux/amd64 "breezy-kwin-steamos:amd64"
sudo chown -R $USER:$GROUP out/ sudo chown -R $USER:$GROUP out/
fi fi

View File

@ -2,6 +2,7 @@
#include "core/rendertarget.h" #include "core/rendertarget.h"
#include "core/renderviewport.h" #include "core/renderviewport.h"
#include "cursor.h" #include "cursor.h"
#include "input.h"
#include "pointer_input.h" #include "pointer_input.h"
#include "kcm/shortcuts.h" #include "kcm/shortcuts.h"
#include "breezydesktopeffect.h" #include "breezydesktopeffect.h"
@ -1005,10 +1006,28 @@ void BreezyDesktopEffect::warpPointerToOutputCenter(ScreenOutput *output)
} }
const QRect geometry = output->geometry(); const QRect geometry = output->geometry();
const QPointF center = geometry.center(); const QPointF center = geometry.center();
Cursors::self()->mouse()->setPos(center);
// When warping, we don't have a meaningful previous position; use center for both. bool warped = false;
evaluateCursorOnScreenState(center, center); if (InputRedirection *inputRedirection = input(); inputRedirection && inputRedirection->supportsPointerWarping()) {
inputRedirection->warpPointer(center);
warped = true;
} else if (auto *mouseCursor = Cursors::self()->mouse(); mouseCursor) {
mouseCursor->setPos(center);
warped = true;
}
if (!warped) {
return;
}
const QPointF newPos = center - effects->cursorImage().hotSpot();
const QPointF prevPos = m_cursorPos;
if (m_cursorPos != newPos) {
m_cursorPos = newPos;
Q_EMIT cursorPosChanged();
}
evaluateCursorOnScreenState(prevPos, newPos);
} }
void BreezyDesktopEffect::moveCursorToFocusedDisplay() void BreezyDesktopEffect::moveCursorToFocusedDisplay()

View File

@ -10,6 +10,7 @@ Item {
readonly property var supportedModels: [ readonly property var supportedModels: [
"VITURE", "VITURE",
"VITURE Beast",
"nreal air", "nreal air",
"Air", "Air",
"Air 2", "Air 2",

@ -1 +1 @@
Subproject commit 33f15b0e15b141e7664afcc4c09d2c19b62716c0 Subproject commit dd0d592130b7fb8bc0923d2df6238e0c6a8b419b

View File

@ -1,6 +1,5 @@
import sys import sys
import threading from gi.repository import GObject, GLib
from gi.repository import GObject
from .xrdriveripc import XRDriverIPC from .xrdriveripc import XRDriverIPC
class ConfigManager(GObject.GObject): class ConfigManager(GObject.GObject):
@ -60,10 +59,15 @@ class ConfigManager(GObject.GObject):
self.neck_saver_horizontal_multiplier = None self.neck_saver_horizontal_multiplier = None
self.neck_saver_vertical_multiplier = None self.neck_saver_vertical_multiplier = None
self._running = True self._running = True
self._refresh_source_id = None
self._refresh_config() self._refresh_config()
self._refresh_source_id = GLib.timeout_add_seconds(1, self._refresh_config)
def stop(self): def stop(self):
self._running = False self._running = False
if self._refresh_source_id is not None:
GLib.source_remove(self._refresh_source_id)
self._refresh_source_id = None
def _refresh_config(self): def _refresh_config(self):
self.config = self.ipc.retrieve_config(False) self.config = self.ipc.retrieve_config(False)
@ -91,7 +95,7 @@ class ConfigManager(GObject.GObject):
if self.config['neck_saver_vertical_multiplier'] != self.neck_saver_vertical_multiplier: if self.config['neck_saver_vertical_multiplier'] != self.neck_saver_vertical_multiplier:
self.set_property('neck-saver-vertical-multiplier', self.config['neck_saver_vertical_multiplier']) self.set_property('neck-saver-vertical-multiplier', self.config['neck_saver_vertical_multiplier'])
if self._running: threading.Timer(1.0, self._refresh_config).start() return self._running
def _is_breezy_desktop_enabled(self): def _is_breezy_desktop_enabled(self):
return self.config.get('disabled') == False and 'breezy_desktop' in self.config.get('external_mode', []) return self.config.get('disabled') == False and 'breezy_desktop' in self.config.get('external_mode', [])

View File

@ -1,6 +1,5 @@
import sys import sys
import threading from gi.repository import GObject, GLib
from gi.repository import GObject
from .time import LICENSE_WARN_SECONDS from .time import LICENSE_WARN_SECONDS
from .xrdriveripc import XRDriverIPC from .xrdriveripc import XRDriverIPC
@ -66,14 +65,21 @@ class StateManager(GObject.GObject):
self.connected_device_full_distance_cm = 0.0 self.connected_device_full_distance_cm = 0.0
self.connected_device_full_size_cm = 0.0 self.connected_device_full_size_cm = 0.0
self._running = True self._running = True
self._refresh_source_id = None
self._refresh_state() self._refresh_state()
self._refresh_source_id = GLib.timeout_add_seconds(1, self._refresh_state)
def stop(self): def stop(self):
self._running = False self._running = False
if self._refresh_source_id is not None:
GLib.source_remove(self._refresh_source_id)
self._refresh_source_id = None
def _refresh_state(self): def _refresh_state(self):
self.state = self.ipc.retrieve_driver_state() self.state = self.ipc.retrieve_driver_state()
self.set_property('driver-running', self.state['ui_view'].get('driver_running')) driver_running = self.state['ui_view'].get('driver_running')
if driver_running != self.driver_running:
self.set_property('driver-running', driver_running)
new_device_name = StateManager.device_name(self.state) new_device_name = StateManager.device_name(self.state)
if self.connected_device_name != new_device_name: if self.connected_device_name != new_device_name:
@ -100,10 +106,21 @@ class StateManager(GObject.GObject):
# only update these properties if a device is still connected # only update these properties if a device is still connected
if (self.connected_device_name): if (self.connected_device_name):
self.set_property('follow-mode', self.state.get('breezy_desktop_smooth_follow_enabled', False)) follow_mode = self.state.get('breezy_desktop_smooth_follow_enabled', False)
self.set_property('device-supports-sbs', self.state.get('sbs_mode_supported', False)) if follow_mode != self.follow_mode:
self.set_property('widescreen-mode', self.state.get('sbs_mode_enabled', False)) self.set_property('follow-mode', follow_mode)
self.set_property('connected-device-pose-has-position', self.state.get('connected_device_pose_has_position', False) == True)
device_supports_sbs = self.state.get('sbs_mode_supported', False)
if device_supports_sbs != self.device_supports_sbs:
self.set_property('device-supports-sbs', device_supports_sbs)
widescreen_mode = self.state.get('sbs_mode_enabled', False)
if widescreen_mode != self.widescreen_mode:
self.set_property('widescreen-mode', widescreen_mode)
pose_has_position = (self.state.get('connected_device_pose_has_position', False) == True)
if pose_has_position != self.connected_device_pose_has_position:
self.set_property('connected-device-pose-has-position', pose_has_position)
full_distance = self.state.get('connected_device_full_distance_cm') or 0.0 full_distance = self.state.get('connected_device_full_distance_cm') or 0.0
if full_distance != self.connected_device_full_distance_cm: if full_distance != self.connected_device_full_distance_cm:
@ -113,7 +130,7 @@ class StateManager(GObject.GObject):
if full_size != self.connected_device_full_size_cm: if full_size != self.connected_device_full_size_cm:
self.set_property('connected-device-full-size-cm', full_size) self.set_property('connected-device-full-size-cm', full_size)
if self._running: threading.Timer(1.0, self._refresh_state).start() return self._running
def do_set_property(self, prop, value): def do_set_property(self, prop, value):
if prop.name == 'driver-running': if prop.name == 'driver-running':

View File

@ -6,6 +6,7 @@ set -e
declare -A file_paths declare -A file_paths
file_paths=( file_paths=(
["bin/breezy_vulkan_uninstall"]="{bin_dir}/breezy_vulkan_uninstall" ["bin/breezy_vulkan_uninstall"]="{bin_dir}/breezy_vulkan_uninstall"
["bin/breezy_vulkan_logs"]="{bin_dir}/breezy_vulkan_logs"
["vkBasalt.64/libvkbasalt.so"]="{lib_dir}/libvkbasalt.so" ["vkBasalt.64/libvkbasalt.so"]="{lib_dir}/libvkbasalt.so"
["vkBasalt.32/libvkbasalt.so"]="{lib32_dir}/libvkbasalt.so" ["vkBasalt.32/libvkbasalt.so"]="{lib32_dir}/libvkbasalt.so"
["Sombrero.frag"]="{reshade_config_dir}/Shaders/Sombrero.frag" ["Sombrero.frag"]="{reshade_config_dir}/Shaders/Sombrero.frag"

View File

@ -14,9 +14,6 @@ if [ -z "$XDG_DATA_HOME" ]; then
XDG_DATA_HOME="$USER_HOME/.local/share" XDG_DATA_HOME="$USER_HOME/.local/share"
fi fi
DATA_DIR="$XDG_DATA_HOME/breezy_vulkan" DATA_DIR="$XDG_DATA_HOME/breezy_vulkan"
if [ ! -d "$DATA_DIR" ]; then
mkdir -p $DATA_DIR
fi
VULKAN_DATA_DIR="$XDG_DATA_HOME/vulkan" VULKAN_DATA_DIR="$XDG_DATA_HOME/vulkan"
XR_DRIVER_DATA_DIR="$XDG_DATA_HOME/xr_driver" XR_DRIVER_DATA_DIR="$XDG_DATA_HOME/xr_driver"
@ -35,27 +32,15 @@ if [ -z "$XDG_BIN_HOME" ]; then
fi fi
OLD_BIN_DIR="$USER_HOME/bin" OLD_BIN_DIR="$USER_HOME/bin"
BIN_DIR="$XDG_BIN_HOME" BIN_DIR="$XDG_BIN_HOME"
if [ ! -d "$BIN_DIR" ]; then
mkdir -p $BIN_DIR
fi
if [ -z "$XDG_STATE_HOME" ]; then if [ -z "$XDG_STATE_HOME" ]; then
XDG_STATE_HOME="$USER_HOME/.local/state" XDG_STATE_HOME="$USER_HOME/.local/state"
fi fi
STATE_DIR="$XDG_STATE_HOME/breezy_vulkan" STATE_DIR="$XDG_STATE_HOME/breezy_vulkan"
if [ ! -d "$STATE_DIR" ]; then
mkdir -p $STATE_DIR
fi
LIB_DIR="$USER_HOME/.local/lib" LIB_DIR="$USER_HOME/.local/lib"
if [ ! -d "$LIB_DIR" ]; then
mkdir -p "$LIB_DIR"
fi
LIB32_DIR="$USER_HOME/.local/lib32" LIB32_DIR="$USER_HOME/.local/lib32"
if [ ! -d "$LIB32_DIR" ]; then
mkdir -p "$LIB32_DIR"
fi
if [ -e "$USER_HOME/bin/breezy_vulkan_uninstall" ]; then if [ -e "$USER_HOME/bin/breezy_vulkan_uninstall" ]; then
echo "Cleaning up the previous installation" echo "Cleaning up the previous installation"
@ -90,6 +75,7 @@ ESCAPED_DATA_DIR=$(printf '%s\n' "$DATA_DIR" | sed -e 's/[\/&]/\\&/g')
ESCAPED_XR_DRIVER_DATA_DIR=$(printf '%s\n' "$XR_DRIVER_DATA_DIR" | sed -e 's/[\/&]/\\&/g') ESCAPED_XR_DRIVER_DATA_DIR=$(printf '%s\n' "$XR_DRIVER_DATA_DIR" | sed -e 's/[\/&]/\\&/g')
echo "Copying the breezy_vulkan scripts to ${BIN_DIR} and related files to ${DATA_DIR}" echo "Copying the breezy_vulkan scripts to ${BIN_DIR} and related files to ${DATA_DIR}"
mkdir -p "$BIN_DIR"
cp bin/breezy_vulkan_uninstall $BIN_DIR cp bin/breezy_vulkan_uninstall $BIN_DIR
cp bin/breezy_vulkan_logs $BIN_DIR cp bin/breezy_vulkan_logs $BIN_DIR
sed -i -e "s/{bin_dir}/$ESCAPED_BIN_DIR/g" \ sed -i -e "s/{bin_dir}/$ESCAPED_BIN_DIR/g" \
@ -101,7 +87,8 @@ sed -i -e "s/{bin_dir}/$ESCAPED_BIN_DIR/g" \
-e "s/{xr_driver_data_dir}/$ESCAPED_XR_DRIVER_DATA_DIR/g" \ -e "s/{xr_driver_data_dir}/$ESCAPED_XR_DRIVER_DATA_DIR/g" \
bin/breezy_vulkan_verify bin/breezy_vulkan_verify
cp bin/breezy_vulkan_verify $BIN_DIR cp bin/breezy_vulkan_verify $BIN_DIR
cp manifest $DATA_DIR mkdir -p "$DATA_DIR"
cp manifest "$DATA_DIR/manifest"
# keep putting this in the old location in case an older version of the script tries to find it # keep putting this in the old location in case an older version of the script tries to find it
if [ ! -d "$OLD_BIN_DIR" ]; then if [ ! -d "$OLD_BIN_DIR" ]; then
@ -115,6 +102,8 @@ echo "Installing vkBasalt; copying binaries, configs, and shader files"
# copy the vkBasalt binaries and configs # copy the vkBasalt binaries and configs
mkdir -p "$VULKAN_DATA_DIR"/implicit_layer.d mkdir -p "$VULKAN_DATA_DIR"/implicit_layer.d
mkdir -p "$XDG_CONFIG_HOME"/{vkBasalt,reshade/Shaders,reshade/Textures} mkdir -p "$XDG_CONFIG_HOME"/{vkBasalt,reshade/Shaders,reshade/Textures}
mkdir -p "$LIB_DIR"
mkdir -p "$LIB32_DIR"
cp vkBasalt.64/libvkbasalt.so $LIB_DIR/ cp vkBasalt.64/libvkbasalt.so $LIB_DIR/
cp vkBasalt.32/libvkbasalt.so $LIB32_DIR/ cp vkBasalt.32/libvkbasalt.so $LIB32_DIR/
@ -143,6 +132,8 @@ cp *.frag $GAMESCOPE_RESHADE_SHADERS_DIR
cp *.fx* $GAMESCOPE_RESHADE_SHADERS_DIR cp *.fx* $GAMESCOPE_RESHADE_SHADERS_DIR
cp *.png $GAMESCOPE_RESHADE_TEXTURES_DIR cp *.png $GAMESCOPE_RESHADE_TEXTURES_DIR
mkdir -p "$STATE_DIR"
chown -R $USER:$GROUP $LIB_DIR chown -R $USER:$GROUP $LIB_DIR
chown -R $USER:$GROUP $LIB32_DIR chown -R $USER:$GROUP $LIB32_DIR
chown -R $USER:$GROUP $DATA_DIR chown -R $USER:$GROUP $DATA_DIR