diff --git a/package/contents/ui/EnvironmentVariableModel.qml b/package/contents/ui/EnvironmentVariableModel.qml new file mode 100644 index 0000000..7de0f48 --- /dev/null +++ b/package/contents/ui/EnvironmentVariableModel.qml @@ -0,0 +1,107 @@ +import QtQuick + +// import "code/utils.js" as Utils + +Item { + id: root + property ListModel model: ListModel {} + property bool isLoading: true + readonly property string plasmaEnvFile: "$HOME/.config/plasma-workspace/env/luisbocanegra.smart.video.wallpaper.reborn.sh" + + signal updated + signal loaded + + function initModel(envVars) { + model.clear(); + let varList = envVars.split("\n"); + for (let envVar of varList) { + let [name, value] = envVar.split("="); + const existsIndex = getIndex(name); + if (existsIndex !== -1) { + model.set(existsIndex, { + name, + value + }); + continue; + } + model.append({ + name, + value + }); + } + root.isLoading = false; + loaded(); + } + + function getValue(name) { + for (let i = 0; i < model.count; i++) { + const item = model.get(i); + if (item.name === name) { + return item.value; + } + } + return ""; + } + + function getIndex(name) { + for (let i = 0; i < model.count; i++) { + const item = model.get(i); + if (item.name === name) { + return i; + } + } + return -1; + } + + function getPlasmaEnvVar(name, c) { + runCommand.exec(`grep 'export ${name}' "${plasmaEnvFile}" | sed 's/export ${name}=//'`, output => { + if (c) { + if (output.exitCode === 0 && output.stdout.length > 0) { + return c(output.stdout.trim()); + } + return c(null); + } + }); + } + + function setPlasmaEnvVar(name, value) { + // check if it exists + // if it does replace + // if it does not, append + runCommand.exec(`grep 'export ${name}' "${plasmaEnvFile}"`, output => { + if (output.exitCode === 0 && output.stdout.length > 0) { + console.log(`${name}`, output.stdout); + console.log(`sed -i 's/export ${name}=.*/export ${name}=${value}/g' "${plasmaEnvFile}"`); + runCommand.exec(`sed -i 's/export ${name}=.*/export ${name}=${value}/g' "${plasmaEnvFile}"`); + } else { + runCommand.exec(`touch "${plasmaEnvFile}" && echo "export ${name}=${value}" >> "${plasmaEnvFile}"`); + } + }); + } + + function removePlasmaEnvVar(name) { + console.log(`sed -i '/export ${name}=.*/d' "${plasmaEnvFile}"`); + runCommand.exec(`sed -i '/export ${name}=.*/d' "${plasmaEnvFile}"`); + } + + function varExists(name) { + return getValue(name) !== ""; + } + + RunCommand { + id: runCommand + } + + function getVars() { + let vars; + runCommand.exec(`printenv`, output => { + if (output.exitCode === 0 && output.stdout.length > 0) { + initModel(output.stdout.trim()); + } + }); + } + + Component.onCompleted: { + getVars(); + } +} diff --git a/package/contents/ui/config.qml b/package/contents/ui/config.qml index 82b9556..f381e76 100644 --- a/package/contents/ui/config.qml +++ b/package/contents/ui/config.qml @@ -81,6 +81,16 @@ ColumnLayout { property var isLockScreenSettings: null property int editingIndex: -1 property var validDropExtensions: [".mp4", ".mpg", ".ogg", ".mov", ".webm", ".flv", ".mkv", ".avi", ".wmv", ".gif"] + property string qtMEdiaBackend + property string qtMEdiaBackendOverride + property string qtHwDecodingDevice + property string qtHwDecodingDeviceOverride + + property string vaapiDriver + property string vaapiDriverOverride + + property string vdpauDriver + property string vdpauDriverOverride property var muteModeModel: { // options for desktop and lock screen @@ -220,6 +230,36 @@ ColumnLayout { } } + EnvironmentVariableModel { + id: envVarsModel + onLoaded: { + root.qtMEdiaBackend = getValue("QT_MEDIA_BACKEND"); + root.qtHwDecodingDevice = getValue("QT_FFMPEG_DECODING_HW_DEVICE_TYPES"); + root.vaapiDriver = getValue("LIBVA_DRIVER_NAME"); + root.vdpauDriver = getValue("VDPAU_DRIVER"); + getPlasmaEnvVar("QT_MEDIA_BACKEND", value => { + if (value !== null) { + root.qtMEdiaBackendOverride = value; + } + }); + getPlasmaEnvVar("QT_FFMPEG_DECODING_HW_DEVICE_TYPES", value => { + if (value !== null) { + root.qtHwDecodingDeviceOverride = value; + } + }); + getPlasmaEnvVar("LIBVA_DRIVER_NAME", value => { + if (value !== null) { + root.vaapiDriverOverride = value; + } + }); + getPlasmaEnvVar("VDPAU_DRIVER", value => { + if (value !== null) { + root.vdpauDriverOverride = value; + } + }); + } + } + Component.onCompleted: { videosModel.initModel(cfg_VideoUrls); getAudioDevicesModel(); @@ -279,14 +319,29 @@ ColumnLayout { text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Desktop Effects") checked: tabBar.currentIndex === 2 }, + Kirigami.Action { + icon.name: "view-list-details" + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Advanced") + checked: tabBar.currentIndex === 3 + }, Kirigami.Action { icon.name: "emblem-favorite-symbolic" text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Donate") - checked: tabBar.currentIndex === 3 + checked: tabBar.currentIndex === 4 } ] } + Kirigami.Heading { + Layout.topMargin: Kirigami.Units.largeSpacing * 2 + visible: root.currentTab === 3 + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Video Decoding") + font.weight: 600 + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignVCenter + level: 1 + } + Kirigami.FormLayout { Item { Kirigami.FormData.isSection: true @@ -888,13 +943,6 @@ ColumnLayout { } } - CheckBox { - id: debugEnabledCheckbox - Kirigami.FormData.label: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Enable debug:") - text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Print debug messages to the system log") - visible: root.currentTab === 1 - } - TextEdit { wrapMode: Text.Wrap Layout.maximumWidth: 400 @@ -984,6 +1032,173 @@ ColumnLayout { } } + ColumnLayout { + spacing: Kirigami.Units.largeSpacing + Label { + visible: root.currentTab === 3 + text: "" + i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "A logout is needed for these settings to have an effect!") + "" + Layout.preferredWidth: 500 + wrapMode: Label.WordWrap + color: Kirigami.Theme.neutralTextColor + } + + Label { + visible: root.currentTab === 3 + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "These settings are modified using Plasma Session Environment Variables", "https://userbase.kde.org/Session_Environment_Variables") + Layout.preferredWidth: 500 + wrapMode: Label.WordWrap + onLinkActivated: link => Qt.openUrlExternally(link) + } + + Label { + visible: root.currentTab === 3 + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "If after setting an option to default still shows a value it means you have configured an environment variable elsewhere! See Environment variables - ArchWiki", "https://wiki.archlinux.org/title/Environment_variables") + Layout.preferredWidth: 500 + wrapMode: Label.WordWrap + onLinkActivated: link => Qt.openUrlExternally(link) + } + + Label { + visible: root.currentTab === 3 + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Verify it's working, see Improve performance by enabling Hardware Video Acceleration", "https://github.com/luisbocanegra/plasma-smart-video-wallpaper-reborn?tab=readme-ov-file#improve-performance-by-enabling-hardware-video-acceleration") + Layout.preferredWidth: 500 + wrapMode: Label.WordWrap + onLinkActivated: link => Qt.openUrlExternally(link) + } + + Label { + visible: root.currentTab === 3 + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Looking for documentation?") + "
Qt Multimedia
Qt Advanced FFmpeg Configuration
Hardware video acceleration - ArchWiki" + Layout.preferredWidth: 500 + wrapMode: Label.WordWrap + onLinkActivated: link => Qt.openUrlExternally(link) + } + } + + RowLayout { + Kirigami.FormData.label: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Hardware acceleration backend:") + visible: root.currentTab === 3 + ComboBox { + enabled: root.qtMEdiaBackendOverride !== "gstreamer" + model: [i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "System default"), "cuda", "drm", "dxva2", "d3d11va", "d3d12va", "opencl", "qsv", "vaapi", "vdpau", "videotoolbox", "mediacodec", "vulkan"] + onActivated: { + if (currentIndex === 0) { + envVarsModel.removePlasmaEnvVar("QT_FFMPEG_DECODING_HW_DEVICE_TYPES"); + } else { + envVarsModel.setPlasmaEnvVar("QT_FFMPEG_DECODING_HW_DEVICE_TYPES", currentValue); + } + } + currentIndex: root.qtHwDecodingDeviceOverride ? indexOfValue(root.qtHwDecodingDeviceOverride) : 0 + } + Kirigami.ContextualHelpButton { + toolTipText: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "You can use this to force a specific gpu, for example by setting vaapi to use an integrated Intel/AMD gpu instead of a dedicated NVIDIA gpu, which uses cuda.

It's important to note that this will not work if both gpus use the same acceleration backend.") + } + } + + Label { + visible: root.currentTab === 3 + text: "QT_FFMPEG_DECODING_HW_DEVICE_TYPES
" + i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Current value:") + " " + (root.qtHwDecodingDevice || i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Qt default")) + "" + font.pointSize: Kirigami.Theme.smallFont.pointSize + color: Kirigami.Theme.disabledTextColor + } + + ButtonGroup { + id: mediaBackendButtonGroup + onClicked: { + if (checkedButton) { + root.qtMEdiaBackendOverride = checkedButton.backend; + if (checkedButton.backend) { + envVarsModel.setPlasmaEnvVar("QT_MEDIA_BACKEND", checkedButton.backend); + } else { + envVarsModel.removePlasmaEnvVar("QT_MEDIA_BACKEND"); + } + } + } + } + RowLayout { + // By default Qt will use the FFmpeg backend, if it causes playback issues in your system try switching to the GStreamer backend instead. + Kirigami.FormData.label: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Media backend:") + visible: root.currentTab === 3 + RadioButton { + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "System default") + ButtonGroup.group: mediaBackendButtonGroup + property string backend: "" + checked: root.qtMEdiaBackendOverride === backend + } + Kirigami.ContextualHelpButton { + toolTipText: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "By default Qt will use the FFmpeg backend, if it causes playback issues in your system try switching to the GStreamer backend instead.

Make sure you have both backends installed in your system, on Arch the packages are qt6-multimedia-ffmpeg and qt6-multimedia-gstreamer") + } + } + + RadioButton { + visible: root.currentTab === 3 + text: "FFmpeg" + ButtonGroup.group: mediaBackendButtonGroup + property string backend: "ffmpeg" + checked: root.qtMEdiaBackendOverride === backend + } + + RadioButton { + visible: root.currentTab === 3 + text: "GStreamer" + ButtonGroup.group: mediaBackendButtonGroup + property string backend: "gstreamer" + checked: root.qtMEdiaBackendOverride === backend + } + + Label { + visible: root.currentTab === 3 + text: "QT_MEDIA_BACKEND
" + i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Current value:") + " " + (root.qtMEdiaBackend || i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Qt default")) + "" + font.pointSize: Kirigami.Theme.smallFont.pointSize + color: Kirigami.Theme.disabledTextColor + } + + //////////////// + ComboBox { + visible: root.currentTab === 3 + Kirigami.FormData.label: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "VA-API driver:") + model: [i18n("System default"), "i965", "iHD", "nouveau", "nvidia", "radeonsi"] + onActivated: { + if (currentIndex === 0) { + envVarsModel.removePlasmaEnvVar("LIBVA_DRIVER_NAME"); + } else { + envVarsModel.setPlasmaEnvVar("LIBVA_DRIVER_NAME", currentValue); + } + } + currentIndex: root.vaapiDriverOverride ? indexOfValue(root.vaapiDriverOverride) : 0 + } + + Label { + visible: root.currentTab === 3 + text: "LIBVA_DRIVER_NAME
" + i18n("Current value: ") + "" + (root.vaapiDriver || i18n("System default")) + "" + font.pointSize: Kirigami.Theme.smallFont.pointSize + color: Kirigami.Theme.disabledTextColor + } + //////////////// + + //////////////// + ComboBox { + visible: root.currentTab === 3 + Kirigami.FormData.label: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "VDPAU driver:") + model: [i18n("System default"), "va_gl", "nvidia"] + onActivated: { + if (currentIndex === 0) { + envVarsModel.removePlasmaEnvVar("VDPAU_DRIVER"); + } else { + envVarsModel.setPlasmaEnvVar("VDPAU_DRIVER", currentValue); + } + } + currentIndex: root.vdpauDriverOverride ? indexOfValue(root.vdpauDriverOverride) : 0 + } + + Label { + visible: root.currentTab === 3 + text: "VDPAU_DRIVER
" + i18n("Current value: ") + "" + (root.vdpauDriver || i18n("System default")) + "" + font.pointSize: Kirigami.Theme.smallFont.pointSize + color: Kirigami.Theme.disabledTextColor + } + //////////////// + Component.onCompleted: { // align with parent form from wallpaper config page if (typeof appearanceRoot !== "undefined") { @@ -1001,8 +1216,42 @@ ColumnLayout { } } - Components.Donate { + Kirigami.Heading { + Layout.topMargin: Kirigami.Units.largeSpacing * 2 visible: root.currentTab === 3 + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Debug") + font.weight: 600 + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignVCenter + level: 2 + } + + Kirigami.FormLayout { + CheckBox { + id: debugEnabledCheckbox + Kirigami.FormData.label: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Enable debug:") + text: i18nd("plasma_wallpaper_luisbocanegra.smart.video.wallpaper.reborn", "Print debug messages to the system log") + visible: root.currentTab === 3 + } + Component.onCompleted: { + // align with parent form from wallpaper config page + if (typeof appearanceRoot !== "undefined") { + twinFormLayouts.push(appearanceRoot.parentLayout); + } + + let candidate = root.parent; + while (candidate) { + if (candidate && candidate.hasOwnProperty("configDialog")) { + root.isLockScreenSettings = candidate.configDialog.toString().includes("ScreenLockerKcm"); + break; + } + candidate = candidate.parent; + } + } + } + + Components.Donate { + visible: root.currentTab === 4 Layout.fillWidth: true Layout.fillHeight: true Layout.margins: Kirigami.Units.gridUnit