Add display offsets and wrapping scheme options

This commit is contained in:
wheaney 2025-09-02 22:01:59 -07:00
parent 6c5f08611e
commit bc959c2f4c
7 changed files with 172 additions and 26 deletions

View File

@ -29,5 +29,26 @@
<label>Display Spacing</label>
<description>How far apart the displays are visually (not logically)</description>
</entry>
<entry name="DisplayHorizontalOffset" type="Int">
<default>0</default>
<min>-250</min>
<max>250</max>
<label>Display Horizontal Offset</label>
<description>Horizontal offset as a percent of the viewport width (-2.50 to 2.50)</description>
</entry>
<entry name="DisplayVerticalOffset" type="Int">
<default>0</default>
<min>-250</min>
<max>250</max>
<label>Display Vertical Offset</label>
<description>Vertical offset as a percent of the viewport height (-2.50 to 2.50)</description>
</entry>
<entry name="DisplayWrappingScheme" type="Int">
<default>0</default>
<min>0</min>
<max>3</max>
<label>Display Wrapping Scheme</label>
<description>How to arrange monitors: 0=Auto, 1=Horizontal, 2=Vertical, 3=Flat</description>
</entry>
</group>
</kcfg>

View File

@ -153,6 +153,14 @@ void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
setAllDisplaysDistance(BreezyDesktopConfig::allDisplaysDistance() / 100.0f);
setDisplaySpacing(BreezyDesktopConfig::displaySpacing() / 1000.0f);
setZoomOnFocusEnabled(BreezyDesktopConfig::zoomOnFocusEnabled());
qreal horiz = BreezyDesktopConfig::displayHorizontalOffset() / 100.0f;
qreal vert = BreezyDesktopConfig::displayVerticalOffset() / 100.0f;
int wrap = BreezyDesktopConfig::displayWrappingScheme();
bool changed = false;
if (!qFuzzyCompare(m_displayHorizontalOffset, horiz)) { m_displayHorizontalOffset = horiz; changed = true; }
if (!qFuzzyCompare(m_displayVerticalOffset, vert)) { m_displayVerticalOffset = vert; changed = true; }
if (m_displayWrappingScheme != wrap) { m_displayWrappingScheme = wrap; Q_EMIT displayWrappingSchemeChanged(); }
if (changed) Q_EMIT displayOffsetChanged();
}
QVariantMap BreezyDesktopEffect::initialProperties(Output *screen)
@ -327,6 +335,18 @@ void BreezyDesktopEffect::setDisplaySpacing(qreal spacing) {
}
}
qreal BreezyDesktopEffect::displayHorizontalOffset() const {
return m_displayHorizontalOffset;
}
qreal BreezyDesktopEffect::displayVerticalOffset() const {
return m_displayVerticalOffset;
}
int BreezyDesktopEffect::displayWrappingScheme() const {
return m_displayWrappingScheme;
}
qreal BreezyDesktopEffect::diagonalFOV() const {
return m_diagonalFOV;
}

View File

