Fix issue where Qt 6.5 and below don't have the Quick3D.Helpers modules, fall back to a standard Rectange geometry, disable curved display UI option
Add better logging to the python IPC integration
This commit is contained in:
parent
2bcc2e07e3
commit
40a8613aa1
|
|
@ -25,7 +25,7 @@ print_missing_dependencies() {
|
|||
printf "\n\033[1;31mMissing required components\033[0m\n"
|
||||
echo ""
|
||||
echo "Install the corresponding packages with your package manager, then rerun this setup:"
|
||||
echo " Debian/Ubuntu: sudo apt-get update && sudo apt-get install -y extra-cmake-modules kwin-dev libkf6config-dev libkf6configwidgets-dev libkf6coreaddons-dev libkf6kcmutils-dev libkf6globalaccel-dev libkf6i18n-dev libkf6windowsystem-dev libkf6xmlgui-dev qt6-base-dev qt6-declarative-dev libdrm-dev"
|
||||
echo " Debian/Ubuntu: sudo apt-get update && sudo apt-get install -y extra-cmake-modules kwin-dev libkf6config-dev libkf6configwidgets-dev libkf6coreaddons-dev libkf6kcmutils-dev libkf6globalaccel-dev libkf6i18n-dev libkf6windowsystem-dev libkf6xmlgui-dev qt6-base-dev qt6-declarative-dev libdrm-dev && (sudo apt-get install -y qml6-module-qtquick3d-helpers || true)"
|
||||
echo " Fedora/RHEL: sudo dnf install -y extra-cmake-modules kwin-devel kf6-kconfig-devel kf6-kconfigwidgets-devel kf6-kcoreaddons-devel kf6-kcmutils-devel kf6-kglobalaccel-devel kf6-ki18n-devel kf6-kwindowsystem-devel kf6-kxmlgui-devel qt6-qtbase-devel qt6-qttools-devel wayland-devel libepoxy-devel libdrm-devel"
|
||||
echo " Arch: sudo pacman -S --needed extra-cmake-modules qt6-base qt6-declarative qt6-tools qt6-quick3d kconfig kconfigwidgets kcoreaddons kglobalaccel ki18n kcmutils kxmlgui kwindowsystem kwin"
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ public Q_SLOTS:
|
|||
return m_effect->listVirtualDisplays();
|
||||
}
|
||||
|
||||
bool CurvedDisplaySupported() {
|
||||
return m_effect->curvedDisplaySupported();
|
||||
}
|
||||
|
||||
private:
|
||||
KWin::BreezyDesktopEffect *m_effect;
|
||||
};
|
||||
|
|
@ -240,7 +244,7 @@ void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
|
|||
if (m_removeVirtualDisplaysOnDisable != removeVD) { m_removeVirtualDisplaysOnDisable = removeVD; Q_EMIT removeVirtualDisplaysOnDisableChanged(); }
|
||||
if (m_mirrorPhysicalDisplays != mirrorPhysicalDisplays) { m_mirrorPhysicalDisplays = mirrorPhysicalDisplays; Q_EMIT mirrorPhysicalDisplaysChanged(); }
|
||||
|
||||
bool curved = BreezyDesktopConfig::curvedDisplay();
|
||||
bool curved = BreezyDesktopConfig::curvedDisplay() && m_curvedDisplaySupported;
|
||||
if (m_curvedDisplay != curved) { m_curvedDisplay = curved; Q_EMIT curvedDisplayChanged(); }
|
||||
|
||||
// this one doesn't have a signal, just always assign it
|
||||
|
|
@ -523,6 +527,22 @@ bool BreezyDesktopEffect::curvedDisplay() const {
|
|||
return m_curvedDisplay;
|
||||
}
|
||||
|
||||
bool BreezyDesktopEffect::curvedDisplaySupported() const {
|
||||
return m_curvedDisplaySupported;
|
||||
}
|
||||
|
||||
void BreezyDesktopEffect::setCurvedDisplaySupported(bool supported) {
|
||||
if (m_curvedDisplaySupported != supported) {
|
||||
m_curvedDisplaySupported = supported;
|
||||
Q_EMIT curvedDisplaySupportedChanged();
|
||||
}
|
||||
|
||||
if (!supported && m_curvedDisplay) {
|
||||
m_curvedDisplay = false;
|
||||
Q_EMIT curvedDisplayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QList<QQuaternion> BreezyDesktopEffect::smoothFollowOrigin() const {
|
||||
return m_smoothFollowOrigin;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ namespace KWin
|
|||
Q_PROPERTY(bool removeVirtualDisplaysOnDisable READ removeVirtualDisplaysOnDisable NOTIFY removeVirtualDisplaysOnDisableChanged)
|
||||
Q_PROPERTY(bool mirrorPhysicalDisplays READ mirrorPhysicalDisplays NOTIFY mirrorPhysicalDisplaysChanged)
|
||||
Q_PROPERTY(bool curvedDisplay READ curvedDisplay NOTIFY curvedDisplayChanged)
|
||||
Q_PROPERTY(bool curvedDisplaySupported READ curvedDisplaySupported WRITE setCurvedDisplaySupported NOTIFY curvedDisplaySupportedChanged)
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -92,6 +93,7 @@ namespace KWin
|
|||
bool removeVirtualDisplaysOnDisable() const;
|
||||
bool mirrorPhysicalDisplays() const;
|
||||
bool curvedDisplay() const;
|
||||
void setCurvedDisplaySupported(bool supported);
|
||||
|
||||
void showCursor();
|
||||
void hideCursor();
|
||||
|
|
@ -109,6 +111,7 @@ namespace KWin
|
|||
QVariantList listVirtualDisplays() const;
|
||||
bool removeVirtualDisplay(const QString &id);
|
||||
void moveCursorToFocusedDisplay();
|
||||
bool curvedDisplaySupported() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void lookAheadOverrideChanged();
|
||||
|
|
@ -127,6 +130,7 @@ namespace KWin
|
|||
void removeVirtualDisplaysOnDisableChanged();
|
||||
void mirrorPhysicalDisplaysChanged();
|
||||
void curvedDisplayChanged();
|
||||
void curvedDisplaySupportedChanged();
|
||||
void cursorImageSourceChanged();
|
||||
void cursorPosChanged();
|
||||
|
||||
|
|
@ -177,6 +181,7 @@ namespace KWin
|
|||
bool m_removeVirtualDisplaysOnDisable = true;
|
||||
bool m_mirrorPhysicalDisplays = false;
|
||||
bool m_curvedDisplay = false;
|
||||
bool m_curvedDisplaySupported = false;
|
||||
float m_smoothFollowThreshold = 1.0f;
|
||||
bool m_allDisplaysFollowMode = false;
|
||||
bool m_focusedSmoothFollowEnabled = false;
|
||||
|
|
|
|||
|
|
@ -527,6 +527,13 @@ QVariantList BreezyDesktopEffectConfig::dbusRemoveVirtualDisplay(const QString &
|
|||
return list.isValid() ? list.value() : QVariantList{};
|
||||
}
|
||||
|
||||
bool BreezyDesktopEffectConfig::dbusCurvedDisplaySupported() const {
|
||||
QDBusInterface iface = makeVDInterface();
|
||||
if (!iface.isValid()) return false;
|
||||
QDBusReply<bool> reply = iface.call(QStringLiteral("CurvedDisplaySupported"));
|
||||
return reply.isValid() && reply.value();
|
||||
}
|
||||
|
||||
void BreezyDesktopEffectConfig::renderVirtualDisplays(const QVariantList &rows) {
|
||||
auto listContainer = widget()->findChild<QWidget*>(QStringLiteral("widgetVirtualDisplayList"));
|
||||
auto listLayout = listContainer ? qobject_cast<QVBoxLayout*>(listContainer->layout()) : nullptr;
|
||||
|
|
@ -651,6 +658,24 @@ void BreezyDesktopEffectConfig::pollDriverState()
|
|||
QStringLiteral("No device connected"));
|
||||
}
|
||||
|
||||
if (m_deviceConnected) {
|
||||
if (!dbusCurvedDisplaySupported()) {
|
||||
if (m_curvedDisplaySupported) {
|
||||
m_curvedDisplaySupported = false;
|
||||
ui.kcfg_CurvedDisplay->setEnabled(false);
|
||||
ui.kcfg_CurvedDisplay->setChecked(false);
|
||||
ui.kcfg_CurvedDisplay->setToolTip(QObject::tr("This feature requires Qt version 6.6 or higher"));
|
||||
}
|
||||
} else {
|
||||
if (!m_curvedDisplaySupported) {
|
||||
m_curvedDisplaySupported = true;
|
||||
ui.kcfg_CurvedDisplay->setEnabled(true);
|
||||
ui.kcfg_CurvedDisplay->setChecked(BreezyDesktopConfig::self()->curvedDisplay());
|
||||
ui.kcfg_CurvedDisplay->setToolTip(QString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool effectEnabled = driverEnabled(configJsonOpt);
|
||||
if (ui.EffectEnabled->isChecked() != effectEnabled) ui.EffectEnabled->setChecked(effectEnabled);
|
||||
bool multitap = multitapEnabled(configJsonOpt);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ private:
|
|||
QVariantList dbusRemoveVirtualDisplay(const QString &id) const;
|
||||
void renderVirtualDisplays(const QVariantList &rows);
|
||||
|
||||
bool dbusCurvedDisplaySupported() const;
|
||||
|
||||
::Ui::BreezyDesktopEffectConfig ui;
|
||||
|
||||
KConfigWatcher::Ptr m_configWatcher;
|
||||
|
|
@ -70,4 +72,5 @@ private:
|
|||
QTimer m_statePollTimer; // periodic driver state polling
|
||||
QTimer m_virtualDisplayPollTimer; // periodic virtual display list polling
|
||||
bool m_licenseLoading = false;
|
||||
bool m_curvedDisplaySupported = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -171,6 +171,15 @@ Node {
|
|||
return matrix;
|
||||
}
|
||||
|
||||
// only for the Rectangle geometry fallback
|
||||
property vector3d rectangleFallbackScale: {
|
||||
const geometry = screen.geometry;
|
||||
|
||||
// default geometry unit size is 100x100, so we scale it up to the screen size
|
||||
return Qt.vector3d(geometry.width / 100, geometry.height / 100, 1);
|
||||
}
|
||||
|
||||
scale: effect.curvedDisplaySupported ? Qt.vector3d(1, 1, 1) : rectangleFallbackScale
|
||||
eulerRotation.y: screenRotationY
|
||||
eulerRotation.x: screenRotationX
|
||||
position: {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import QtQuick
|
||||
import QtQuick3D
|
||||
import QtQuick3D.Helpers
|
||||
|
||||
Model {
|
||||
id: display
|
||||
|
|
@ -18,95 +17,31 @@ Model {
|
|||
id: displays
|
||||
}
|
||||
|
||||
geometry: ProceduralMesh {
|
||||
id: mesh
|
||||
// Default to simple rectangle source so we work on older Qt6
|
||||
// We'll attempt to dynamically load CurvableDisplayMesh.qml in onCompleted
|
||||
source: "#Rectangle"
|
||||
|
||||
property var _meshArrays: generateMesh()
|
||||
positions: _meshArrays.positions
|
||||
uv0s: _meshArrays.uvs
|
||||
indexes: _meshArrays.indices
|
||||
primitiveMode: ProceduralMesh.TriangleStrip
|
||||
|
||||
function generateMesh() {
|
||||
if (!display.fovDetails || !display.screen)
|
||||
return { positions: [], uvs: [], indices: [] };
|
||||
|
||||
const fov = display.fovDetails;
|
||||
const monitor = display.screen.geometry;
|
||||
|
||||
const conv = fov.curvedDisplay ? displays.fovConversionFns.curved
|
||||
: displays.fovConversionFns.flat;
|
||||
|
||||
const horizontalWrap = fov.monitorWrappingScheme === 'horizontal';
|
||||
const verticalWrap = fov.monitorWrappingScheme === 'vertical';
|
||||
|
||||
const sideEdgeDistance = conv.centerToFovEdgeDistance(
|
||||
fov.completeScreenDistancePixels, fov.widthPixels);
|
||||
const horizontalRadians = conv.lengthToRadians(
|
||||
fov.defaultDistanceHorizontalRadians,
|
||||
fov.widthPixels,
|
||||
sideEdgeDistance,
|
||||
monitor.width
|
||||
);
|
||||
|
||||
const topEdgeDistance = conv.centerToFovEdgeDistance(
|
||||
fov.completeScreenDistancePixels, fov.heightPixels);
|
||||
const verticalRadians = conv.lengthToRadians(
|
||||
fov.defaultDistanceVerticalRadians,
|
||||
fov.heightPixels,
|
||||
topEdgeDistance,
|
||||
monitor.height
|
||||
);
|
||||
|
||||
const positions = [];
|
||||
const uvs = [];
|
||||
const indices = [];
|
||||
|
||||
const radius = fov.completeScreenDistancePixels;
|
||||
function vertexFor(s, t) {
|
||||
let z = 0;
|
||||
|
||||
const xOffset = s - 0.5;
|
||||
let x = xOffset * monitor.width;
|
||||
if (fov.curvedDisplay && horizontalWrap) {
|
||||
const xOffsetRadians = xOffset * horizontalRadians;
|
||||
x = Math.sin(xOffsetRadians) * radius;
|
||||
z = radius - Math.cos(xOffsetRadians) * radius;
|
||||
Component.onCompleted: {
|
||||
try {
|
||||
const component = Qt.createComponent(Qt.resolvedUrl("CurvableDisplayMesh.qml"), Component.PreferSynchronous);
|
||||
if (component.status === Component.Ready) {
|
||||
const mesh = component.createObject(display, {
|
||||
fovDetails: Qt.binding(() => display.fovDetails),
|
||||
monitorGeometry: Qt.binding(() => display.screen ? display.screen.geometry : null),
|
||||
fovConversionFns: Qt.binding(() => displays.fovConversionFns)
|
||||
});
|
||||
if (mesh) {
|
||||
display.source = "";
|
||||
display.geometry = mesh;
|
||||
effect.curvedDisplaySupported = true;
|
||||
}
|
||||
|
||||
const yOffset = t - 0.5;
|
||||
let y = yOffset * monitor.height;
|
||||
if (fov.curvedDisplay && verticalWrap) {
|
||||
const yOffsetRadians = yOffset * verticalRadians;
|
||||
y = Math.sin(yOffsetRadians) * radius;
|
||||
z = radius - Math.cos(yOffsetRadians) * radius;
|
||||
}
|
||||
|
||||
return { pos: Qt.vector3d(x, y, z), uv: Qt.vector2d(s, t) };
|
||||
} else {
|
||||
console.error("Breezy - CurvableDisplayMesh not available:", component.errorString());
|
||||
effect.curvedDisplaySupported = false;
|
||||
}
|
||||
|
||||
let segments = 1;
|
||||
if (horizontalWrap) segments = conv.radiansToSegments(horizontalRadians);
|
||||
if (verticalWrap) segments = conv.radiansToSegments(verticalRadians);
|
||||
for (let i = 0; i <= segments; i++) {
|
||||
const texFraction = i / segments;
|
||||
|
||||
// !verticalWrap also covers "flat" wrap scheme
|
||||
const texX0 = !verticalWrap ? texFraction : 0;
|
||||
const texX1 = !verticalWrap ? texFraction : 1;
|
||||
|
||||
const texY0 = verticalWrap ? texFraction : 1;
|
||||
const texY1 = verticalWrap ? texFraction : 0;
|
||||
|
||||
let vtxB = vertexFor(texX0, texY0);
|
||||
let vtxT = vertexFor(texX1, texY1);
|
||||
positions.push(vtxB.pos);
|
||||
positions.push(vtxT.pos);
|
||||
uvs.push(vtxB.uv);
|
||||
uvs.push(vtxT.uv);
|
||||
}
|
||||
|
||||
return { positions: positions, uvs: uvs, indices: [] };
|
||||
} catch (e) {
|
||||
console.error("Breezy - CurvableDisplayMesh loading error:", e);
|
||||
effect.curvedDisplaySupported = false;
|
||||
}
|
||||
}
|
||||
materials: [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
import QtQuick
|
||||
import QtQuick3D
|
||||
import QtQuick3D.Helpers
|
||||
|
||||
ProceduralMesh {
|
||||
id: mesh
|
||||
|
||||
property var fovDetails
|
||||
property var monitorGeometry
|
||||
property var fovConversionFns
|
||||
|
||||
property var _meshArrays: generateMesh()
|
||||
positions: _meshArrays.positions
|
||||
uv0s: _meshArrays.uvs
|
||||
indexes: _meshArrays.indices
|
||||
primitiveMode: ProceduralMesh.TriangleStrip
|
||||
|
||||
onFovDetailsChanged: _meshArrays = generateMesh()
|
||||
onMonitorGeometryChanged: _meshArrays = generateMesh()
|
||||
onFovConversionFnsChanged: _meshArrays = generateMesh()
|
||||
|
||||
function generateMesh() {
|
||||
if (!mesh.fovDetails || !mesh.monitorGeometry || !mesh.fovConversionFns)
|
||||
return { positions: [], uvs: [], indices: [] };
|
||||
|
||||
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 sideEdgeDistance = conv.centerToFovEdgeDistance(
|
||||
fov.completeScreenDistancePixels, fov.widthPixels);
|
||||
const horizontalRadians = conv.lengthToRadians(
|
||||
fov.defaultDistanceHorizontalRadians,
|
||||
fov.widthPixels,
|
||||
sideEdgeDistance,
|
||||
monitor.width
|
||||
);
|
||||
|
||||
const topEdgeDistance = conv.centerToFovEdgeDistance(
|
||||
fov.completeScreenDistancePixels, fov.heightPixels);
|
||||
const verticalRadians = conv.lengthToRadians(
|
||||
fov.defaultDistanceVerticalRadians,
|
||||
fov.heightPixels,
|
||||
topEdgeDistance,
|
||||
monitor.height
|
||||
);
|
||||
|
||||
const positions = [];
|
||||
const uvs = [];
|
||||
const indices = [];
|
||||
|
||||
const radius = fov.completeScreenDistancePixels;
|
||||
function vertexFor(s, t) {
|
||||
let z = 0;
|
||||
|
||||
const xOffset = s - 0.5;
|
||||
let x = xOffset * monitor.width;
|
||||
if (fov.curvedDisplay && horizontalWrap) {
|
||||
const xOffsetRadians = xOffset * horizontalRadians;
|
||||
x = Math.sin(xOffsetRadians) * radius;
|
||||
z = radius - Math.cos(xOffsetRadians) * radius;
|
||||
}
|
||||
|
||||
const yOffset = t - 0.5;
|
||||
let y = yOffset * monitor.height;
|
||||
if (fov.curvedDisplay && verticalWrap) {
|
||||
const yOffsetRadians = yOffset * verticalRadians;
|
||||
y = Math.sin(yOffsetRadians) * radius;
|
||||
z = radius - Math.cos(yOffsetRadians) * radius;
|
||||
}
|
||||
|
||||
return { pos: Qt.vector3d(x, y, z), uv: Qt.vector2d(s, t) };
|
||||
}
|
||||
|
||||
let segments = 1;
|
||||
if (horizontalWrap) segments = conv.radiansToSegments(horizontalRadians);
|
||||
if (verticalWrap) segments = conv.radiansToSegments(verticalRadians);
|
||||
for (let i = 0; i <= segments; i++) {
|
||||
const texFraction = i / segments;
|
||||
|
||||
// !verticalWrap also covers "flat" wrap scheme
|
||||
const texX0 = !verticalWrap ? texFraction : 0;
|
||||
const texX1 = !verticalWrap ? texFraction : 1;
|
||||
|
||||
const texY0 = verticalWrap ? texFraction : 1;
|
||||
const texY1 = verticalWrap ? texFraction : 0;
|
||||
|
||||
let vtxB = vertexFor(texX0, texY0);
|
||||
let vtxT = vertexFor(texX1, texY1);
|
||||
positions.push(vtxB.pos);
|
||||
positions.push(vtxT.pos);
|
||||
uvs.push(vtxB.uv);
|
||||
uvs.push(vtxT.uv);
|
||||
}
|
||||
|
||||
return { positions: positions, uvs: uvs, indices: [] };
|
||||
}
|
||||
}
|
||||
|
|
@ -8,17 +8,34 @@ python one-liner implementation.
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
state_home = os.environ.get('XDG_STATE_HOME', '~/.local/state')
|
||||
state_dir = os.path.expanduser(state_home)
|
||||
breezy_state_dir = os.path.join(state_dir, 'breezy_kwin')
|
||||
log_dir = os.path.join(breezy_state_dir, 'logs')
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
logger = logging.getLogger('xrdriveripc')
|
||||
logger.setLevel(logging.INFO)
|
||||
logname = os.path.join(log_dir, "xrdriveripc.log")
|
||||
handler = TimedRotatingFileHandler(logname, when="midnight", backupCount=30)
|
||||
handler.suffix = "%Y%m%d"
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
class Logger:
|
||||
def info(self, *args, **kwargs):
|
||||
pass
|
||||
logger.info(*args, **kwargs)
|
||||
|
||||
def error(self, *args, **kwargs):
|
||||
pass
|
||||
logger.error(*args, **kwargs)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
|
|
|
|||
Loading…
Reference in New Issue