Remove legacy bar widget modules

This commit is contained in:
Ryan Hughes
2026-05-18 02:33:43 -04:00
parent 713a32e61d
commit 8272c6d881
5 changed files with 108 additions and 307 deletions
@@ -1,8 +1,6 @@
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Hyprland
import Quickshell.Io
import Quickshell.Services.Pipewire
import Quickshell.Services.SystemTray
import Quickshell.Services.UPower
import Quickshell.Wayland
@@ -58,22 +56,13 @@ Item {
Behavior on foreground { ColorAnimation { duration: 420; easing.type: Easing.InOutCubic } }
Behavior on background { ColorAnimation { duration: 420; easing.type: Easing.InOutCubic } }
Behavior on urgent { ColorAnimation { duration: 420; easing.type: Easing.InOutCubic } }
property string weatherText: ""
property string weatherClass: ""
property bool updateAvailable: false
property string voxtypeIcon: ""
property string voxtypeClass: ""
property string screenRecordingText: ""
property string screenRecordingTooltip: ""
property string idleText: ""
property string idleTooltip: ""
property string notificationSilencingText: ""
property string notificationSilencingTooltip: ""
property int audioVolumePercent: -1
property string networkKind: "disconnected"
property string networkLabel: ""
property int networkSignal: -1
property string networkFrequency: ""
property bool clockAlt: false
property var tooltipTarget: null
property string tooltipText: ""
@@ -223,20 +212,13 @@ Item {
case "omarchy": return omarchyModuleComponent
case "workspaces": return workspacesModuleComponent
case "clock": return clockModuleComponent
case "weather": return weatherModuleComponent
case "update": return updateModuleComponent
case "voxtype": return voxtypeModuleComponent
case "screenRecording":
case "screenrecording": return screenRecordingModuleComponent
case "idle": return idleModuleComponent
case "notifications":
case "notificationSilencing": return notificationsModuleComponent
case "tray": return trayModuleComponent
case "bluetooth": return bluetoothModuleComponent
case "network": return networkModuleComponent
case "audio":
case "pulseaudio": return audioModuleComponent
case "cpu": return cpuModuleComponent
case "battery": return batteryModuleComponent
default: return null
}
@@ -338,37 +320,6 @@ Item {
else finalize()
}
function networkCommand() {
return [
"device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == \"dev\") { print $(i + 1); exit } }')",
"if [[ -z $device ]]; then",
" printf 'disconnected\\t\\t\\t\\n'",
" exit 0",
"fi",
"if [[ ! -d /sys/class/net/$device/wireless ]]; then",
" printf 'ethernet\\t%s\\t\\t\\n' \"$device\"",
" exit 0",
"fi",
"show=$(iwctl station \"$device\" show 2>/dev/null | sed -e 's/\\x1b\\[[0-9;]*m//g')",
"state=$(awk '/^[[:space:]]*State[[:space:]]/ { sub(/.*State[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"ssid=$(awk '/^[[:space:]]*Connected network[[:space:]]/ { sub(/.*Connected network[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"freq=$(awk '/^[[:space:]]*Frequency[[:space:]]/ { sub(/.*Frequency[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"rssi=$(awk '/^[[:space:]]*RSSI[[:space:]]/ { sub(/.*RSSI[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"dbm=${rssi%% *}",
"signal=\"\"",
"if [[ -n $dbm ]]; then",
" if (( dbm >= -50 )); then signal=100",
" elif (( dbm <= -100 )); then signal=0",
" else signal=$(( 2 * (dbm + 100) )); fi",
"fi",
"if [[ -n $state && $state != connected ]]; then",
" printf 'disconnected\\t\\t\\t\\n'",
" exit 0",
"fi",
"printf 'wifi\\t%s\\t%s\\t%s\\n' \"${ssid:-$device}\" \"$signal\" \"$freq\""
].join("\n")
}
function run(command) {
if (!command) return
@@ -431,12 +382,6 @@ Item {
}
}
function updateWeather(raw) {
var data = parseModuleJson(raw)
weatherText = data.text || ""
weatherClass = data.class || ""
}
function updateIndicator(name, raw) {
var data = parseModuleJson(raw)
var text = data.text || ""
@@ -445,9 +390,6 @@ Item {
if (name === "screenRecording") {
screenRecordingText = text
screenRecordingTooltip = tooltip
} else if (name === "idle") {
idleText = text
idleTooltip = tooltip
} else if (name === "notifications") {
notificationSilencingText = text
notificationSilencingTooltip = tooltip
@@ -464,18 +406,6 @@ Item {
else voxtypeIcon = ""
}
function updateNetwork(raw) {
var parts = String(raw || "disconnected\t\t\t").replace(/\r?\n+$/, "").split("\t")
networkKind = parts[0] || "disconnected"
networkLabel = parts[1] || ""
networkSignal = parts[2] ? parseInt(parts[2], 10) : -1
networkFrequency = parts[3] || ""
}
function refreshWeather() {
runProcess(weatherProc)
}
function refreshUpdate() {
runProcess(updateProc)
}
@@ -486,23 +416,9 @@ Item {
function refreshIndicators() {
refreshScreenRecording()
runProcess(idleProc)
runProcess(notificationSilencingProc)
}
function refreshNetwork() {
runProcess(networkProc)
}
function updateAudioVolume(raw) {
var volume = parseInt(String(raw || "").trim(), 10)
audioVolumePercent = isNaN(volume) ? -1 : Math.max(0, volume)
}
function refreshAudio() {
runProcess(audioProc)
}
function workspaceById(id) {
var values = Hyprland.workspaces.values
for (var i = 0; i < values.length; i++) {
@@ -553,95 +469,6 @@ Item {
return defaultIcons[index]
}
function audioIcon() {
var sink = Pipewire.defaultAudioSink
if (!sink || !sink.audio) return ""
if (sink.audio.muted) return ""
var props = sink.properties || {}
var sinkText = String([
sink.name,
sink.description,
sink.nickname,
props["device.icon-name"],
props["device.product.name"],
props["node.name"]
].join(" ")).toLowerCase()
if (sinkText.indexOf("headphone") !== -1 || sinkText.indexOf("headset") !== -1)
return ""
var volume = sink.audio.volume
if (!isFinite(volume) && audioVolumePercent >= 0)
volume = audioVolumePercent / 100
if (!isFinite(volume)) return ""
if (volume < 0.34) return ""
if (volume < 0.67) return ""
return ""
}
function bluetoothIcon() {
var adapter = Bluetooth.defaultAdapter
if (!adapter) return ""
if (!adapter.enabled) return "󰂲"
var devices = Bluetooth.devices.values
for (var i = 0; i < devices.length; i++) {
if (devices[i].connected)
return "󰂱"
}
return ""
}
function networkIcon() {
if (networkKind === "wifi") {
var icons = ["󰤯", "󰤟", "󰤢", "󰤥", "󰤨"]
var index = Math.max(0, Math.min(4, Math.ceil(networkSignal / 20) - 1))
return icons[index]
}
if (networkKind === "ethernet") return "󰀂"
return "󰤮"
}
function networkTooltip() {
if (networkKind === "wifi") {
var frequency = parseFloat(networkFrequency)
var frequencyText = frequency > 0 ? " (" + (frequency / 1000).toFixed(1) + " GHz)" : ""
return (networkLabel || "Wi-Fi") + frequencyText
}
if (networkKind === "ethernet") return "Connected"
return "Disconnected"
}
function audioTooltip() {
var sink = Pipewire.defaultAudioSink
if (sink && sink.audio) {
var volume = sink.audio.volume
if (isFinite(volume))
return "Playing at " + Math.round(volume * 100) + "%"
}
if (audioVolumePercent >= 0)
return "Playing at " + audioVolumePercent + "%"
return "Audio"
}
function bluetoothTooltip() {
var count = 0
var devices = Bluetooth.devices.values
for (var i = 0; i < devices.length; i++) {
if (devices[i].connected)
count++
}
return "Devices connected: " + count
}
function batteryTooltip() {
var device = UPower.displayDevice
if (!device || !device.isPresent) return ""
@@ -720,23 +547,6 @@ Item {
onFileChanged: barHiddenProbe.running = true
}
Process {
id: weatherProc
command: ["bash", "-lc", root.commandWithOmarchyPath(root.shellQuote(root.omarchyPath + "/default/quickshell/omarchy-shell/scripts/weather.sh"))]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateWeather(text)
}
}
Timer {
interval: 60000
running: true
repeat: true
triggeredOnStart: true
onTriggered: root.refreshWeather()
}
Process {
id: updateProc
command: ["bash", "-lc", root.commandWithOmarchyPath("omarchy-update-available")]
@@ -774,15 +584,6 @@ Item {
}
}
Process {
id: idleProc
command: ["bash", "-lc", root.commandWithOmarchyPath(root.shellQuote(root.omarchyPath + "/default/quickshell/omarchy-shell/scripts/indicators/idle.sh"))]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateIndicator("idle", text)
}
}
Process {
id: notificationSilencingProc
command: ["bash", "-lc", root.commandWithOmarchyPath(root.shellQuote(root.omarchyPath + "/default/quickshell/omarchy-shell/scripts/indicators/notification-silencing.sh"))]
@@ -800,40 +601,6 @@ Item {
onTriggered: root.refreshIndicators()
}
Process {
id: networkProc
command: ["bash", "-lc", root.commandWithOmarchyPath(root.networkCommand())]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateNetwork(text)
}
}
Timer {
interval: 3000
running: true
repeat: true
triggeredOnStart: true
onTriggered: root.refreshNetwork()
}
Process {
id: audioProc
command: ["bash", "-lc", "if command -v pamixer >/dev/null; then pamixer --get-volume; elif command -v wpctl >/dev/null; then wpctl get-volume @DEFAULT_AUDIO_SINK@ | awk '{ print int($2 * 100) }'; fi"]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateAudioVolume(text)
}
}
Timer {
interval: 2000
running: true
repeat: true
triggeredOnStart: true
onTriggered: root.refreshAudio()
}
IpcHandler {
target: "bar"
@@ -999,17 +766,11 @@ Item {
Component { id: omarchyModuleComponent; OmarchyModule {} }
Component { id: workspacesModuleComponent; WorkspacesModule {} }
Component { id: clockModuleComponent; ClockModule {} }
Component { id: weatherModuleComponent; WeatherModule {} }
Component { id: updateModuleComponent; UpdateModule {} }
Component { id: voxtypeModuleComponent; VoxtypeModule {} }
Component { id: screenRecordingModuleComponent; ScreenRecordingModule {} }
Component { id: idleModuleComponent; IdleModule {} }
Component { id: notificationsModuleComponent; NotificationsModule {} }
Component { id: trayModuleComponent; TrayModule {} }
Component { id: bluetoothModuleComponent; BluetoothModule {} }
Component { id: networkModuleComponent; NetworkModule {} }
Component { id: audioModuleComponent; AudioModule {} }
Component { id: cpuModuleComponent; CpuModule {} }
Component { id: batteryModuleComponent; BatteryModule {} }
function findCenterAnchorEntry() {
@@ -1405,14 +1166,6 @@ Item {
}
}
component WeatherModule: ModuleButton {
text: root.weatherText
active: root.weatherClass === "active"
keepSpace: false
horizontalMargin: 7.5
onPressed: function() { root.run("omarchy-notification-send \"$(omarchy-weather-status)\"") }
}
component UpdateModule: ModuleButton {
text: root.updateAvailable ? "" : ""
fontSize: 10
@@ -1437,13 +1190,6 @@ Item {
onPressed: function() { root.run("omarchy-capture-screenrecording") }
}
component IdleModule: IndicatorModule {
text: root.idleText
active: root.idleText !== ""
tooltipText: root.idleTooltip
onPressed: function() { root.run("omarchy-toggle-idle") }
}
component NotificationsModule: IndicatorModule {
text: root.notificationSilencingText
active: root.notificationSilencingText !== ""
@@ -1876,42 +1622,6 @@ Item {
}
}
component BluetoothModule: ModuleButton {
text: root.bluetoothIcon()
horizontalMargin: 8.5
visible: Bluetooth.defaultAdapter !== null
onPressed: function() { root.run("omarchy-launch-bluetooth") }
}
component NetworkModule: ModuleButton {
text: root.networkIcon()
horizontalMargin: 6.5
rightExtraMargin: 2
tooltipText: root.networkTooltip()
onPressed: function() { root.run("OMARCHY_PATH=" + root.shellQuote(root.omarchyPath) + " PATH=" + root.shellQuote(root.omarchyPath + "/bin:" + (Quickshell.env("PATH") || "")) + " " + root.shellQuote(root.omarchyPath + "/bin/omarchy-launch-wifi")) }
}
component AudioModule: ModuleButton {
text: root.audioIcon()
onPressed: function(button) {
if (button === Qt.RightButton) root.run("pamixer -t")
else root.run("omarchy-launch-audio")
}
onWheelMoved: function(delta) {
if (delta > 0) root.run("pamixer -i 5")
else if (delta < 0) root.run("pamixer -d 5")
root.refreshAudio()
}
}
component CpuModule: ModuleButton {
text: "󰍛"
onPressed: function(button) {
if (button === Qt.RightButton) root.run("alacritty")
else root.run("omarchy-launch-or-focus-tui btop")
}
}
component BatteryModule: ModuleButton {
property var device: UPower.displayDevice
@@ -148,9 +148,61 @@ iwctl known-networks list 2>/dev/null \\
if (net && net.connected) forget(net.ssid)
}
readonly property string kind: bar ? bar.networkKind : "disconnected"
readonly property string label: bar ? bar.networkLabel : ""
readonly property int signalStrength: bar ? bar.networkSignal : -1
// Bar pill state. Polled locally so this panel is self-contained;
// populated by networkProc + networkTimer below.
property string kind: "disconnected"
property string label: ""
property int signalStrength: -1
property string frequency: ""
function updateNetwork(raw) {
var parts = String(raw || "disconnected\t\t\t").replace(/\r?\n+$/, "").split("\t")
kind = parts[0] || "disconnected"
label = parts[1] || ""
signalStrength = parts[2] ? parseInt(parts[2], 10) : -1
frequency = parts[3] || ""
}
function networkTooltip() {
if (kind === "wifi") {
var f = parseFloat(frequency)
var ftext = f > 0 ? " (" + (f / 1000).toFixed(1) + " GHz)" : ""
return (label || "Wi-Fi") + ftext
}
if (kind === "ethernet") return "Connected"
return "Disconnected"
}
function networkCommand() {
return [
"device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == \"dev\") { print $(i + 1); exit } }')",
"if [[ -z $device ]]; then",
" printf 'disconnected\\t\\t\\t\\n'",
" exit 0",
"fi",
"if [[ ! -d /sys/class/net/$device/wireless ]]; then",
" printf 'ethernet\\t%s\\t\\t\\n' \"$device\"",
" exit 0",
"fi",
"show=$(iwctl station \"$device\" show 2>/dev/null | sed -e 's/\\x1b\\[[0-9;]*m//g')",
"state=$(awk '/^[[:space:]]*State[[:space:]]/ { sub(/.*State[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"ssid=$(awk '/^[[:space:]]*Connected network[[:space:]]/ { sub(/.*Connected network[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"freq=$(awk '/^[[:space:]]*Frequency[[:space:]]/ { sub(/.*Frequency[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"rssi=$(awk '/^[[:space:]]*RSSI[[:space:]]/ { sub(/.*RSSI[[:space:]]+/, \"\"); sub(/[[:space:]]+$/, \"\"); print; exit }' <<<\"$show\")",
"dbm=${rssi%% *}",
"signal=\"\"",
"if [[ -n $dbm ]]; then",
" if (( dbm >= -50 )); then signal=100",
" elif (( dbm <= -100 )); then signal=0",
" else signal=$(( 2 * (dbm + 100) )); fi",
"fi",
"if [[ -n $state && $state != connected ]]; then",
" printf 'disconnected\\t\\t\\t\\n'",
" exit 0",
"fi",
"printf 'wifi\\t%s\\t%s\\t%s\\n' \"${ssid:-$device}\" \"$signal\" \"$freq\""
].join("\n")
}
readonly property string icon: {
if (kind === "wifi") {
@@ -525,7 +577,7 @@ iwctl station "$station" get-networks rssi-dbms 2>/dev/null \\
text: root.icon
horizontalMargin: 8.5
rightExtraMargin: 2
tooltipText: bar ? bar.networkTooltip() : ""
tooltipText: root.networkTooltip()
onPressed: function(b) {
if (b === Qt.RightButton) root.launchImpala()
@@ -1146,4 +1198,23 @@ iwctl known-networks list 2>/dev/null \\
}
}
}
// Poll the wifi/ethernet pill state every 3s. Local to this panel so
// Bar.qml does not need to mirror network state.
Process {
id: networkProc
command: ["bash", "-lc", root.bar ? root.bar.commandWithOmarchyPath(root.networkCommand()) : ""]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateNetwork(text)
}
}
Timer {
interval: 3000
running: true
repeat: true
triggeredOnStart: true
onTriggered: if (!networkProc.running) networkProc.running = true
}
}
@@ -30,8 +30,16 @@ Item {
property var dailyForecastReport: null
property string wttrLocation: ""
readonly property string label: bar ? bar.weatherText : ""
readonly property string klass: bar ? bar.weatherClass : ""
// Bar pill state. Polled locally; populated by weatherProc below.
property string label: ""
property string klass: ""
function updateWeather(raw) {
var data
try { data = JSON.parse(raw || "{}") } catch (e) { data = {} }
label = data.text || ""
klass = data.class || ""
}
readonly property var current: report && report.current_condition && report.current_condition[0] ? report.current_condition[0] : null
readonly property var areaInfo: report && report.nearest_area && report.nearest_area[0] ? report.nearest_area[0] : null
@@ -533,4 +541,22 @@ 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 + "/default/quickshell/omarchy-shell/scripts/weather.sh")) : ""]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateWeather(text)
}
}
Timer {
interval: 60000
running: true
repeat: true
triggeredOnStart: true
onTriggered: if (!weatherProc.running) weatherProc.running = true
}
}
@@ -306,21 +306,15 @@ Item {
}
// ---------------- widget catalog -----------------------------------------
readonly property var legacyWidgetMeta: ({
readonly property var builtinWidgetMeta: ({
"omarchy": { name: "Omarchy menu", description: "Launches the Omarchy menu", category: "Compositor" },
"workspaces": { name: "Workspaces", description: "Workspace number indicators", category: "Compositor" },
"clock": { name: "Clock", description: "Date / time text", category: "Time" },
"weather": { name: "Weather (legacy)", description: "Tiny weather pill", category: "Info" },
"update": { name: "Updates", description: "Indicates available system updates", category: "System" },
"voxtype": { name: "Voxtype", description: "Voxtype dictation state", category: "Status" },
"screenRecording": { name: "Screen recording", description: "Active recording indicator", category: "Status" },
"idle": { name: "Idle (legacy)", description: "Inhibitor indicator", category: "Status" },
"notifications": { name: "DND", description: "Do-not-disturb indicator", category: "Status" },
"tray": { name: "System tray", description: "Status notifier items", category: "Status" },
"bluetooth": { name: "Bluetooth (legacy)", description: "Bluetooth status icon", category: "Network" },
"network": { name: "Network (legacy)", description: "Wi-Fi / ethernet status", category: "Network" },
"audio": { name: "Volume (legacy)", description: "Speaker icon, scroll for volume", category: "Audio" },
"cpu": { name: "CPU (legacy)", description: "btop launcher", category: "System" },
"battery": { name: "Battery", description: "Battery percent and ETA", category: "System" }
})
@@ -344,7 +338,7 @@ Item {
var key = String(id || "")
if (root.barWidgetRegistry && root.barWidgetRegistry.has(key))
return root.barWidgetRegistry.metadataFor(key) || {}
if (legacyWidgetMeta[key]) return legacyWidgetMeta[key]
if (builtinWidgetMeta[key]) return builtinWidgetMeta[key]
var manifest = root.pluginRegistry ? root.pluginRegistry.installedPlugins[key] : null
if (manifest) {
@@ -409,7 +403,7 @@ Item {
ids[pid] = true
}
}
for (var key in legacyWidgetMeta) ids[key] = true
for (var key in builtinWidgetMeta) ids[key] = true
return Object.keys(ids)
}
@@ -432,7 +426,7 @@ Item {
var manifest = root.pluginRegistry ? root.pluginRegistry.installedPlugins[id] : null
var manifestIsBarWidget = manifest && Array.isArray(manifest.kinds) && manifest.kinds.indexOf("bar-widget") !== -1
var isBarWidget = !!(meta && meta.source !== "plugin") || manifestIsBarWidget
if (!isBarWidget && !legacyWidgetMeta[id]) continue
if (!isBarWidget && !builtinWidgetMeta[id]) continue
var inSection = sectionArray(section)
var existsHere = false