Address momus review: fix icons, vertical layout, popup coordination

- Replace nerd font glyphs that were stripped during the initial widget
  writes with verified codepoints sourced from the JetBrains Mono Nerd
  Font cmap (cpu-64-bit, scale-balance, notification-clear-all, etc).
- systemStats now switches to a Column layout when the bar is vertical
  so the widget no longer overflows a 28px-wide side bar.
- Remove notificationCenter from defaults: it registers a notification
  server and would collide with the mako daemon Omarchy autostarts.
- PopupCard owns the popout coordinator lifecycle and delegates close to
  its widget owner when provided; calendar and media now pass owner.
- brightness debounces brightnessctl writes through a coalescing timer
  to avoid spawning a process per slider tick.
- audioPanel tracks unfiltered Pipewire sinks/streams via PwObjectTracker
  so audio metadata becomes available before filtering.
- ModuleSlot re-injects bar/moduleName/settings whenever the bar config
  serial changes so widget settings update live with bar.json.
- Guard null bar references in workspacesPro and systemStats components
  that are constructed before bar injection.
This commit is contained in:
Ryan Hughes
2026-05-14 02:21:47 -04:00
parent 221e0e1fcc
commit fe73986a01
13 changed files with 152 additions and 76 deletions
+2 -2
View File
@@ -4,8 +4,8 @@
"centerAnchor": "calendar",
"layout": {
"left": ["omarchy", "workspacesPro"],
"center": ["media", "calendar", "weatherFlyout", "update", "voxtype", "screenRecording", "idle"],
"right": ["tray", "systemStats", "notificationCenter", "microphone", "bluetoothPanel", "networkPanel", "audioPanel", "brightness", "powerProfile", "battery", "powerMenu"]
"center": ["media", "calendar", "weatherFlyout", "update", "voxtype", "screenRecording", "idle", "notifications"],
"right": ["tray", "systemStats", "microphone", "bluetoothPanel", "networkPanel", "audioPanel", "brightness", "powerProfile", "battery", "powerMenu"]
},
"modules": {
"calendar": {
+12 -13
View File
@@ -11,13 +11,13 @@ PopupWindow {
property int padding: 14
property int contentWidth: 280
property int contentHeight: 200
property bool dismissOnOutsideClick: true
property bool open: false
onOpenChanged: {
if (!bar) return
if (open) bar.requestPopout(owner || root)
else if (bar.activePopout === (owner || root)) bar.releasePopout(owner || root)
readonly property var coordinatorKey: owner || root
function closePopout() {
if (owner && "closePopout" in owner) owner.closePopout()
else root.open = false
}
default property alias contentItem: contentHolder.children
@@ -27,6 +27,12 @@ PopupWindow {
implicitWidth: contentWidth
implicitHeight: contentHeight
onOpenChanged: {
if (!bar) return
if (open) bar.requestPopout(coordinatorKey)
else if (bar.activePopout === coordinatorKey) bar.releasePopout(coordinatorKey)
}
anchor {
id: popupAnchor
window: anchorItem ? anchorItem.QsWindow.window : null
@@ -71,7 +77,7 @@ PopupWindow {
border.color: root.bar ? root.bar.foreground : "#cacccc"
border.width: 1
radius: 0
opacity: root.open ? 0.97 : 0
opacity: root.open ? 0.98 : 0
Behavior on opacity {
NumberAnimation { duration: 140; easing.type: Easing.OutCubic }
@@ -82,12 +88,5 @@ PopupWindow {
anchors.fill: parent
anchors.margins: root.padding
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
hoverEnabled: false
propagateComposedEvents: true
}
}
}
+14 -5
View File
@@ -1104,11 +1104,20 @@ ShellRoot {
active: slot.qmlCustom || slot.firstParty
source: slot.qmlCustom ? root.customModuleSource(slot.moduleName) : (slot.firstParty ? slot.firstPartySource : "")
anchors.fill: parent
onLoaded: {
if (item && "bar" in item) item.bar = root
if (item && "moduleName" in item) item.moduleName = slot.moduleName
if (item && "settings" in item) item.settings = root.moduleSettings(slot.moduleName)
}
onLoaded: slot.injectProps()
}
function injectProps() {
var target = qmlLoader.item
if (!target) return
if ("bar" in target) target.bar = root
if ("moduleName" in target) target.moduleName = moduleName
if ("settings" in target) target.settings = root.moduleSettings(moduleName)
}
Connections {
target: root
function onBarConfigSerialChanged() { slot.injectProps() }
}
Component {
+24 -9
View File
@@ -18,21 +18,35 @@ Item {
readonly property var source: Pipewire.defaultAudioSource
readonly property var nodes: Pipewire.nodes ? Pipewire.nodes.values : []
readonly property var audioSinks: {
readonly property var candidateSinks: {
var list = []
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i]
if (node && node.isSink && !node.isStream && node.audio) list.push(node)
if (node && node.isSink && !node.isStream) list.push(node)
}
return list
}
readonly property var candidateStreams: {
var list = []
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i]
if (node && node.isStream && !node.isSink) list.push(node)
}
return list
}
readonly property var audioSinks: {
var list = []
for (var i = 0; i < candidateSinks.length; i++)
if (candidateSinks[i].audio) list.push(candidateSinks[i])
return list
}
readonly property var audioStreams: {
var list = []
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i]
if (node && node.isStream && !node.isSink && node.audio) list.push(node)
}
for (var i = 0; i < candidateStreams.length; i++)
if (candidateStreams[i].audio) list.push(candidateStreams[i])
return list
}
@@ -65,8 +79,9 @@ Item {
implicitWidth: button.implicitWidth
implicitHeight: button.implicitHeight
PwObjectTracker { objects: root.audioSinks }
PwObjectTracker { objects: root.audioStreams }
PwObjectTracker { objects: root.candidateSinks }
PwObjectTracker { objects: root.candidateStreams }
PwObjectTracker { objects: root.sink ? [root.sink] : [] }
Common.WidgetButton {
id: button
@@ -224,7 +239,7 @@ Item {
node.properties ? node.properties["device.icon-name"] : "",
node.properties ? node.properties["device.product.name"] : ""
].join(" ")).toLowerCase()
if (blob.indexOf("headphone") !== -1 || blob.indexOf("headset") !== -1) return ""
if (blob.indexOf("headphone") !== -1 || blob.indexOf("headset") !== -1) return "󰋋"
if (blob.indexOf("bluetooth") !== -1) return "󰂯"
if (blob.indexOf("hdmi") !== -1 || blob.indexOf("display") !== -1) return "󰍹"
return "󰓃"
@@ -41,7 +41,7 @@ Item {
if (!adapter) return ""
if (!adapter.enabled) return "󰂲"
if (connectedDevices.length > 0) return "󰂱"
return ""
return "󰂯"
}
visible: adapter !== null
@@ -92,7 +92,7 @@ Item {
Item { width: parent.width - 200; height: 1 }
Common.PillButton {
iconText: root.adapter && root.adapter.enabled ? "" : ""
iconText: root.adapter && root.adapter.enabled ? "󰂯" : "󰂲"
text: root.adapter && root.adapter.enabled ? "On" : "Off"
foreground: root.bar.foreground
horizontalPadding: 8
@@ -102,7 +102,7 @@ Item {
}
Common.PillButton {
iconText: ""
iconText: "󰂳"
foreground: root.bar.foreground
horizontalPadding: 8
verticalPadding: 4
@@ -120,7 +120,7 @@ Item {
required property var modelData
width: parent.width
iconText: modelData && modelData.connected ? "󰂱" : ""
iconText: modelData && modelData.connected ? "󰂱" : "󰂯"
text: {
var label = modelData ? (modelData.deviceName || modelData.name || modelData.address || "Device") : ""
if (modelData && modelData.batteryAvailable) label += " " + Math.round(modelData.battery * 100) + "%"
+20 -2
View File
@@ -35,11 +35,29 @@ Item {
if (!readProc.running) readProc.running = true
}
property int pendingPercent: -1
function setBrightness(percent) {
var clamped = Math.max(1, Math.min(100, Math.round(percent)))
currentPercent = clamped
writeProc.command = ["bash", "-lc", "brightnessctl set " + clamped + "% >/dev/null"]
writeProc.running = true
pendingPercent = clamped
writeTimer.restart()
}
Timer {
id: writeTimer
interval: 60
repeat: false
onTriggered: {
if (writeProc.running) {
writeTimer.restart()
return
}
if (pendingPercent < 0) return
writeProc.command = ["bash", "-lc", "brightnessctl set " + pendingPercent + "% >/dev/null"]
pendingPercent = -1
writeProc.running = true
}
}
Component.onCompleted: refresh()
+3 -2
View File
@@ -68,6 +68,7 @@ Item {
id: popup
anchorItem: button
bar: root.bar
owner: root
open: root.popupOpen
contentWidth: 300
contentHeight: header.implicitHeight + grid.implicitHeight + 36
@@ -85,7 +86,7 @@ Item {
id: prevButton
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
iconText: ""
iconText: "󰅁"
foreground: root.bar.foreground
horizontalPadding: 8
verticalPadding: 4
@@ -105,7 +106,7 @@ Item {
id: nextButton
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
iconText: ""
iconText: "󰅂"
foreground: root.bar.foreground
horizontalPadding: 8
verticalPadding: 4
+6 -5
View File
@@ -28,7 +28,7 @@ Item {
}
readonly property bool hasMedia: activePlayer !== null && (activePlayer.trackTitle || activePlayer.trackArtist)
readonly property string playIcon: activePlayer && activePlayer.isPlaying ? "" : ""
readonly property string playIcon: activePlayer && activePlayer.isPlaying ? "󰏤" : "󰐊"
readonly property string title: activePlayer ? (activePlayer.trackTitle || "") : ""
readonly property string artist: activePlayer ? (activePlayer.trackArtist || "") : ""
@@ -118,6 +118,7 @@ Item {
id: popup
anchorItem: root
bar: root.bar
owner: root
open: root.popupOpen
contentWidth: 320
contentHeight: column.implicitHeight + 28
@@ -151,7 +152,7 @@ Item {
Text {
anchors.centerIn: parent
visible: !root.activePlayer || !root.activePlayer.trackArtUrl
text: ""
text: "󰝚"
color: root.bar.foreground
font.family: root.bar.fontFamily
font.pixelSize: 28
@@ -199,7 +200,7 @@ Item {
spacing: 6
Common.PillButton {
iconText: ""
iconText: "󰒮"
foreground: root.bar.foreground
horizontalPadding: 10
verticalPadding: 6
@@ -209,7 +210,7 @@ Item {
}
Common.PillButton {
iconText: root.activePlayer && root.activePlayer.isPlaying ? "" : ""
iconText: root.activePlayer && root.activePlayer.isPlaying ? "󰏤" : "󰐊"
foreground: root.bar.foreground
horizontalPadding: 14
verticalPadding: 6
@@ -220,7 +221,7 @@ Item {
}
Common.PillButton {
iconText: ""
iconText: "󰒭"
foreground: root.bar.foreground
horizontalPadding: 10
verticalPadding: 6
@@ -149,7 +149,7 @@ Item {
}
Common.PillButton {
iconText: ""
iconText: "󰑐"
foreground: root.bar.foreground
horizontalPadding: 8
verticalPadding: 4
@@ -205,7 +205,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰖩"
text: "Open Wi-Fi manager"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -20,7 +20,7 @@ Item {
readonly property string icon: {
if (dnd) return "󰂛"
if (count > 0) return "󱅫"
return ""
return "󰂚"
}
NotificationServer {
@@ -131,7 +131,7 @@ Item {
}
Common.PillButton {
iconText: ""
iconText: "󰎟"
foreground: root.bar.foreground
horizontalPadding: 8
verticalPadding: 4
@@ -196,7 +196,7 @@ Item {
Common.PillButton {
id: dismissBtn
iconText: ""
iconText: "󰅖"
foreground: root.bar.foreground
horizontalPadding: 4
verticalPadding: 0
+5 -5
View File
@@ -25,7 +25,7 @@ Item {
id: button
anchors.fill: parent
bar: root.bar
text: ""
text: "󰐥"
fontSize: 14
tooltipText: "Power menu"
onPressed: function() { root.popupOpen = !root.popupOpen }
@@ -54,7 +54,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰌾"
text: "Lock"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -74,7 +74,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰍃"
text: "Log out"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -84,7 +84,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰜉"
text: "Reboot"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -94,7 +94,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰐥"
text: "Shut down"
foreground: root.bar.urgent
horizontalPadding: 10
+55 -22
View File
@@ -119,30 +119,63 @@ Item {
}
}
implicitWidth: row.implicitWidth + 6
implicitHeight: bar ? bar.barSize : 26
readonly property bool vertical: bar ? bar.vertical : false
Row {
id: row
implicitWidth: vertical ? (bar ? bar.barSize : 28) : (statLayout.item ? statLayout.item.implicitWidth + 6 : 0)
implicitHeight: vertical ? (statLayout.item ? statLayout.item.implicitHeight + 6 : 0) : (bar ? bar.barSize : 26)
readonly property color statColor: bar ? bar.foreground : "#cacccc"
readonly property string statFont: bar ? bar.fontFamily : "JetBrainsMono Nerd Font"
Loader {
id: statLayout
anchors.centerIn: parent
spacing: 8
sourceComponent: root.vertical ? statColumn : statRow
}
StatPill {
glyph: "󰍛"
percent: root.cpuPercent
history: root.cpuHistory
vertical: root.bar.vertical
barFg: root.bar.foreground
fontFamily: root.bar.fontFamily
Component {
id: statRow
Row {
spacing: 8
StatPill {
glyph: "󰻠"
percent: root.cpuPercent
history: root.cpuHistory
vertical: false
barFg: root.statColor
fontFamily: root.statFont
}
StatPill {
glyph: "󰍛"
percent: root.memPercent
history: root.memHistory
vertical: false
barFg: root.statColor
fontFamily: root.statFont
}
}
}
StatPill {
glyph: ""
percent: root.memPercent
history: root.memHistory
vertical: root.bar.vertical
barFg: root.bar.foreground
fontFamily: root.bar.fontFamily
Component {
id: statColumn
Column {
spacing: 4
StatPill {
glyph: "󰻠"
percent: root.cpuPercent
history: root.cpuHistory
vertical: true
barFg: root.statColor
fontFamily: root.statFont
}
StatPill {
glyph: "󰍛"
percent: root.memPercent
history: root.memHistory
vertical: true
barFg: root.statColor
fontFamily: root.statFont
}
}
}
@@ -184,7 +217,7 @@ Item {
title: "CPU"
value: Math.round(root.cpuPercent) + "%"
history: root.cpuHistory
barFg: root.bar.foreground
barFg: root.statColor
fontFamily: root.bar.fontFamily
width: parent.width
}
@@ -193,7 +226,7 @@ Item {
title: "Memory"
value: Math.round(root.memPercent) + "%"
history: root.memHistory
barFg: root.bar.foreground
barFg: root.statColor
fontFamily: root.bar.fontFamily
width: parent.width
}
@@ -217,7 +250,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: "󰍛"
iconText: "󰆍"
text: "Open btop"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -120,7 +120,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰑐"
text: "Refresh"
foreground: root.bar.foreground
horizontalPadding: 10
@@ -130,7 +130,7 @@ Item {
Common.PillButton {
width: parent.width
iconText: ""
iconText: "󰏌"
text: "Open wttr.in"
foreground: root.bar.foreground
horizontalPadding: 10