@ -27,6 +27,9 @@ 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 displayHorizontalOffset READ displayHorizontalOffset NOTIFY displayOffsetChanged)
Q_PROPERTY(qreal displayVerticalOffset READ displayVerticalOffset NOTIFY displayOffsetChanged)
Q_PROPERTY(int displayWrappingScheme READ displayWrappingScheme NOTIFY displayWrappingSchemeChanged)
Q_PROPERTY(qreal diagonalFOV READ diagonalFOV NOTIFY devicePropertiesChanged)
Q_PROPERTY(qreal lensDistanceRatio READ lensDistanceRatio NOTIFY devicePropertiesChanged)
Q_PROPERTY(bool sbsEnabled READ sbsEnabled NOTIFY devicePropertiesChanged)
@ -58,6 +61,9 @@ namespace KWin
void setAllDisplaysDistance(qreal distance);
qreal displaySpacing() const;
void setDisplaySpacing(qreal spacing);
qreal displayHorizontalOffset() const;
qreal displayVerticalOffset() const;
int displayWrappingScheme() const;
qreal diagonalFOV() const;
qreal lensDistanceRatio() const;
bool sbsEnabled() const;
@ -80,6 +86,8 @@ namespace KWin
void focusedDisplayDistanceChanged();
void allDisplaysDistanceChanged();
void displaySpacingChanged();
void displayOffsetChanged();
void displayWrappingSchemeChanged();
void enabledStateChanged();
void zoomOnFocusChanged();
void imuRotationsChanged();
@ -119,6 +127,9 @@ namespace KWin
qreal m_focusedDisplayDistance = 0.85;
qreal m_allDisplaysDistance = 1.05;
qreal m_displaySpacing = 0.0;
qreal m_displayHorizontalOffset = 0.0;
qreal m_displayVerticalOffset = 0.0;
int m_displayWrappingScheme = 0; // 0=auto,1=horizontal,2=vertical,3=flat
QList<Output *> m_virtualOutputs;
};

View File

