Move from hypridle to QS
This commit is contained in:
@@ -18,6 +18,7 @@ User-installed plugins live alongside these conceptually but on disk under
|
||||
| Clipboard mgr | `omarchy.clipboard-picker`| `overlay` | `clipboard-picker/ClipboardPicker.qml`|
|
||||
| Omarchy menu | `omarchy.menu` | `menu` | `menu/Menu.qml` |
|
||||
| Notifications | `omarchy.notifications` | `service` | `notifications/Service.qml` |
|
||||
| Idle monitor | `omarchy.idle` | `service` | `idle/Service.qml` |
|
||||
| OSD | `omarchy.osd` | `panel` | `osd/Osd.qml` |
|
||||
| Polkit agent | `omarchy.polkit` | `service` | `polkit/PolkitAgent.qml` |
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ import qs.Ui
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// The omarchy-shell host injects omarchyPath when it instantiates this Bar.
|
||||
// Default fallback keeps the file loadable in isolation (e.g. for QML tooling).
|
||||
// The omarchy-shell host injects omarchyPath from OMARCHY_PATH.
|
||||
required property string omarchyPath
|
||||
// Injected by the host shell. Shared with the bar settings panel so both
|
||||
// see the same widget catalogue.
|
||||
@@ -110,10 +109,6 @@ Item {
|
||||
return "file://" + path.split("/").map(encodeURIComponent).join("/")
|
||||
}
|
||||
|
||||
function commandWithOmarchyPath(command) {
|
||||
return "OMARCHY_PATH=" + shellQuote(omarchyPath) + " " + command
|
||||
}
|
||||
|
||||
function isPlainObject(value) {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value)
|
||||
}
|
||||
@@ -539,7 +534,7 @@ Item {
|
||||
|
||||
Process {
|
||||
id: updateProc
|
||||
command: ["bash", "-lc", root.commandWithOmarchyPath("omarchy-update-available")]
|
||||
command: ["bash", "-lc", "omarchy-update-available"]
|
||||
stdout: StdioCollector { waitForEnd: true }
|
||||
onExited: function(exitCode) {
|
||||
root.updateAvailable = exitCode === 0
|
||||
@@ -556,7 +551,7 @@ Item {
|
||||
|
||||
Process {
|
||||
id: voxtypeProc
|
||||
command: ["bash", "-lc", root.commandWithOmarchyPath("omarchy-voxtype-status")]
|
||||
command: ["bash", "-lc", "omarchy-voxtype-status"]
|
||||
running: true
|
||||
stdout: SplitParser {
|
||||
onRead: function(data) {
|
||||
@@ -567,7 +562,7 @@ Item {
|
||||
|
||||
Process {
|
||||
id: screenRecordingProc
|
||||
command: ["bash", "-lc", root.commandWithOmarchyPath(root.shellQuote(root.omarchyPath + "/shell/scripts/indicators/screen-recording.sh"))]
|
||||
command: ["bash", "-lc", root.shellQuote(root.omarchyPath + "/shell/scripts/indicators/screen-recording.sh")]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateIndicator("screenRecording", text)
|
||||
@@ -576,7 +571,7 @@ Item {
|
||||
|
||||
Process {
|
||||
id: notificationSilencingProc
|
||||
command: ["bash", "-lc", root.commandWithOmarchyPath(root.shellQuote(root.omarchyPath + "/shell/scripts/indicators/notification-silencing.sh"))]
|
||||
command: ["bash", "-lc", root.shellQuote(root.omarchyPath + "/shell/scripts/indicators/notification-silencing.sh")]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateIndicator("notifications", text)
|
||||
@@ -1037,7 +1032,7 @@ Item {
|
||||
|
||||
Process {
|
||||
id: customProc
|
||||
command: ["bash", "-lc", root.commandWithOmarchyPath(String(customRoot.setting("exec", "")))]
|
||||
command: ["bash", "-lc", String(customRoot.setting("exec", ""))]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: customRoot.update(text)
|
||||
|
||||
@@ -33,11 +33,17 @@ Item {
|
||||
|
||||
Process {
|
||||
id: statusProc
|
||||
command: ["bash", "-lc", "pgrep -x hypridle >/dev/null 2>&1 && echo running || echo stopped"]
|
||||
command: ["bash", "-lc", "omarchy-shell idle status 2>/dev/null"]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: {
|
||||
root.active = String(text || "").trim() === "stopped"
|
||||
var raw = String(text || "").trim()
|
||||
try {
|
||||
var parsed = JSON.parse(raw)
|
||||
root.active = parsed && parsed.enabled === false
|
||||
} catch (e) {
|
||||
root.active = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,7 +71,7 @@ Item {
|
||||
bar: root.bar
|
||||
text: root.icon
|
||||
active: false
|
||||
tooltipText: root.active ? "No sleep, lock, or screensaver" : ""
|
||||
tooltipText: root.active ? "No lock or screensaver" : ""
|
||||
onPressed: function() { root.toggle() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1328,7 +1328,7 @@ iwctl known-networks list 2>/dev/null \\
|
||||
// Bar.qml does not need to mirror network state.
|
||||
Process {
|
||||
id: networkProc
|
||||
command: ["bash", "-lc", root.bar ? root.bar.commandWithOmarchyPath(root.networkCommand()) : ""]
|
||||
command: ["bash", "-lc", root.bar ? root.networkCommand() : ""]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateNetwork(text)
|
||||
|
||||
@@ -552,7 +552,7 @@ Item {
|
||||
// Poll the weather pill text/class every minute. Local to this widget.
|
||||
Process {
|
||||
id: weatherProc
|
||||
command: ["bash", "-lc", root.bar ? root.bar.commandWithOmarchyPath(root.bar.shellQuote(root.bar.omarchyPath + "/shell/scripts/weather.sh")) : ""]
|
||||
command: ["bash", "-lc", root.bar ? root.bar.shellQuote(root.bar.omarchyPath + "/shell/scripts/weather.sh") : ""]
|
||||
stdout: StdioCollector {
|
||||
waitForEnd: true
|
||||
onStreamFinished: root.updateWeather(text)
|
||||
|
||||
@@ -7,7 +7,7 @@ import qs.Commons
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
|
||||
property string omarchyPath: Quickshell.env("OMARCHY_PATH")
|
||||
property var shell: null
|
||||
property var manifest: null
|
||||
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Injected by omarchy-shell (the first-party service loader).
|
||||
property var shell: null
|
||||
|
||||
readonly property int defaultScreensaverSeconds: 150
|
||||
readonly property int defaultLockSeconds: 300
|
||||
readonly property var idleConfig: shell && shell.shellConfig && shell.shellConfig.idle ? shell.shellConfig.idle : ({})
|
||||
readonly property int screensaverTimeoutSeconds: secondsFromConfig(idleConfig.screensaver, defaultScreensaverSeconds)
|
||||
readonly property int lockTimeoutSeconds: secondsFromConfig(idleConfig.lock, defaultLockSeconds)
|
||||
readonly property int firstIdleTimeoutSeconds: Math.min(screensaverTimeoutSeconds, lockTimeoutSeconds)
|
||||
readonly property int screensaverDelaySeconds: Math.max(0, screensaverTimeoutSeconds - firstIdleTimeoutSeconds)
|
||||
readonly property int lockDelaySeconds: Math.max(0, lockTimeoutSeconds - firstIdleTimeoutSeconds)
|
||||
readonly property bool idleEnabled: persisted.idleEnabled
|
||||
|
||||
property bool idledThisCycle: false
|
||||
property bool screensaverStartedThisCycle: false
|
||||
|
||||
PersistentProperties {
|
||||
id: persisted
|
||||
reloadableId: "omarchy-idle"
|
||||
property bool idleEnabled: true
|
||||
}
|
||||
|
||||
function secondsFromConfig(value, fallback) {
|
||||
var n = Number(value)
|
||||
if (!isFinite(n) || n < 0) return fallback
|
||||
return Math.floor(n)
|
||||
}
|
||||
|
||||
function runProcess(process, command) {
|
||||
if (process.running) return false
|
||||
process.command = ["bash", "-lc", command]
|
||||
process.running = true
|
||||
return true
|
||||
}
|
||||
|
||||
function launchScreensaver() {
|
||||
root.screensaverStartedThisCycle = true
|
||||
runProcess(screensaverProcess, "pidof hyprlock >/dev/null || omarchy-launch-screensaver")
|
||||
}
|
||||
|
||||
function lockSystem() {
|
||||
screensaverTimer.stop()
|
||||
lockTimer.stop()
|
||||
screensaverResumePollTimer.stop()
|
||||
root.idledThisCycle = false
|
||||
root.screensaverStartedThisCycle = false
|
||||
runProcess(lockProcess, "omarchy-system-lock")
|
||||
}
|
||||
|
||||
function startIdleCycle() {
|
||||
if (root.idledThisCycle) return
|
||||
|
||||
root.idledThisCycle = true
|
||||
root.screensaverStartedThisCycle = false
|
||||
screensaverResumePollTimer.stop()
|
||||
|
||||
if (root.screensaverDelaySeconds === 0) launchScreensaver()
|
||||
else screensaverTimer.restart()
|
||||
|
||||
if (root.lockDelaySeconds === 0) lockSystem()
|
||||
else lockTimer.restart()
|
||||
}
|
||||
|
||||
function cancelIdleCycle() {
|
||||
screensaverTimer.stop()
|
||||
lockTimer.stop()
|
||||
screensaverResumePollTimer.stop()
|
||||
|
||||
if (root.idledThisCycle) runProcess(wakeProcess, "omarchy-system-wake")
|
||||
|
||||
root.idledThisCycle = false
|
||||
root.screensaverStartedThisCycle = false
|
||||
}
|
||||
|
||||
function checkScreensaverAfterActiveSignal() {
|
||||
if (!root.idledThisCycle || !root.screensaverStartedThisCycle) return
|
||||
if (screensaverCheckProcess.running) return
|
||||
screensaverCheckProcess.command = ["bash", "-lc", "pgrep -f org.omarchy.screensaver >/dev/null && echo running || echo stopped"]
|
||||
screensaverCheckProcess.running = true
|
||||
}
|
||||
|
||||
function handleActiveSignal() {
|
||||
if (!root.idledThisCycle) return
|
||||
|
||||
// Starting the screensaver can make the compositor report activity. Keep
|
||||
// the lock timer running while the screensaver is still alive so the lock
|
||||
// deadline remains `idle.lock` seconds from the original user idle time.
|
||||
if (root.screensaverStartedThisCycle) {
|
||||
screensaverResumePollTimer.restart()
|
||||
return
|
||||
}
|
||||
|
||||
cancelIdleCycle()
|
||||
}
|
||||
|
||||
function handleIdleChanged() {
|
||||
if (!root.idleEnabled) return
|
||||
|
||||
if (idleMonitor.isIdle) startIdleCycle()
|
||||
else handleActiveSignal()
|
||||
}
|
||||
|
||||
function statusJson() {
|
||||
return JSON.stringify({
|
||||
enabled: root.idleEnabled,
|
||||
idle: idleMonitor.isIdle,
|
||||
inIdleCycle: root.idledThisCycle,
|
||||
sleepMonitor: sleepMonitorProcess.running,
|
||||
screensaver: root.screensaverTimeoutSeconds,
|
||||
lock: root.lockTimeoutSeconds
|
||||
})
|
||||
}
|
||||
|
||||
function handleSleepPreparing(preparing) {
|
||||
if (!root.idleEnabled) return
|
||||
|
||||
if (preparing) {
|
||||
cancelIdleCycle()
|
||||
runProcess(sleepLockProcess, "OMARCHY_LOCK_ONLY=true omarchy-system-lock")
|
||||
} else {
|
||||
runProcess(sleepWakeProcess, "sleep 1 && omarchy-system-wake")
|
||||
}
|
||||
}
|
||||
|
||||
function setIdleEnabled(value) {
|
||||
var enabled = !!value
|
||||
if (persisted.idleEnabled === enabled) return enabled ? "enabled" : "disabled"
|
||||
|
||||
persisted.idleEnabled = enabled
|
||||
if (!enabled) cancelIdleCycle()
|
||||
else Qt.callLater(root.handleIdleChanged)
|
||||
|
||||
return enabled ? "enabled" : "disabled"
|
||||
}
|
||||
|
||||
IdleMonitor {
|
||||
id: idleMonitor
|
||||
enabled: root.idleEnabled
|
||||
timeout: root.firstIdleTimeoutSeconds
|
||||
respectInhibitors: true
|
||||
onIsIdleChanged: root.handleIdleChanged()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: screensaverTimer
|
||||
interval: root.screensaverDelaySeconds * 1000
|
||||
repeat: false
|
||||
onTriggered: root.launchScreensaver()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: lockTimer
|
||||
interval: root.lockDelaySeconds * 1000
|
||||
repeat: false
|
||||
onTriggered: if (root.idleEnabled && root.idledThisCycle) root.lockSystem()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: screensaverResumePollTimer
|
||||
interval: 1000
|
||||
repeat: true
|
||||
onTriggered: root.checkScreensaverAfterActiveSignal()
|
||||
}
|
||||
|
||||
Process { id: screensaverProcess }
|
||||
Process { id: lockProcess }
|
||||
Process { id: wakeProcess }
|
||||
Process { id: sleepLockProcess }
|
||||
Process { id: sleepWakeProcess }
|
||||
|
||||
Process {
|
||||
id: screensaverCheckProcess
|
||||
stdout: StdioCollector {
|
||||
id: screensaverCheckStdout
|
||||
waitForEnd: true
|
||||
}
|
||||
onExited: {
|
||||
if (!root.idledThisCycle || !root.screensaverStartedThisCycle) return
|
||||
if (String(screensaverCheckStdout.text || "").trim() === "running") return
|
||||
root.cancelIdleCycle()
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: sleepMonitorProcess
|
||||
command: ["bash", "-lc", "exec dbus-monitor --system \"type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Manager',member='PrepareForSleep'\""]
|
||||
running: true
|
||||
stdout: SplitParser {
|
||||
onRead: function(line) {
|
||||
var text = String(line || "").trim()
|
||||
if (text === "boolean true") root.handleSleepPreparing(true)
|
||||
else if (text === "boolean false") root.handleSleepPreparing(false)
|
||||
}
|
||||
}
|
||||
onExited: sleepMonitorRestartTimer.restart()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: sleepMonitorRestartTimer
|
||||
interval: 5000
|
||||
repeat: false
|
||||
onTriggered: if (!sleepMonitorProcess.running) sleepMonitorProcess.running = true
|
||||
}
|
||||
|
||||
Component.onCompleted: Qt.callLater(root.handleIdleChanged)
|
||||
|
||||
IpcHandler {
|
||||
target: "idle"
|
||||
|
||||
function status(): string {
|
||||
return root.statusJson()
|
||||
}
|
||||
|
||||
function enable(): string {
|
||||
return root.setIdleEnabled(true)
|
||||
}
|
||||
|
||||
function disable(): string {
|
||||
return root.setIdleEnabled(false)
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
return root.setIdleEnabled(!root.idleEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "omarchy.idle",
|
||||
"name": "Idle Monitor",
|
||||
"version": "1.0.0",
|
||||
"author": "Omarchy",
|
||||
"description": "Quickshell-based idle detection for screensaver, lock, and display wake.",
|
||||
"kinds": [
|
||||
"service"
|
||||
],
|
||||
"keepLoaded": true,
|
||||
"entryPoints": {
|
||||
"service": "Service.qml"
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,8 @@ import qs.Commons
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Injected by omarchy-shell so helper scripts resolve without relying on
|
||||
// OMARCHY_PATH being set in the environment.
|
||||
property string omarchyPath: ""
|
||||
// Injected by omarchy-shell; defaults to the session OMARCHY_PATH.
|
||||
property string omarchyPath: Quickshell.env("OMARCHY_PATH")
|
||||
property string imageDirs: Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIRS") || Quickshell.env("OMARCHY_IMAGE_SELECTOR_DIR") || Quickshell.env("OMARCHY_STOCK_BACKGROUNDS_DIR") || (Quickshell.env("HOME") + "/.config/omarchy/current/theme/backgrounds")
|
||||
property string imageRows: ""
|
||||
property string loadedImageRows: ""
|
||||
@@ -53,8 +52,7 @@ Item {
|
||||
}
|
||||
|
||||
function scriptPath(name) {
|
||||
var base = omarchyPath || Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
|
||||
return base + "/shell/scripts/" + name
|
||||
return omarchyPath + "/shell/scripts/" + name
|
||||
}
|
||||
|
||||
function focusPicker() {
|
||||
|
||||
@@ -8,7 +8,7 @@ Item {
|
||||
id: root
|
||||
|
||||
// Injected by omarchy-shell when this plugin is summoned.
|
||||
property string omarchyPath: Quickshell.env("OMARCHY_PATH") || (Quickshell.env("HOME") + "/.local/share/omarchy")
|
||||
property string omarchyPath: Quickshell.env("OMARCHY_PATH")
|
||||
|
||||
// Plugin lifecycle hooks. The host calls open(payloadJson) after
|
||||
// `omarchy-shell shell summon omarchy.menu ...` and close() when hidden.
|
||||
|
||||
@@ -33,17 +33,7 @@ Item {
|
||||
property var shell: null
|
||||
|
||||
// ---------------- paths --------------------------------------------------
|
||||
property string omarchyPath: {
|
||||
var env = Quickshell.env("OMARCHY_PATH")
|
||||
if (env) return env
|
||||
var dir = String(Quickshell.shellDir || "")
|
||||
while (dir.length > 1 && dir.charAt(dir.length - 1) === "/")
|
||||
dir = dir.substring(0, dir.length - 1)
|
||||
var suffix = "/shell"
|
||||
if (dir.length > suffix.length && dir.substring(dir.length - suffix.length) === suffix)
|
||||
return dir.substring(0, dir.length - suffix.length)
|
||||
return Quickshell.env("HOME") + "/.local/share/omarchy"
|
||||
}
|
||||
property string omarchyPath: Quickshell.env("OMARCHY_PATH")
|
||||
readonly property string home: Quickshell.env("HOME")
|
||||
readonly property string userConfigPath: home + "/.config/omarchy/shell.json"
|
||||
readonly property string defaultsPath: omarchyPath + "/shell/shell-defaults.json"
|
||||
|
||||
Reference in New Issue
Block a user