summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/BeatDetector.qml2
-rw-r--r--services/Bluetooth.qml52
-rw-r--r--services/Brightness.qml25
-rw-r--r--services/Hyprland.qml15
-rw-r--r--services/Network.qml48
-rw-r--r--services/SystemUsage.qml83
-rw-r--r--services/Wallpapers.qml12
-rw-r--r--services/Weather.qml28
8 files changed, 146 insertions, 119 deletions
diff --git a/services/BeatDetector.qml b/services/BeatDetector.qml
index 66bf2d4..196d40c 100644
--- a/services/BeatDetector.qml
+++ b/services/BeatDetector.qml
@@ -10,7 +10,7 @@ Singleton {
Process {
running: true
- command: [`${Quickshell.shellRoot}/assets/realtime-beat-detector.py`]
+ command: [`${Quickshell.configDir}/assets/realtime-beat-detector.py`]
stdout: SplitParser {
onRead: data => root.bpm = parseFloat(data)
}
diff --git a/services/Bluetooth.qml b/services/Bluetooth.qml
index 43f3636..f5e9de1 100644
--- a/services/Bluetooth.qml
+++ b/services/Bluetooth.qml
@@ -24,31 +24,47 @@ Singleton {
Process {
id: getInfo
+
running: true
- command: ["sh", "-c", "bluetoothctl show | paste -s"]
- stdout: SplitParser {
- onRead: data => {
- root.powered = data.includes("Powered: yes");
- root.discovering = data.includes("Discovering: yes");
+ command: ["bluetoothctl", "show"]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ root.powered = text.includes("Powered: yes");
+ root.discovering = text.includes("Discovering: yes");
}
}
}
Process {
id: getDevices
+
running: true
- command: ["fish", "-c", `for a in (bluetoothctl devices | cut -d ' ' -f 2); bluetoothctl info $a | jq -R 'reduce (inputs / ":") as [$key, $value] ({}; .[$key | ltrimstr("\t")] = ($value | ltrimstr(" ")))' | jq -c --arg addr $a '.Address = $addr'; end | jq -sc`]
- stdout: SplitParser {
- onRead: data => {
- const devices = JSON.parse(data).filter(d => d.Name);
+ command: ["fish", "-c", `
+ for a in (bluetoothctl devices)
+ if string match -q 'Device *' $a
+ bluetoothctl info $addr (string split ' ' $a)[2]
+ echo
+ end
+ end`]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const devices = text.trim().split("\n\n").map(d => ({
+ name: d.match(/Name: (.*)/)[1],
+ alias: d.match(/Alias: (.*)/)[1],
+ address: d.match(/Device ([0-9A-Z:]{17})/)[1],
+ icon: d.match(/Icon: (.*)/)[1],
+ connected: d.includes("Connected: yes"),
+ paired: d.includes("Paired: yes"),
+ trusted: d.includes("Trusted: yes")
+ }));
const rDevices = root.devices;
- const destroyed = rDevices.filter(rd => !devices.find(d => d.Address === rd.address));
+ const destroyed = rDevices.filter(rd => !devices.find(d => d.address === rd.address));
for (const device of destroyed)
rDevices.splice(rDevices.indexOf(device), 1).forEach(d => d.destroy());
for (const device of devices) {
- const match = rDevices.find(d => d.address === device.Address);
+ const match = rDevices.find(d => d.address === device.address);
if (match) {
match.lastIpcObject = device;
} else {
@@ -63,13 +79,13 @@ Singleton {
component Device: QtObject {
required property var lastIpcObject
- readonly property string name: lastIpcObject.Name
- readonly property string alias: lastIpcObject.Alias
- readonly property string address: lastIpcObject.Address
- readonly property string icon: lastIpcObject.Icon
- readonly property bool connected: lastIpcObject.Connected === "yes"
- readonly property bool paired: lastIpcObject.Paired === "yes"
- readonly property bool trusted: lastIpcObject.Trusted === "yes"
+ readonly property string name: lastIpcObject.name
+ readonly property string alias: lastIpcObject.alias
+ readonly property string address: lastIpcObject.address
+ readonly property string icon: lastIpcObject.icon
+ readonly property bool connected: lastIpcObject.connected
+ readonly property bool paired: lastIpcObject.paired
+ readonly property bool trusted: lastIpcObject.trusted
}
Component {
diff --git a/services/Brightness.qml b/services/Brightness.qml
index 1687878..3715853 100644
--- a/services/Brightness.qml
+++ b/services/Brightness.qml
@@ -9,7 +9,7 @@ import QtQuick
Singleton {
id: root
- property var ddcMonitors: []
+ property list<var> ddcMonitors: []
readonly property list<Monitor> monitors: variants.instances
function getMonitorForScreen(screen: ShellScreen): var {
@@ -49,19 +49,12 @@ Singleton {
id: ddcProc
command: ["ddcutil", "detect", "--brief"]
- stdout: SplitParser {
- splitMarker: "\n\n"
- onRead: data => {
- if (data.startsWith("Display ")) {
- const lines = data.split("\n").map(l => l.trim());
- root.ddcMonitors.push({
- model: lines.find(l => l.startsWith("Monitor:")).split(":")[2],
- busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1]
- });
- }
- }
+ stdout: StdioCollector {
+ onStreamFinished: root.ddcMonitors = text.trim().split("\n\n").filter(d => d.startsWith("Display ")).map(d => ({
+ model: d.match(/Monitor:.*:(.*):.*/)[1],
+ busNum: d.match(/I2C bus:[ ]*\/dev\/i2c-([0-9]+)/)[1]
+ }))
}
- onExited: root.ddcMonitorsChanged()
}
Process {
@@ -87,9 +80,9 @@ Singleton {
property real brightness
readonly property Process initProc: Process {
- stdout: SplitParser {
- onRead: data => {
- const [, , , current, max] = data.split(" ");
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const [, , , current, max] = text.split(" ");
monitor.brightness = parseInt(current) / parseInt(max);
}
}
diff --git a/services/Hyprland.qml b/services/Hyprland.qml
index 610fba2..b8fa7c5 100644
--- a/services/Hyprland.qml
+++ b/services/Hyprland.qml
@@ -41,10 +41,10 @@ Singleton {
Process {
id: getClients
- command: ["sh", "-c", "hyprctl -j clients | jq -c"]
- stdout: SplitParser {
- onRead: data => {
- const clients = JSON.parse(data);
+ command: ["hyprctl", "-j", "clients"]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const clients = JSON.parse(text);
const rClients = root.clients;
const destroyed = rClients.filter(rc => !clients.find(c => c.address === rc.address));
@@ -68,10 +68,9 @@ Singleton {
Process {
id: getActiveClient
command: ["hyprctl", "-j", "activewindow"]
- stdout: SplitParser {
- splitMarker: ""
- onRead: data => {
- const client = JSON.parse(data);
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const client = JSON.parse(text);
const rClient = root.activeClient;
if (client.address) {
if (rClient)
diff --git a/services/Network.qml b/services/Network.qml
index b4827c8..6a7f50e 100644
--- a/services/Network.qml
+++ b/services/Network.qml
@@ -23,31 +23,36 @@ Singleton {
Process {
id: getNetworks
running: true
- command: ["sh", "-c", `nmcli -g ACTIVE,SIGNAL,FREQ,SSID,BSSID d w | jq -ncR '[(inputs | split("(?<!\\\\\\\\):"; "g")) | select(.[3] | length >= 4)]'`]
- stdout: SplitParser {
- onRead: data => {
- const networks = JSON.parse(data).map(n => [n[0] === "yes", parseInt(n[1]), parseInt(n[2]), n[3], n[4].replace(/\\/g, "")]);
+ command: ["nmcli", "-g", "ACTIVE,SIGNAL,FREQ,SSID,BSSID", "d", "w"]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED";
+ const rep = new RegExp("\\\\:", "g");
+ const rep2 = new RegExp(PLACEHOLDER, "g");
+
+ const networks = text.trim().split("\n").map(n => {
+ const net = n.replace(rep, PLACEHOLDER).split(":");
+ return {
+ active: net[0] === "yes",
+ strength: parseInt(net[1]),
+ frequency: parseInt(net[2]),
+ ssid: net[3],
+ bssid: net[4].replace(rep2, ":")
+ };
+ });
const rNetworks = root.networks;
- const destroyed = rNetworks.filter(rn => !networks.find(n => n[2] === rn.frequency && n[3] === rn.ssid && n[4] === rn.bssid));
+ const destroyed = rNetworks.filter(rn => !networks.find(n => n.frequency === rn.frequency && n.ssid === rn.ssid && n.bssid === rn.bssid));
for (const network of destroyed)
rNetworks.splice(rNetworks.indexOf(network), 1).forEach(n => n.destroy());
for (const network of networks) {
- const match = rNetworks.find(n => n.frequency === network[2] && n.ssid === network[3] && n.bssid === network[4]);
+ const match = rNetworks.find(n => n.frequency === network.frequency && n.ssid === network.ssid && n.bssid === network.bssid);
if (match) {
- match.active = network[0];
- match.strength = network[1];
- match.frequency = network[2];
- match.ssid = network[3];
- match.bssid = network[4];
+ match.lastIpcObject = network;
} else {
rNetworks.push(apComp.createObject(root, {
- active: network[0],
- strength: network[1],
- frequency: network[2],
- ssid: network[3],
- bssid: network[4]
+ lastIpcObject: network
}));
}
}
@@ -56,11 +61,12 @@ Singleton {
}
component AccessPoint: QtObject {
- required property string ssid
- required property string bssid
- required property int strength
- required property int frequency
- required property bool active
+ required property var lastIpcObject
+ readonly property string ssid: lastIpcObject.ssid
+ readonly property string bssid: lastIpcObject.bssid
+ readonly property int strength: lastIpcObject.strength
+ readonly property int frequency: lastIpcObject.frequency
+ readonly property bool active: lastIpcObject.active
}
Component {
diff --git a/services/SystemUsage.qml b/services/SystemUsage.qml
index ef953f1..9bf665a 100644
--- a/services/SystemUsage.qml
+++ b/services/SystemUsage.qml
@@ -98,38 +98,40 @@ Singleton {
running: true
command: ["sh", "-c", "df | grep '^/dev/' | awk '{print $1, $3, $4}'"]
- stdout: SplitParser {
- splitMarker: ""
- onRead: data => {
- const deviceMap = new Map();
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const deviceMap = new Map();
- for (const line of data.trim().split("\n")) {
- if (line.trim() === "") continue;
+ for (const line of text.trim().split("\n")) {
+ if (line.trim() === "")
+ continue;
- const parts = line.trim().split(/\s+/);
- if (parts.length >= 3) {
- const device = parts[0];
- const used = parseInt(parts[1], 10) || 0;
- const avail = parseInt(parts[2], 10) || 0;
-
- // only keep the entry with the largest total space for each device
- if (!deviceMap.has(device) ||
- (used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) {
- deviceMap.set(device, { used: used, avail: avail });
- }
- }
- }
+ const parts = line.trim().split(/\s+/);
+ if (parts.length >= 3) {
+ const device = parts[0];
+ const used = parseInt(parts[1], 10) || 0;
+ const avail = parseInt(parts[2], 10) || 0;
- let totalUsed = 0;
- let totalAvail = 0;
-
- for (const [device, stats] of deviceMap) {
- totalUsed += stats.used;
- totalAvail += stats.avail;
- }
+ // Only keep the entry with the largest total space for each device
+ if (!deviceMap.has(device) || (used + avail) > (deviceMap.get(device).used + deviceMap.get(device).avail)) {
+ deviceMap.set(device, {
+ used: used,
+ avail: avail
+ });
+ }
+ }
+ }
+
+ let totalUsed = 0;
+ let totalAvail = 0;
- root.storageUsed = totalUsed;
- root.storageTotal = totalUsed + totalAvail;
+ for (const [device, stats] of deviceMap) {
+ totalUsed += stats.used;
+ totalAvail += stats.avail;
+ }
+
+ root.storageUsed = totalUsed;
+ root.storageTotal = totalUsed + totalAvail;
}
}
}
@@ -138,10 +140,10 @@ Singleton {
id: cpuTemp
running: true
- command: ["fish", "-c", "cat /sys/class/thermal/thermal_zone*/temp | string join ' '"]
- stdout: SplitParser {
- onRead: data => {
- const temps = data.trim().split(" ");
+ command: ["sh", "-c", "cat /sys/class/thermal/thermal_zone*/temp"]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const temps = text.trim().split(" ");
const sum = temps.reduce((acc, d) => acc + parseInt(d, 10), 0);
root.cpuTemp = sum / temps.length / 1000;
}
@@ -153,10 +155,9 @@ Singleton {
running: true
command: ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"]
- stdout: SplitParser {
- splitMarker: ""
- onRead: data => {
- const percs = data.trim().split("\n");
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const percs = text.trim().split("\n");
const sum = percs.reduce((acc, d) => acc + parseInt(d, 10), 0);
root.gpuPerc = sum / percs.length / 100;
}
@@ -167,13 +168,14 @@ Singleton {
id: gpuTemp
running: true
- command: ["sh", "-c", "sensors | jq -nRc '[inputs]'"]
- stdout: SplitParser {
- onRead: data => {
+ command: ["sensors"]
+ stdout: StdioCollector {
+ onStreamFinished: {
let eligible = false;
let sum = 0;
let count = 0;
- for (const line of JSON.parse(data)) {
+
+ for (const line of text.trim().split("\n")) {
if (line === "Adapter: PCI adapter")
eligible = true;
else if (line === "")
@@ -186,6 +188,7 @@ Singleton {
}
}
}
+
root.gpuTemp = count > 0 ? sum / count : 0;
}
}
diff --git a/services/Wallpapers.qml b/services/Wallpapers.qml
index dd6a9f7..ef0eb3d 100644
--- a/services/Wallpapers.qml
+++ b/services/Wallpapers.qml
@@ -78,10 +78,9 @@ Singleton {
id: getPreviewColoursProc
command: ["caelestia", "wallpaper", "-p", root.previewPath]
- stdout: SplitParser {
- splitMarker: ""
- onRead: data => {
- Colours.load(data, true);
+ stdout: StdioCollector {
+ onStreamFinished: {
+ Colours.load(text, true);
Colours.showPreview = true;
}
}
@@ -98,9 +97,8 @@ Singleton {
Process {
running: true
command: ["fd", ".", root.path, "-t", "f", "-e", "jpg", "-e", "jpeg", "-e", "png", "-e", "webp", "-e", "tif", "-e", "tiff"]
- stdout: SplitParser {
- splitMarker: ""
- onRead: data => wallpapers.model = data.trim().split("\n")
+ stdout: StdioCollector {
+ onStreamFinished: wallpapers.model = text.trim().split("\n")
}
}
diff --git a/services/Weather.qml b/services/Weather.qml
index 13503f9..4f53d0b 100644
--- a/services/Weather.qml
+++ b/services/Weather.qml
@@ -7,6 +7,7 @@ import Quickshell.Io
Singleton {
id: root
+ property string loc
property string icon
property string description
property real temperature
@@ -15,17 +16,28 @@ Singleton {
wttrProc.running = true;
}
+ onLocChanged: wttrProc.running = true
+
Process {
- id: wttrProc
+ id: ipProc
running: true
- command: ["fish", "-c", `curl "https://wttr.in/$(curl ipinfo.io | jq -r '.city' | string replace -a ' ' '%20')?format=j1" | jq -c '.current_condition[0] | {code: .weatherCode, desc: .weatherDesc[0].value, temp: .temp_C}'`]
- stdout: SplitParser {
- onRead: data => {
- const json = JSON.parse(data);
- root.icon = Icons.getWeatherIcon(json.code);
- root.description = json.desc;
- root.temperature = parseFloat(json.temp);
+ command: ["curl", "ipinfo.io"]
+ stdout: StdioCollector {
+ onStreamFinished: root.loc = JSON.parse(text).loc
+ }
+ }
+
+ Process {
+ id: wttrProc
+
+ command: ["curl", `https://wttr.in/${root.loc}?format=j1`]
+ stdout: StdioCollector {
+ onStreamFinished: {
+ const json = JSON.parse(text).current_condition[0];
+ root.icon = Icons.getWeatherIcon(json.weatherCode);
+ root.description = json.weatherDesc[0].value;
+ root.temperature = parseFloat(json.temp_C);
}
}
}