Replace the desktop video path with OWE
The desktop background no longer plays videos. OWE owns video backgrounds, and the shell layer stays empty behind one. The shell keeps stills, which OWE hands back to it. Remove the desktop video pause plumbing that only existed to stop an unseen player: the lock, idle, and battery service lookups, the per-output fullscreen check, the first-screen audio opt-in, and the audio output in BackgroundVideo. The lock screen keeps its own silent playback. Update the background tests, the manual, and the package note.
This commit is contained in:
6 files changed
+37
-119
No files matched your search
@@ -7,11 +7,9 @@ Item {
|
||||
property string path: ""
|
||||
property int version: 0
|
||||
property bool playbackEnabled: true
|
||||
property bool audioEnabled: false
|
||||
// The desktop yields video playback to OWE while it runs, so two engines
|
||||
// never decode the same file. The lock screen leaves this off and keeps its
|
||||
// own playback.
|
||||
property bool deferVideo: false
|
||||
// The desktop turns this off because OWE owns video backgrounds. The lock
|
||||
// screen leaves it on and keeps its own playback.
|
||||
property bool videoEnabled: true
|
||||
// Bumped when the file behind an unchanged path may have been replaced.
|
||||
// Images cache-bust through version; a video is rebuilt, since FFmpeg
|
||||
// would read a query as part of the filename.
|
||||
@@ -27,7 +25,7 @@ Item {
|
||||
// Both test the path directly: going through `video` lets a URL evaluate
|
||||
// against the stale flag and leak the wrong file for one pass.
|
||||
readonly property url imageUrl: path && !Util.isVideoPath(path) ? Util.fileUrl(path) + (version ? "?v=" + version : "") : ""
|
||||
readonly property url videoUrl: path && Util.isVideoPath(path) ? Util.fileUrl(path) : ""
|
||||
readonly property url videoUrl: path && Util.isVideoPath(path) && videoEnabled ? Util.fileUrl(path) : ""
|
||||
|
||||
Loader {
|
||||
id: imageLoader
|
||||
@@ -41,7 +39,7 @@ Item {
|
||||
Loader {
|
||||
id: videoLoader
|
||||
anchors.fill: parent
|
||||
active: root.path !== "" && root.video && !root.reloading && !root.deferVideo
|
||||
active: root.path !== "" && root.video && !root.reloading && root.videoEnabled
|
||||
source: "BackgroundVideo.qml"
|
||||
}
|
||||
|
||||
@@ -68,13 +66,6 @@ Item {
|
||||
when: videoLoader.item !== null
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: videoLoader.item
|
||||
property: "audioEnabled"
|
||||
value: root.audioEnabled
|
||||
when: videoLoader.item !== null
|
||||
}
|
||||
|
||||
Component {
|
||||
id: imageComponent
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import QtQuick
|
||||
import QtMultimedia
|
||||
|
||||
// Deliberately a bare MediaPlayer and VideoOutput rather than the Video
|
||||
// convenience type: Video always builds an AudioOutput, and a muted sink still
|
||||
// decodes the audio stream and opens an audio client on every output.
|
||||
// The lock screen is the only user. Playback is always silent, so this is a
|
||||
// bare MediaPlayer and VideoOutput rather than the Video convenience type:
|
||||
// Video always builds an AudioOutput, and a muted sink still decodes the audio
|
||||
// stream and opens an audio client.
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property url mediaSource: ""
|
||||
property bool playbackEnabled: true
|
||||
property bool audioEnabled: false
|
||||
property int mediaGeneration: 0
|
||||
property bool priming: false
|
||||
property int primingGeneration: -1
|
||||
@@ -74,23 +74,12 @@ Item {
|
||||
fillMode: VideoOutput.PreserveAspectCrop
|
||||
}
|
||||
|
||||
// Sound is opted into per output: with a player per monitor, every output
|
||||
// playing the track would layer copies of it. The sink is only built once
|
||||
// the media reports a sound track, so a silent file never opens an audio
|
||||
// client or its threads. Priming a paused player must not be heard.
|
||||
Loader {
|
||||
id: audioLoader
|
||||
active: root.audioEnabled && player.hasAudio
|
||||
sourceComponent: AudioOutput {
|
||||
muted: root.priming || !root.playbackEnabled
|
||||
}
|
||||
}
|
||||
|
||||
// No audio output is built, so the lock never decodes an audio stream or
|
||||
// opens an audio client.
|
||||
MediaPlayer {
|
||||
id: player
|
||||
source: root.mediaSource
|
||||
videoOutput: output
|
||||
audioOutput: audioLoader.item
|
||||
loops: MediaPlayer.Infinite
|
||||
autoPlay: root.playbackEnabled
|
||||
onMediaStatusChanged: {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
@@ -28,43 +27,6 @@ Item {
|
||||
property string pendingShellRaw: ""
|
||||
property real revealProgress: 1
|
||||
|
||||
// Injected by the first-party service loader; used to reach the lock and idle
|
||||
// services so playback can stop whenever nothing can see the wallpaper.
|
||||
property var shell: null
|
||||
|
||||
// When the OWE wallpaper engine is running, it owns video backgrounds. This
|
||||
// plugin keeps stills, which OWE hands back to it, and the lock screen keeps
|
||||
// its own playback. The desktop video path and its pause policy stay as the
|
||||
// fallback for systems without OWE.
|
||||
property bool oweActive: false
|
||||
|
||||
Process {
|
||||
id: oweStatusProc
|
||||
command: ["bash", "-c", "test -S \"${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/owe/owed.sock\""]
|
||||
onExited: root.oweActive = (exitCode === 0)
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: oweStatusTimer
|
||||
interval: 5000
|
||||
repeat: true
|
||||
running: true
|
||||
onTriggered: if (!oweStatusProc.running) oweStatusProc.running = true
|
||||
}
|
||||
|
||||
// Stop a video wallpaper's decoding whenever it is covered. Qt's FFmpeg
|
||||
// engine drives its own clock, so an unseen player keeps decoding until it
|
||||
// is told not to — a locked laptop would otherwise decode until it died.
|
||||
readonly property var lockService: shell && shell.services ? shell.firstPartyServiceFor("omarchy.lock") : null
|
||||
readonly property var idleService: shell && shell.services ? shell.firstPartyServiceFor("omarchy.idle") : null
|
||||
readonly property var batteryService: shell && shell.services ? shell.firstPartyServiceFor("omarchy.battery") : null
|
||||
readonly property bool lockActive: lockService ? lockService.locked : false
|
||||
readonly property bool screensaverActive: idleService ? idleService.screensaverWindowCount > 0 : false
|
||||
readonly property bool powerSaverActive: batteryService ? batteryService.powerSaverOnBattery : false
|
||||
// A lock or a screensaver covers every output, so it is decided once here.
|
||||
// Fullscreen is decided per output below, because it only covers its own.
|
||||
readonly property bool sessionObscured: lockActive || screensaverActive
|
||||
|
||||
function isVideo(path) {
|
||||
return Util.isVideoPath(path)
|
||||
}
|
||||
@@ -252,19 +214,6 @@ Item {
|
||||
// by pausing playback rather than by parking the layer.
|
||||
updatesEnabled: true
|
||||
|
||||
// Pausing every wallpaper for one fullscreen window would freeze the one
|
||||
// still on show next to it, which costs a viewer more than it saves. The
|
||||
// workspace on show here knows whether a fullscreen window covers it,
|
||||
// wherever focus happens to be.
|
||||
readonly property var hyprlandMonitor: Hyprland.monitorFor(modelData)
|
||||
readonly property var visibleWorkspace: hyprlandMonitor ? hyprlandMonitor.activeWorkspace : null
|
||||
readonly property bool fullscreenHere: visibleWorkspace ? visibleWorkspace.hasFullscreen : false
|
||||
|
||||
// A sound track plays from one output only, or every monitor would
|
||||
// layer its own copy of it.
|
||||
readonly property bool firstScreen: Quickshell.screens.length > 0
|
||||
&& String(Quickshell.screens[0].name || "") === String(modelData.name || "")
|
||||
|
||||
property bool maskReady: false
|
||||
|
||||
function maybeStartReveal() {
|
||||
@@ -282,14 +231,14 @@ Item {
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
|
||||
// OWE owns video backgrounds. This layer draws stills, and stays empty
|
||||
// behind a video so OWE's own layer shows through.
|
||||
BackgroundMedia {
|
||||
id: base
|
||||
anchors.fill: parent
|
||||
path: root.displayedBackground
|
||||
reloads: root.displayedReloads
|
||||
deferVideo: root.oweActive
|
||||
playbackEnabled: !root.sessionObscured && !root.powerSaverActive && !panel.fullscreenHere
|
||||
audioEnabled: panel.firstScreen
|
||||
videoEnabled: false
|
||||
onReadyChanged: {
|
||||
if (ready && root.finishingTransition) {
|
||||
root.incomingBackground = ""
|
||||
|
||||
Reference in new issue
Block a user