From efd652b77ca8833dc0c7b60ef30d36bea9674d61 Mon Sep 17 00:00:00 2001
From: wheaney <42350981+wheaney@users.noreply.github.com>
Date: Sat, 10 Jan 2026 10:00:10 -0800
Subject: [PATCH] WIP
---
kwin/src/breezydesktopconfig.kcfg | 7 ++
kwin/src/breezydesktopeffect.cpp | 13 +++
kwin/src/breezydesktopeffect.h | 5 ++
kwin/src/kcm/breezydesktopeffectkcm.cpp | 4 +-
kwin/src/kcm/breezydesktopeffectkcm.ui | 38 ++++++--
kwin/src/qml/CameraController.qml | 12 +--
kwin/src/qml/CurvableDisplayMesh.qml | 23 +++--
kwin/src/qml/Displays.qml | 114 ++++++++++++++++--------
kwin/src/qml/main.qml | 49 +++++++---
9 files changed, 191 insertions(+), 74 deletions(-)
diff --git a/kwin/src/breezydesktopconfig.kcfg b/kwin/src/breezydesktopconfig.kcfg
index 99cfec4..98dab8d 100644
--- a/kwin/src/breezydesktopconfig.kcfg
+++ b/kwin/src/breezydesktopconfig.kcfg
@@ -29,6 +29,13 @@
How far apart the displays are visually (not logically)
+
+ 100
+ 10
+ 250
+
+ Scale the displays in XR (percentage)
+
0
-250
diff --git a/kwin/src/breezydesktopeffect.cpp b/kwin/src/breezydesktopeffect.cpp
index d0f3a64..0a821ac 100644
--- a/kwin/src/breezydesktopeffect.cpp
+++ b/kwin/src/breezydesktopeffect.cpp
@@ -243,6 +243,7 @@ void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
setFocusedDisplayDistance(BreezyDesktopConfig::focusedDisplayDistance() / 100.0f);
setAllDisplaysDistance(BreezyDesktopConfig::allDisplaysDistance() / 100.0f);
setDisplaySpacing(BreezyDesktopConfig::displaySpacing() / 1000.0f);
+ setDisplaySize(BreezyDesktopConfig::displaySize() / 100.0f);
setZoomOnFocusEnabled(BreezyDesktopConfig::zoomOnFocusEnabled());
setSmoothFollowThreshold(BreezyDesktopConfig::smoothFollowThreshold());
@@ -515,6 +516,18 @@ void BreezyDesktopEffect::setDisplaySpacing(qreal spacing) {
}
}
+qreal BreezyDesktopEffect::displaySize() const {
+ return m_displaySize;
+}
+
+void BreezyDesktopEffect::setDisplaySize(qreal size) {
+ const qreal clamped = std::clamp(size, 0.5, 2.0);
+ if (!qFuzzyCompare(clamped, m_displaySize)) {
+ m_displaySize = clamped;
+ Q_EMIT displaySizeChanged();
+ }
+}
+
qreal BreezyDesktopEffect::displayHorizontalOffset() const {
return m_displayHorizontalOffset;
}
diff --git a/kwin/src/breezydesktopeffect.h b/kwin/src/breezydesktopeffect.h
index 328a67d..7c3d881 100644
--- a/kwin/src/breezydesktopeffect.h
+++ b/kwin/src/breezydesktopeffect.h
@@ -38,6 +38,7 @@ namespace KWin
Q_PROPERTY(qreal focusedDisplayDistance READ focusedDisplayDistance NOTIFY focusedDisplayDistanceChanged)
Q_PROPERTY(qreal allDisplaysDistance READ allDisplaysDistance NOTIFY allDisplaysDistanceChanged)
Q_PROPERTY(qreal displaySpacing READ displaySpacing NOTIFY displaySpacingChanged)
+ Q_PROPERTY(qreal displaySize READ displaySize NOTIFY displaySizeChanged)
Q_PROPERTY(qreal displayHorizontalOffset READ displayHorizontalOffset NOTIFY displayOffsetChanged)
Q_PROPERTY(qreal displayVerticalOffset READ displayVerticalOffset NOTIFY displayOffsetChanged)
Q_PROPERTY(int displayWrappingScheme READ displayWrappingScheme NOTIFY displayWrappingSchemeChanged)
@@ -89,6 +90,8 @@ namespace KWin
void setAllDisplaysDistance(qreal distance);
qreal displaySpacing() const;
void setDisplaySpacing(qreal spacing);
+ qreal displaySize() const;
+ void setDisplaySize(qreal size);
qreal displayHorizontalOffset() const;
qreal displayVerticalOffset() const;
int displayWrappingScheme() const;
@@ -127,6 +130,7 @@ namespace KWin
void focusedDisplayDistanceChanged();
void allDisplaysDistanceChanged();
void displaySpacingChanged();
+ void displaySizeChanged();
void displayOffsetChanged();
void displayWrappingSchemeChanged();
void enabledStateChanged();
@@ -191,6 +195,7 @@ namespace KWin
qreal m_focusedDisplayDistance = 0.85;
qreal m_allDisplaysDistance = 1.05;
qreal m_displaySpacing = 0.0;
+ qreal m_displaySize = 1.0;
qreal m_displayHorizontalOffset = 0.0;
qreal m_displayVerticalOffset = 0.0;
int m_displayWrappingScheme = 0; // 0=auto,1=horizontal,2=vertical,3=flat
diff --git a/kwin/src/kcm/breezydesktopeffectkcm.cpp b/kwin/src/kcm/breezydesktopeffectkcm.cpp
index b629f5b..527cc9e 100644
--- a/kwin/src/kcm/breezydesktopeffectkcm.cpp
+++ b/kwin/src/kcm/breezydesktopeffectkcm.cpp
@@ -330,6 +330,7 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
connect(ui.kcfg_ZoomOnFocusEnabled, &QCheckBox::toggled, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_FocusedDisplayDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_AllDisplaysDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
+ connect(ui.kcfg_DisplaySize, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_DisplaySpacing, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_SmoothFollowThreshold, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_DisplayHorizontalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
@@ -456,6 +457,7 @@ void BreezyDesktopEffectConfig::updateUiFromConfig()
{
ui.kcfg_FocusedDisplayDistance->setValue(BreezyDesktopConfig::self()->focusedDisplayDistance());
ui.kcfg_AllDisplaysDistance->setValue(BreezyDesktopConfig::self()->allDisplaysDistance());
+ ui.kcfg_DisplaySize->setValue(BreezyDesktopConfig::self()->displaySize());
ui.kcfg_DisplaySpacing->setValue(BreezyDesktopConfig::self()->displaySpacing());
ui.kcfg_DisplayHorizontalOffset->setValue(BreezyDesktopConfig::self()->displayHorizontalOffset());
ui.kcfg_DisplayVerticalOffset->setValue(BreezyDesktopConfig::self()->displayVerticalOffset());
@@ -492,7 +494,7 @@ void BreezyDesktopEffectConfig::checkEffectLoaded() {
QPalette pal = warn->palette();
pal.setColor(QPalette::WindowText, QColor(Qt::red));
warn->setPalette(pal);
- warn->setText(tr("The Breezy Desktop KWin effect is not loaded. Please log out and back in to enable it."));
+ warn->setText(tr("The Breezy Desktop KWin effect is disabled or not loaded. Please check the Desktop Effects dialog. Otherwise, log out and back in to enable it."));
warn->setVisible(true);
}
}
diff --git a/kwin/src/kcm/breezydesktopeffectkcm.ui b/kwin/src/kcm/breezydesktopeffectkcm.ui
index 372b818..5df95ad 100644
--- a/kwin/src/kcm/breezydesktopeffectkcm.ui
+++ b/kwin/src/kcm/breezydesktopeffectkcm.ui
@@ -151,14 +151,23 @@
-
-
+
- Display Spacing:
+ Display Size:
-
-
+
+
+ QSlider::NoTicks
+
+
+ 10
+
+
+ 25
+
Qt::Horizontal
@@ -168,13 +177,30 @@
-
+
+
+ Display Spacing:
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ true
+
+
+
+ -
Follow threshold:
- -
+
-
Qt::Horizontal
@@ -196,7 +222,7 @@
- -
+
-
Add Virtual Display:
@@ -209,7 +235,7 @@
- -
+
-
false
diff --git a/kwin/src/qml/CameraController.qml b/kwin/src/qml/CameraController.qml
index 886116c..6cdafd3 100644
--- a/kwin/src/qml/CameraController.qml
+++ b/kwin/src/qml/CameraController.qml
@@ -17,7 +17,7 @@ Item {
property bool customBannerEnabled: effect.customBannerEnabled
property bool smoothFollowEnabled: effect.smoothFollowEnabled
property real lookAheadScanlineMs: effect.lookAheadConfig[2]
- property var crossFovs: displays.diagonalToCrossFOVs(
+ property var fovLengths: displays.diagonalToCrossFOVs(
displays.degreeToRadian(effect.diagonalFOV),
aspectRatio
);
@@ -84,7 +84,9 @@ Item {
}
function buildPerspectiveMatrix() {
- const f = 1.0 / crossFovs.verticalTangent;
+ const verticalTangent = fovLengths.heightUnitDistance / 2.0;
+ const horizontalTangent = fovLengths.widthUnitDistance / 2.0;
+ const f = 1.0 / verticalTangent;
const nf = 1.0 / (clipNear - clipFar);
const m00 = f / aspectRatio;
const m11 = f;
@@ -102,13 +104,13 @@ Item {
function applyRollingShutterShear(rates) {
// Convert to maximum shift at bottom of frame
- const maxDxNdc = (rates.yaw * lookAheadScanlineMs) / crossFovs.horizontalTangent;
- const maxDyNdc = -(rates.pitch * lookAheadScanlineMs) / crossFovs.verticalTangent;
+ const maxDxNdc = (rates.yaw * lookAheadScanlineMs) / horizontalTangent;
+ const maxDyNdc = -(rates.pitch * lookAheadScanlineMs) / verticalTangent;
let shx = maxDxNdc / 2.0;
let shy = maxDyNdc / 2.0;
- const f = 1.0 / crossFovs.verticalTangent;
+ const f = 1.0 / verticalTangent;
const nf = 1.0 / (clipNear - clipFar);
const m00 = f / aspectRatio;
const m11 = f;
diff --git a/kwin/src/qml/CurvableDisplayMesh.qml b/kwin/src/qml/CurvableDisplayMesh.qml
index 28f33cd..269e9b0 100644
--- a/kwin/src/qml/CurvableDisplayMesh.qml
+++ b/kwin/src/qml/CurvableDisplayMesh.qml
@@ -26,27 +26,26 @@ ProceduralMesh {
const fov = mesh.fovDetails;
const monitor = mesh.monitorGeometry;
- const conv = fov.curvedDisplay ? mesh.fovConversionFns.curved
- : mesh.fovConversionFns.flat;
-
const horizontalWrap = fov.monitorWrappingScheme === 'horizontal';
- const verticalWrap = fov.monitorWrappingScheme === 'vertical';
+ const horizontalConversions = horizontalWrap && fov.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
- const sideEdgeDistance = conv.centerToFovEdgeDistance(
- fov.completeScreenDistancePixels, fov.widthPixels);
- const horizontalRadians = conv.lengthToRadians(
+ const sideEdgeDistancePixels = horizontalConversions.centerToFovEdgeDistance(
+ fov.completeScreenDistancePixels, fov.sizeAdjustedWidthPixels);
+ const horizontalRadians = horizontalConversions.lengthToRadians(
fov.defaultDistanceHorizontalRadians,
fov.widthPixels,
- sideEdgeDistance,
+ sideEdgeDistancePixels,
monitor.width
);
- const topEdgeDistance = conv.centerToFovEdgeDistance(
- fov.completeScreenDistancePixels, fov.heightPixels);
- const verticalRadians = conv.lengthToRadians(
+ const verticalWrap = fov.monitorWrappingScheme === 'vertical';
+ const verticalConversions = verticalWrap && fov.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
+ const topEdgeDistancePixels = verticalConversions.centerToFovEdgeDistance(
+ fov.completeScreenDistancePixels, fov.sizeAdjustedHeightPixels);
+ const verticalRadians = verticalConversions.lengthToRadians(
fov.defaultDistanceVerticalRadians,
fov.heightPixels,
- topEdgeDistance,
+ topEdgeDistancePixels,
monitor.height
);
diff --git a/kwin/src/qml/Displays.qml b/kwin/src/qml/Displays.qml
index be2a3d6..59c108f 100644
--- a/kwin/src/qml/Displays.qml
+++ b/kwin/src/qml/Displays.qml
@@ -23,17 +23,25 @@ QtObject {
return Qt.quaternion(quaternion.scalar, -quaternion.z, -quaternion.x, quaternion.y);
}
- // Converts diagonal FOV in radians and aspect ratio to horizontal and vertical FOVs
+ // Converts diagonal FOV in radians and aspect ratio to horizontal and vertical FOV measurements
function diagonalToCrossFOVs(diagonalFOVRadians, aspectRatio) {
- var diagonalTangent = Math.tan(diagonalFOVRadians / 2);
- var verticalTangent = diagonalTangent / Math.sqrt(1 + aspectRatio * aspectRatio);
- var horizontalTangent = verticalTangent * aspectRatio;
+ // first convert from a spherical FOV to a diagonal FOV on a flat plane at a unit distance of 1.0
+ const diagonalLengthUnitDistance = 2 * Math.tan(diagonalFOVRadians / 2);
+
+ // then convert to flat plane horizontal and vertical FOVs
+ const heightUnitDistance = diagonalLengthUnitDistance / Math.sqrt(1 + aspectRatio * aspectRatio);
+ const widthUnitDistance = heightUnitDistance * aspectRatio;
+
return {
- diagonal: diagonalFOVRadians,
- horizontal: 2 * Math.atan(horizontalTangent),
- horizontalTangent: horizontalTangent,
- vertical: 2 * Math.atan(verticalTangent),
- verticalTangent: verticalTangent
+ // then convert back to spherical FOV
+ diagonalRadians: diagonalFOVRadians,
+ horizontalRadians: 2 * Math.atan(widthUnitDistance / 2),
+ verticalRadians: 2 * Math.atan(heightUnitDistance / 2),
+
+ // flat values are relative to a unit distance of 1.0
+ diagonalLengthUnitDistance,
+ widthUnitDistance,
+ heightUnitDistance
}
}
@@ -50,33 +58,55 @@ QtObject {
}
}
- function buildFovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice) {
+ function buildFovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice, distanceAdjustedSize) {
const aspect = viewportWidth / viewportHeight;
- const crossFovs = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
- const defaultDistanceVerticalRadians = 2 * Math.atan(crossFovs.verticalTangent / defaultDisplayDistance);
- const defaultDistanceHorizontalRadians = 2 * Math.atan(crossFovs.horizontalTangent / defaultDisplayDistance);
-
- // distance needed for the FOV-sized monitor to fill up the screen
- const fullScreenDistance = viewportHeight / (2 * crossFovs.verticalTangent);
- const lensDistancePixels = fullScreenDistance / (1.0 - lensDistanceRatio) - fullScreenDistance;
-
- // distance of a display at the default (most zoomed out) distance, plus the lens distance constant
- const lensToScreenDistance = viewportHeight / (2 * Math.tan(defaultDistanceVerticalRadians / 2));
- const completeScreenDistancePixels = lensToScreenDistance + lensDistancePixels;
+ const fovLengths = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
let monitorWrappingScheme = actualWrapScheme(screens, viewportWidth, viewportHeight);
if (wrappingChoice === 1) monitorWrappingScheme = 'horizontal';
else if (wrappingChoice === 2) monitorWrappingScheme = 'vertical';
else if (wrappingChoice === 3) monitorWrappingScheme = 'flat';
+ const lensDistanceComplement = 1.0 - lensDistanceRatio;
+ const lensDistanceFactor = (1.0 / lensDistanceComplement) - 1.0;
+ const horizontalConversions = effect.curvedDisplay && monitorWrappingScheme === 'horizontal' ? fovConversionFns.curved : fovConversionFns.flat;
+ const verticalConversions = effect.curvedDisplay && monitorWrappingScheme === 'vertical' ? fovConversionFns.curved : fovConversionFns.flat;
+
+ const defaultDistanceVerticalRadians = verticalConversions.fovRadiansAtDistance(
+ fovLengths.verticalRadians,
+ fovLengths.heightUnitDistance,
+ defaultDisplayDistance
+ );
+ const defaultDistanceHorizontalRadians = horizontalConversions.fovRadiansAtDistance(
+ fovLengths.horizontalRadians,
+ fovLengths.widthUnitDistance,
+ defaultDisplayDistance
+ );
+
+ // distance needed for the FOV-sized monitor to fill up the screen, as measured from the lenses
+ const lensToUnitDistancePixels = viewportWidth / fovLengths.widthUnitDistance;
+
+ // distance from pivot point to lens
+ const lensDistancePixels = lensToUnitDistancePixels * lensDistanceFactor;
+
+ // distance from pivot point to full screen (monitor at unit distance from lens)
+ const fullScreenDistancePixels = lensToUnitDistancePixels + lensDistancePixels;
+
+ // distance of a display at the default (most zoomed out) distance from the pivot point
+ const completeScreenDistancePixels = fullScreenDistancePixels * defaultDisplayDistance;
+
return {
widthPixels: viewportWidth,
+ distanceAdjustedSize,
+ sizeAdjustedWidthPixels: viewportWidth * distanceAdjustedSize,
heightPixels: viewportHeight,
+ sizeAdjustedHeightPixels: viewportHeight * distanceAdjustedSize,
defaultDistanceVerticalRadians,
defaultDistanceHorizontalRadians,
lensDistancePixels,
+ fullScreenDistancePixels,
completeScreenDistancePixels,
- monitorWrappingScheme: monitorWrappingScheme,
+ monitorWrappingScheme,
curvedDisplay: effect.curvedDisplay
};
}
@@ -99,6 +129,9 @@ QtObject {
angleToLength: function(fovRadians, fovLength, screenDistance, toAngleOpposite, toAngleAdjacent) {
return toAngleOpposite / toAngleAdjacent * screenDistance;
},
+ fovRadiansAtDistance: function(fovRadians, unitLength, newScreenDistance) {
+ return 2 * Math.atan(unitLength / 2 / newScreenDistance);
+ },
radiansToSegments: function(screenRadians) { return 1; }
},
curved: {
@@ -114,6 +147,9 @@ QtObject {
angleToLength: function(fovRadians, fovLength, screenDistance, toAngleOpposite, toAngleAdjacent) {
return fovLength / fovRadians * Math.atan2(toAngleOpposite, toAngleAdjacent);
},
+ fovRadiansAtDistance: function(fovRadians, unitLength, newScreenDistance) {
+ return fovRadians / newScreenDistance;
+ },
radiansToSegments: function(screenRadians) {
return Math.ceil(screenRadians * segmentsPerRadian);
}
@@ -198,8 +234,12 @@ QtObject {
var conversionFns = fovDetails.curvedDisplay ? fovConversionFns.curved : fovConversionFns.flat;
if (fovDetails.monitorWrappingScheme === 'horizontal') {
- var sideEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.widthPixels);
- var monitorSpacingPixels = monitorSpacing * fovDetails.widthPixels;
+ // monitors wrap around us horizontally
+
+ var sideEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.sizeAdjustedWidthPixels);
+ var monitorSpacingPixels = monitorSpacing * fovDetails.sizeAdjustedWidthPixels;
+
+ // targetWidth is assumed to aleady be size adjusted
var lengthToRadianFn = function(targetWidth) {
return conversionFns.lengthToRadians(
fovDetails.defaultDistanceHorizontalRadians,
@@ -209,14 +249,14 @@ QtObject {
);
};
- cachedMonitorRadians[0] = -fovDetails.defaultDistanceHorizontalRadians / 2;
+ cachedMonitorRadians[0] = -lengthToRadianFn(fovDetails.sizeAdjustedWidthPixels) / 2;
horizontalMonitorSort(monitorDetailsList).forEach(function(obj) {
var monitorDetails = obj.monitorDetails;
var originalIndex = obj.originalIndex;
var monitorWrapDetails = monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorDetails.x, monitorDetails.width, lengthToRadianFn);
var monitorCenterRadius = conversionFns.fovEdgeToScreenCenterDistance(sideEdgeRadius, monitorDetails.width);
- var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.heightPixels) * monitorSpacingPixels;
- var upCenterOffsetPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
+ var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.sizeAdjustedHeightPixels) * monitorSpacingPixels;
+ var upCenterOffsetPixels = (monitorDetails.height - fovDetails.sizeAdjustedHeightPixels) / 2;
var upCenterPixels = upTopPixels - upCenterOffsetPixels;
monitorPlacements.push({
@@ -239,8 +279,8 @@ QtObject {
});
});
} else if (fovDetails.monitorWrappingScheme === 'vertical') {
- var topEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.heightPixels);
- var monitorSpacingPixels = monitorSpacing * fovDetails.heightPixels;
+ var topEdgeRadius = conversionFns.centerToFovEdgeDistance(fovDetails.completeScreenDistancePixels, fovDetails.sizeAdjustedHeightPixels);
+ var monitorSpacingPixels = monitorSpacing * fovDetails.sizeAdjustedHeightPixels;
var lengthToRadianFn = function(targetHeight) {
return conversionFns.lengthToRadians(
fovDetails.defaultDistanceVerticalRadians,
@@ -250,14 +290,14 @@ QtObject {
);
};
- cachedMonitorRadians[0] = -fovDetails.defaultDistanceVerticalRadians / 2;
+ cachedMonitorRadians[0] = -lengthToRadianFn(fovDetails.sizeAdjustedHeightPixels) / 2;
verticalMonitorSort(monitorDetailsList).forEach(function(obj) {
var monitorDetails = obj.monitorDetails;
var originalIndex = obj.originalIndex;
var monitorWrapDetails = monitorWrap(cachedMonitorRadians, monitorSpacingPixels, monitorDetails.y, monitorDetails.height, lengthToRadianFn);
var monitorCenterRadius = conversionFns.fovEdgeToScreenCenterDistance(topEdgeRadius, monitorDetails.height);
- var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.widthPixels) * monitorSpacingPixels;
- var westCenterOffsetPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
+ var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.sizeAdjustedWidthPixels) * monitorSpacingPixels;
+ var westCenterOffsetPixels = (monitorDetails.width - fovDetails.sizeAdjustedWidthPixels) / 2;
var westCenterPixels = westLeftPixels - westCenterOffsetPixels;
monitorPlacements.push({
@@ -280,12 +320,12 @@ QtObject {
});
});
} else {
- var monitorSpacingPixels = monitorSpacing * fovDetails.widthPixels;
+ var monitorSpacingPixels = monitorSpacing * fovDetails.sizeAdjustedWidthPixels;
monitorDetailsList.forEach(function(monitorDetails, index) {
- var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.heightPixels) * monitorSpacingPixels;
- var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.widthPixels) * monitorSpacingPixels;
- var westCenterOffsetPixels = (monitorDetails.width - fovDetails.widthPixels) / 2;
- var upCenterOffsetPixels = (monitorDetails.height - fovDetails.heightPixels) / 2;
+ var upTopPixels = -monitorDetails.y - (monitorDetails.y / fovDetails.sizeAdjustedHeightPixels) * monitorSpacingPixels;
+ var westLeftPixels = -monitorDetails.x - (monitorDetails.x / fovDetails.sizeAdjustedWidthPixels) * monitorSpacingPixels;
+ var westCenterOffsetPixels = (monitorDetails.width - fovDetails.sizeAdjustedWidthPixels) / 2;
+ var upCenterOffsetPixels = (monitorDetails.height - fovDetails.sizeAdjustedHeightPixels) / 2;
var westCenterPixels = westLeftPixels - westCenterOffsetPixels;
var upCenterPixels = upTopPixels - upCenterOffsetPixels;
diff --git a/kwin/src/qml/main.qml b/kwin/src/qml/main.qml
index 2682d4a..f64f021 100644
--- a/kwin/src/qml/main.qml
+++ b/kwin/src/qml/main.qml
@@ -33,19 +33,41 @@ Item {
property var screens: KWinComponents.Workspace.screens.filter(function(screen) {
return mirrorPhysicalDisplays || screen.name.includes("BreezyDesktop") || supportedModels.some(model => screen.model.includes(model));
})
+ property var sizeAdjustedScreens: screens.map(function(screen) {
+ const sizeComplement = (1.0 - distanceAdjustedSize) / 2.0;
+ const sizeViewportOffsetX = sizeComplement * viewportResolution[0];
+ const sizeViewportOffsetY = sizeComplement * viewportResolution[1];
+ return {
+ geometry: {
+ x: screen.geometry.x * distanceAdjustedSize + sizeViewportOffsetX,
+ y: screen.geometry.y * distanceAdjustedSize + sizeViewportOffsetY,
+ width: screen.geometry.width * distanceAdjustedSize,
+ height: screen.geometry.height * distanceAdjustedSize
+ },
+ name: screen.name,
+ model: screen.model
+ };
+ })
+ property real distanceAdjustedSize: (effect.allDisplaysDistance - effect.lensDistanceRatio) *effect.displaySize
+ property var sizeAdjustedViewport: {
+ return {
+ width: viewportResolution[0] * distanceAdjustedSize,
+ height: viewportResolution[1] * distanceAdjustedSize
+ };
+ }
// x value for placing the viewport in the middle of all screens
property real screensXMid: {
let xMin = Number.MAX_VALUE;
let xMax = Number.MIN_VALUE;
- for (let i = 0; i < screens.length; i++) {
- const geometry = screens[i].geometry;
+ for (let i = 0; i < sizeAdjustedScreens.length; i++) {
+ const geometry = sizeAdjustedScreens[i].geometry;
xMin = Math.min(xMin, geometry.x);
xMax = Math.max(xMax, geometry.x + geometry.width);
}
- return (xMin + xMax) / 2 - (viewportResolution[0] / 2);
+ return (xMin + xMax) / 2 - (sizeAdjustedViewport.width / 2);
}
// y value for placing the viewport in the middle of all screens
@@ -53,13 +75,13 @@ Item {
let yMin = Number.MAX_VALUE;
let yMax = Number.MIN_VALUE;
- for (let i = 0; i < screens.length; i++) {
- const geometry = screens[i].geometry;
+ for (let i = 0; i < sizeAdjustedScreens.length; i++) {
+ const geometry = sizeAdjustedScreens[i].geometry;
yMin = Math.min(yMin, geometry.y);
yMax = Math.max(yMax, geometry.y + geometry.height);
}
- return (yMin + yMax) / 2 - (viewportResolution[1] / 2);
+ return (yMin + yMax) / 2 - (sizeAdjustedViewport.height / 2);
}
Displays {
@@ -67,19 +89,20 @@ Item {
}
property var fovDetails: displays.buildFovDetails(
- screens,
- viewportResolution[0],
- viewportResolution[1],
+ sizeAdjustedScreens,
+ sizeAdjustedViewport.width,
+ sizeAdjustedViewport.height,
viewportDiagonalFOVDegrees,
effect.lensDistanceRatio,
effect.allDisplaysDistance,
- effect.displayWrappingScheme
+ effect.displayWrappingScheme,
+ distanceAdjustedSize
)
property var monitorPlacements: {
- const dx = effect.displayHorizontalOffset * viewportResolution[0];
- const dy = effect.displayVerticalOffset * viewportResolution[1];
- const adjustedGeometries = screens.map(screen => {
+ const dx = effect.displayHorizontalOffset * sizeAdjustedViewport.width;
+ const dy = effect.displayVerticalOffset * sizeAdjustedViewport.height;
+ const adjustedGeometries = sizeAdjustedScreens.map(screen => {
const g = screen.geometry;
return {
x: g.x - screensXMid + dx,