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,