@ -14,16 +14,13 @@
#include <KPluginFactory>
#include <QAction>
#include <QTableWidget>
#include <QHeaderView>
#include <QPushButton>
#include <QKeyEvent>
#include <QLineEdit>
#include <QLabel>
#include <QJsonValue>
#include <QJsonArray>
#include <QFileDialog>
#include <QKeyEvent>
#include <QPushButton>
#include <QComboBox>
Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr")
@ -80,6 +77,9 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
connect(ui.kcfg_FocusedDisplayDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_AllDisplaysDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_DisplaySpacing, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_DisplayHorizontalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_DisplayVerticalOffset, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
connect(ui.kcfg_DisplayWrappingScheme, qOverload<int>(&QComboBox::currentIndexChanged), this, &BreezyDesktopEffectConfig::save);
if (auto label = widget()->findChild<QLabel*>("labelAppNameVersion")) {
label->setText(QStringLiteral("Breezy Desktop - v%1").arg(QLatin1String(BREEZY_DESKTOP_VERSION_STR)));
@ -163,6 +163,9 @@ void BreezyDesktopEffectConfig::updateUiFromConfig()
ui.kcfg_FocusedDisplayDistance->setValue(BreezyDesktopConfig::self()->focusedDisplayDistance());
ui.kcfg_AllDisplaysDistance->setValue(BreezyDesktopConfig::self()->allDisplaysDistance());
ui.kcfg_DisplaySpacing->setValue(BreezyDesktopConfig::self()->displaySpacing());
ui.kcfg_DisplayHorizontalOffset->setValue(BreezyDesktopConfig::self()->displayHorizontalOffset());
ui.kcfg_DisplayVerticalOffset->setValue(BreezyDesktopConfig::self()->displayVerticalOffset());
ui.kcfg_DisplayWrappingScheme->setCurrentIndex(BreezyDesktopConfig::self()->displayWrappingScheme());
ui.kcfg_ZoomOnFocusEnabled->setChecked(BreezyDesktopConfig::self()->zoomOnFocusEnabled());
ui.kcfg_FocusedDisplayDistance->setEnabled(ui.kcfg_ZoomOnFocusEnabled->isChecked());
}

View File

@ -2,6 +2,9 @@
<ui version="4.0">
<class>BreezyDesktopEffectConfig</class>
<widget class="QWidget" name="BreezyDesktopEffectConfig">
<property name="minimumWidth">
<number>800</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelDeviceConnectionStatus">
@ -32,7 +35,7 @@
<attribute name="title">
<string>&amp;General</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="kcfg_ZoomOnFocusEnabled">
<property name="text">
@ -112,7 +115,59 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="4" column="0">
<widget class="QLabel" name="labelDisplayHorizontalOffset">
<property name="text">
<string>Display Horizontal Offset:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="LabeledSlider" name="kcfg_DisplayHorizontalOffset">
<property name="decimalShift">
<double>2</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>50</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelDisplayVerticalOffset">
<property name="text">
<string>Display Vertical Offset:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="LabeledSlider" name="kcfg_DisplayVerticalOffset">
<property name="decimalShift">
<double>2</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>50</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="KShortcutsEditor" name="shortcutsEditor" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -128,17 +183,38 @@
<attribute name="title">
<string>&amp;Advanced</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayoutAdvanced">
<item>
<widget class="QLabel" name="labelAdvancedPlaceholder">
<property name="text">
<string>Advanced settings will appear here.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<layout class="QFormLayout" name="formAdvanced">
<item row="0" column="0">
<widget class="QLabel" name="labelDisplayWrappingScheme">
<property name="text">
<string>Display Wrapping Scheme:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="kcfg_DisplayWrappingScheme">
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Horizontal</string>
</property>
</item>
<item>
<property name="text">
<string>Vertical</string>
</property>
</item>
<item>
<property name="text">
<string>Flat</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabLicenseDetails">

View File

@ -48,11 +48,11 @@ QtObject {
}
}
function fovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistanace) {
function fovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice) {
const aspect = viewportWidth / viewportHeight;
const fovRadians = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect);
const defaultDistanceVerticalRadians = 2 * Math.atan(Math.tan(fovRadians.vertical / 2) / defaultDisplayDistanace);
const defaultDistanceHorizontalRadians = 2 * Math.atan(Math.tan(fovRadians.horizontal / 2) / defaultDisplayDistanace);
const defaultDistanceVerticalRadians = 2 * Math.atan(Math.tan(fovRadians.vertical / 2) / defaultDisplayDistance);
const defaultDistanceHorizontalRadians = 2 * Math.atan(Math.tan(fovRadians.horizontal / 2) / defaultDisplayDistance);
// distance needed for the FOV-sized monitor to fill up the screen
const fullScreenDistance = viewportHeight / 2 / Math.tan(fovRadians.vertical / 2);
@ -62,6 +62,11 @@ QtObject {
const lensToScreenDistance = viewportHeight / 2 / Math.tan(defaultDistanceVerticalRadians / 2);
const completeScreenDistancePixels = lensToScreenDistance + lensDistancePixels;
let monitorWrappingScheme = actualWrapScheme(screens, viewportWidth, viewportHeight);
if (wrappingChoice === 1) monitorWrappingScheme = 'horizontal';
else if (wrappingChoice === 2) monitorWrappingScheme = 'vertical';
else if (wrappingChoice === 3) monitorWrappingScheme = 'flat';
return {
widthPixels: viewportWidth,
heightPixels: viewportHeight,
@ -69,7 +74,7 @@ QtObject {
defaultDistanceHorizontalRadians,
lensDistancePixels,
completeScreenDistancePixels,
monitorWrappingScheme: actualWrapScheme(screens, viewportWidth, viewportHeight),
monitorWrappingScheme: monitorWrappingScheme,
curvedDisplay: false // or true
};
}

View File

@ -61,14 +61,24 @@ Item {
id: displays
}
property var fovDetails: displays.fovDetails(screens, viewportResolution[0], viewportResolution[1], viewportDiagonalFOVDegrees, effect.lensDistanceRatio, effect.allDisplaysDistance)
property var fovDetails: displays.fovDetails(
screens,
viewportResolution[0],
viewportResolution[1],
viewportDiagonalFOVDegrees,
effect.lensDistanceRatio,
effect.allDisplaysDistance,
effect.displayWrappingScheme
)
property var monitorPlacements: {
const dx = effect.displayHorizontalOffset * viewportResolution[0];
const dy = effect.displayVerticalOffset * viewportResolution[1];
const adjustedGeometries = screens.map(screen => {
const g = screen.geometry;
return {
x: g.x - screensXMid,
y: g.y - screensYMid,
x: g.x - screensXMid + dx,
y: g.y - screensYMid + dy,
width: g.width,
height: g.height
};