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:
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) + "%"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user