From 2bcc2e07e309a7871301de936eae9336d0bab2cb Mon Sep 17 00:00:00 2001 From: wheaney <42350981+wheaney@users.noreply.github.com> Date: Sun, 21 Sep 2025 23:10:14 -0700 Subject: [PATCH] Fix a couple smooth follow issues * Always fully center the focused screen * Properly rebind the rotation of the screen so it doesn't get frozen to an old one when changing wrap scheme --- kwin/src/breezydesktopeffect.h | 2 +- kwin/src/kcm/breezydesktopeffectkcm.cpp | 3 +- kwin/src/qml/BreezyDesktop.qml | 71 +++++++++++++------------ kwin/src/qml/Displays.qml | 3 ++ 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/kwin/src/breezydesktopeffect.h b/kwin/src/breezydesktopeffect.h index 2edd699..e3a7fbb 100644 --- a/kwin/src/breezydesktopeffect.h +++ b/kwin/src/breezydesktopeffect.h @@ -149,7 +149,7 @@ namespace KWin bool m_enabled = false; bool m_zoomOnFocusEnabled = false; - int m_lookingAtScreenIndex = -1; // -1 means disabled/unknown + int m_lookingAtScreenIndex = -1; bool m_imuResetState; QList m_imuRotations; quint32 m_imuTimeElapsedMs; diff --git a/kwin/src/kcm/breezydesktopeffectkcm.cpp b/kwin/src/kcm/breezydesktopeffectkcm.cpp index b720817..cede422 100644 --- a/kwin/src/kcm/breezydesktopeffectkcm.cpp +++ b/kwin/src/kcm/breezydesktopeffectkcm.cpp @@ -463,7 +463,8 @@ void BreezyDesktopEffectConfig::updateUiFromConfig() ui.kcfg_RemoveVirtualDisplaysOnDisable->setChecked(BreezyDesktopConfig::self()->removeVirtualDisplaysOnDisable()); ui.kcfg_AllDisplaysFollowMode->setChecked(BreezyDesktopConfig::self()->allDisplaysFollowMode()); ui.kcfg_ZoomOnFocusEnabled->setChecked(BreezyDesktopConfig::self()->zoomOnFocusEnabled()); - ui.kcfg_FocusedDisplayDistance->setEnabled(ui.kcfg_ZoomOnFocusEnabled->isChecked()); + ui.kcfg_FocusedDisplayDistance->setEnabled( + ui.kcfg_ZoomOnFocusEnabled->isChecked() || ui.SmoothFollowEnabled->isChecked()); ui.kcfg_SmoothFollowThreshold->setValue(BreezyDesktopConfig::self()->smoothFollowThreshold()); } diff --git a/kwin/src/qml/BreezyDesktop.qml b/kwin/src/qml/BreezyDesktop.qml index ff6fae6..11205d5 100644 --- a/kwin/src/qml/BreezyDesktop.qml +++ b/kwin/src/qml/BreezyDesktop.qml @@ -29,9 +29,7 @@ Node { const rotations = smoothFollowEnabled ? effect.smoothFollowOrigin : effect.imuRotations; if (rotations && rotations.length > 0) { let focusedIndex = -1; - let lookingAtIndex = -1; - - lookingAtIndex = displays.findFocusedMonitor( + const lookingAtIndex = displays.findFocusedMonitor( displays.eusToNwuQuat(rotations[0]), breezyDesktop.monitorPlacements.map(monitorVectors => monitorVectors.centerLook), breezyDesktop.focusedMonitorIndex, @@ -57,26 +55,31 @@ Node { let targetProgress; if (smoothFollowEnabled && focusedIndex !== -1) { focusedDisplay = breezyDesktop.displayAtIndex(focusedIndex); - targetDisplay = focusedDisplay; - targetProgress = 1.0; - startSmoothFollowFocusAnimation = true; + if (focusedDisplay !== null) { + targetDisplay = focusedDisplay; + targetProgress = 1.0; + startSmoothFollowFocusAnimation = true; + } } else if (!smoothFollowEnabled && breezyDesktop.focusedMonitorIndex !== -1) { unfocusedDisplay = breezyDesktop.displayAtIndex(breezyDesktop.focusedMonitorIndex); - targetDisplay = unfocusedDisplay; - targetProgress = 0.0; + if (unfocusedDisplay !== null) { + targetDisplay = unfocusedDisplay; + targetProgress = 0.0; + } + } + + if (targetDisplay !== null) { + smoothFollowTransitionAnimation.stop(); + smoothFollowTransitionAnimation.target = targetDisplay; + smoothFollowTransitionAnimation.from = targetDisplay.smoothFollowTransitionProgress; + smoothFollowTransitionAnimation.to = targetProgress; + smoothFollowTransitionAnimation.start(); } - smoothFollowTransitionAnimation.stop(); - smoothFollowTransitionAnimation.target = targetDisplay; - smoothFollowTransitionAnimation.from = targetDisplay.smoothFollowTransitionProgress; - smoothFollowTransitionAnimation.to = targetProgress; - smoothFollowTransitionAnimation.start(); } if (focusedIndex !== breezyDesktop.focusedMonitorIndex) { const unfocusedIndex = breezyDesktop.focusedMonitorIndex; if (!focusedDisplay) focusedDisplay = focusedIndex !== -1 ? breezyDesktop.displayAtIndex(focusedIndex) : null; - const allDisplaysDistanceBinding = Qt.binding(function() { return effect.allDisplaysDistance; }); - const focusedDisplayDistanceBinding = Qt.binding(function() { return effect.focusedDisplayDistance; }); if (focusedDisplay === null) { if (!unfocusedDisplay) unfocusedDisplay = breezyDesktop.displayAtIndex(unfocusedIndex); zoomOutAnimation.target = unfocusedDisplay; @@ -105,16 +108,12 @@ Node { } } - // monitorPlacement assumed to be present - function displayEusVector(display) { + function displayRotationVector(display) { const displayNwu = display.monitorPlacement.centerNoRotate .times(display.monitorDistance / effect.allDisplaysDistance); - return displays.nwuToEusVector(displayNwu); - } - - function displayRotationVector(display, eusVector) { + const eusVector = displays.nwuToEusVector(displayNwu) return display.rotationMatrix.times(eusVector); } @@ -125,23 +124,27 @@ Node { return effect.smoothFollowOrigin[0].times(effect.imuRotations[0].conjugated()); } - function displaySmoothFollowVector(display, eusVector) { - return smoothFollowQuat().times(eusVector); + function displaySmoothFollowVector(display, smoothFollowRotation) { + // for smooth follow, place the display centered directly in front of the camera + const displayDistanceNorth = + display.monitorPlacement.monitorCenterNorth * + display.monitorDistance / effect.allDisplaysDistance; + const eusVector = Qt.vector3d(0, 0, -displayDistanceNorth); + + return smoothFollowRotation.times(eusVector); } // don't call this from the delegate to avoid binding the position property to the effect properties // used for smooth follow function displayPosition(display, smoothFollowRotation) { - const displayEus = displayEusVector(display); - // short circuit to avoid slerping if not needed if (display.smoothFollowTransitionProgress === 1.0) { - return displaySmoothFollowVector(display, displayEus, smoothFollowRotation); + return displaySmoothFollowVector(display, smoothFollowRotation); } const finalPosition = displays.slerpVector( - displayRotationVector(display, displayEus), - displaySmoothFollowVector(display, displayEus, smoothFollowRotation), + displayRotationVector(display), + displaySmoothFollowVector(display, smoothFollowRotation), display.smoothFollowTransitionProgress ); @@ -173,7 +176,7 @@ Node { position: { if (!monitorPlacement) return Qt.vector3d(0, 0, 0); - return displayRotationVector(this, displayEusVector(this)); + return displayRotationVector(this); } } } @@ -208,17 +211,17 @@ Node { focusedDisplay.position = displayPosition(focusedDisplay, smoothFollowRotation); } else { focusedDisplay.rotation = Qt.quaternion(1, 0, 0, 0); - focusedDisplay.eulerRotation.x = focusedDisplay.screenRotationX; - focusedDisplay.eulerRotation.y = focusedDisplay.screenRotationY; + focusedDisplay.eulerRotation.x = Qt.binding(function() { return focusedDisplay.screenRotationX; }); + focusedDisplay.eulerRotation.y = Qt.binding(function() { return focusedDisplay.screenRotationY; }); focusedDisplay.eulerRotation.z = 0.0; // When smooth follow is done, this frame animation will no longer run so we need to // rebind a safe function to the position property that will automatically update the // position when delegate properties change. display properties don't often change, // but zoomOnFocus does change monitorDistance, so we need the binding to pick that up. - focusedDisplay.position = Qt.binding(function() { - return displayRotationVector(this, displayEusVector(this)); - }.bind(focusedDisplay) ); + focusedDisplay.position = Qt.binding(function() { + return displayRotationVector(this); + }.bind(focusedDisplay)); } } diff --git a/kwin/src/qml/Displays.qml b/kwin/src/qml/Displays.qml index b30a495..982845c 100644 --- a/kwin/src/qml/Displays.qml +++ b/kwin/src/qml/Displays.qml @@ -219,6 +219,7 @@ QtObject { monitorPlacements.push({ originalIndex: originalIndex, + monitorCenterNorth: monitorCenterRadius, centerNoRotate: Qt.vector3d( monitorCenterRadius, 0, @@ -259,6 +260,7 @@ QtObject { monitorPlacements.push({ originalIndex: originalIndex, + monitorCenterNorth: monitorCenterRadius, centerNoRotate: Qt.vector3d( monitorCenterRadius, westCenterPixels, @@ -287,6 +289,7 @@ QtObject { monitorPlacements.push({ originalIndex: index, + monitorCenterNorth: fovDetails.completeScreenDistancePixels, centerNoRotate: Qt.vector3d( fovDetails.completeScreenDistancePixels, westCenterPixels,