Add network stats to SystemMonitor, fix ActiveWindow text display

SystemMonitor: add network up/down stats (also added setting to disable
it in BarTab)
ActiveWindow: add elide if not hovered
This commit is contained in:
Ly-sec 2025-08-31 09:22:33 +02:00
parent 724e55c37d
commit 2ebdc74f15
8 changed files with 135 additions and 10 deletions

View file

@ -24,6 +24,11 @@ fi
TEMP_SENSOR_PATH="" TEMP_SENSOR_PATH=""
TEMP_SENSOR_TYPE="" TEMP_SENSOR_TYPE=""
# Network speed monitoring variables
PREV_RX_BYTES=0
PREV_TX_BYTES=0
PREV_TIME=0
# --- Data Collection Functions --- # --- Data Collection Functions ---
# #
@ -194,6 +199,8 @@ get_cpu_temp() {
fi fi
} }
# --- Main Loop --- # --- Main Loop ---
# This loop runs indefinitely, gathering and printing stats. # This loop runs indefinitely, gathering and printing stats.
while true; do while true; do
@ -205,14 +212,58 @@ while true; do
disk_per=$(get_disk_usage) disk_per=$(get_disk_usage)
cpu_usage=$(get_cpu_usage) cpu_usage=$(get_cpu_usage)
cpu_temp=$(get_cpu_temp) cpu_temp=$(get_cpu_temp)
# Get network speeds
current_time=$(date +%s.%N)
total_rx=0
total_tx=0
# Read total bytes from /proc/net/dev for all interfaces
while IFS=: read -r interface stats; do
# Skip only loopback interface, allow other interfaces
if [[ "$interface" =~ ^lo[[:space:]]*$ ]]; then
continue
fi
# Extract rx and tx bytes (fields 1 and 9 in the stats part)
rx_bytes=$(echo "$stats" | awk '{print $1}')
tx_bytes=$(echo "$stats" | awk '{print $9}')
# Add to totals if they are valid numbers
if [[ "$rx_bytes" =~ ^[0-9]+$ ]] && [[ "$tx_bytes" =~ ^[0-9]+$ ]]; then
total_rx=$((total_rx + rx_bytes))
total_tx=$((total_tx + tx_bytes))
fi
done < <(tail -n +3 /proc/net/dev)
# Calculate speeds if we have previous data
rx_speed=0
tx_speed=0
if [[ "$PREV_TIME" != "0" ]]; then
time_diff=$(awk -v current="$current_time" -v prev="$PREV_TIME" 'BEGIN { printf "%.3f", current - prev }')
rx_diff=$((total_rx - PREV_RX_BYTES))
tx_diff=$((total_tx - PREV_TX_BYTES))
# Calculate speeds in bytes per second using awk
rx_speed=$(awk -v rx="$rx_diff" -v time="$time_diff" 'BEGIN { printf "%.0f", rx / time }')
tx_speed=$(awk -v tx="$tx_diff" -v time="$time_diff" 'BEGIN { printf "%.0f", tx / time }')
fi
# Update previous values for next iteration
PREV_RX_BYTES=$total_rx
PREV_TX_BYTES=$total_tx
PREV_TIME=$current_time
# Use printf to format the final JSON output string, adding the mem_mb key. # Use printf to format the final JSON output string, adding the mem_mb key.
printf '{"cpu": "%s", "cputemp": "%s", "memgb":"%s", "memper": "%s", "diskper": "%s"}\n' \ printf '{"cpu": "%s", "cputemp": "%s", "memgb":"%s", "memper": "%s", "diskper": "%s", "rx_speed": "%s", "tx_speed": "%s"}\n' \
"$cpu_usage" \ "$cpu_usage" \
"$cpu_temp" \ "$cpu_temp" \
"$mem_gb" \ "$mem_gb" \
"$mem_per" \ "$mem_per" \
"$disk_per" "$disk_per" \
"$rx_speed" \
"$tx_speed"
# Wait for the specified duration before the next update. # Wait for the specified duration before the next update.
sleep "$SLEEP_DURATION" sleep "$SLEEP_DURATION"

View file

@ -114,6 +114,7 @@ Singleton {
property string position: "top" // Possible values: "top", "bottom" property string position: "top" // Possible values: "top", "bottom"
property bool showActiveWindowIcon: true property bool showActiveWindowIcon: true
property bool alwaysShowBatteryPercentage: false property bool alwaysShowBatteryPercentage: false
property bool showNetworkStats: true
property real backgroundOpacity: 1.0 property real backgroundOpacity: 1.0
property string showWorkspaceLabel: "none" property string showWorkspaceLabel: "none"
property list<string> monitors: [] property list<string> monitors: []

View file

@ -141,10 +141,12 @@ NPanel {
Layout.fillWidth: true Layout.fillWidth: true
color: (modelData?.enabled color: (modelData?.enabled
?? true) ? (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) : Color.mOnSurfaceVariant ?? true) ? (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) : Color.mOnSurfaceVariant
text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ') : "..." text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ').replace(/\s+/g,
' ').trim() : "..."
font.pointSize: Style.fontSizeS * scaling font.pointSize: Style.fontSizeS * scaling
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap wrapMode: Text.NoWrap
elide: Text.ElideRight
} }
Image { Image {

View file

@ -86,18 +86,18 @@ Row {
NText { NText {
id: titleText id: titleText
// Fix collapsed width to 120px to avoid layout shifts with neighbors // Collapsed width when not hovered, expand on hover
// Expand up to 400px on hover width: mouseArea.containsMouse ? Math.min(fullTitleMetrics.contentWidth + (Style.marginS * scaling),
width: mouseArea.containsMouse ? Math.min(Math.max(minWidth * scaling, fullTitleMetrics.contentWidth), 400 * scaling) : (minWidth * scaling)
400 * scaling) : minWidth * scaling
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
text: getTitle() text: getTitle()
font.pointSize: Style.fontSizeS * scaling font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium font.weight: Style.fontWeightMedium
elide: Text.ElideRight elide: mouseArea.containsMouse ? Text.ElideNone : Text.ElideRight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
color: Color.mSecondary color: Color.mSecondary
clip: true
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {

View file

@ -97,6 +97,50 @@ Row {
color: Color.mPrimary color: Color.mPrimary
} }
} }
// Network Download Speed Component
Row {
id: networkDownloadLayout
spacing: Style.marginXS * scaling
visible: Settings.data.bar.showNetworkStats
NIcon {
text: "download"
anchors.verticalCenter: parent.verticalCenter
}
NText {
text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
font.family: Settings.data.ui.fontFixed
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
color: Color.mPrimary
}
}
// Network Upload Speed Component
Row {
id: networkUploadLayout
spacing: Style.marginXS * scaling
visible: Settings.data.bar.showNetworkStats
NIcon {
text: "upload"
anchors.verticalCenter: parent.verticalCenter
}
NText {
text: SystemStatService.formatSpeed(SystemStatService.txSpeed)
font.family: Settings.data.ui.fontFixed
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
color: Color.mPrimary
}
}
} }
} }
} }

View file

@ -309,7 +309,8 @@ NPanel {
return Color.mOnSurfaceVariant return Color.mOnSurfaceVariant
} }
opacity: Style.opacityHeavy opacity: Style.opacityHeavy
wrapMode: Text.WordWrap wrapMode: Text.NoWrap
elide: Text.ElideRight
} }
} }

View file

@ -88,6 +88,15 @@ ColumnLayout {
} }
} }
NToggle {
label: "Show Network Statistics"
description: "Display network upload and download speeds in the system monitor."
checked: Settings.data.bar.showNetworkStats
onToggled: checked => {
Settings.data.bar.showNetworkStats = checked
}
}
NComboBox { NComboBox {
label: "Show Workspaces Labels" label: "Show Workspaces Labels"
description: "Display the workspace name or index in the workspace indicator" description: "Display the workspace name or index in the workspace indicator"

View file

@ -14,6 +14,21 @@ Singleton {
property real memoryUsageGb: 0 property real memoryUsageGb: 0
property real memoryUsagePer: 0 property real memoryUsagePer: 0
property real diskUsage: 0 property real diskUsage: 0
property real rxSpeed: 0
property real txSpeed: 0
// Helper function to format network speeds
function formatSpeed(bytesPerSecond) {
if (bytesPerSecond < 1024) {
return bytesPerSecond.toFixed(0) + " B/s"
} else if (bytesPerSecond < 1024 * 1024) {
return (bytesPerSecond / 1024).toFixed(1) + " KB/s"
} else if (bytesPerSecond < 1024 * 1024 * 1024) {
return (bytesPerSecond / (1024 * 1024)).toFixed(1) + " MB/s"
} else {
return (bytesPerSecond / (1024 * 1024 * 1024)).toFixed(1) + " GB/s"
}
}
// Background process emitting one JSON line per sample // Background process emitting one JSON line per sample
Process { Process {
@ -29,6 +44,8 @@ Singleton {
root.memoryUsageGb = data.memgb root.memoryUsageGb = data.memgb
root.memoryUsagePer = data.memper root.memoryUsagePer = data.memper
root.diskUsage = data.diskper root.diskUsage = data.diskper
root.rxSpeed = parseFloat(data.rx_speed) || 0
root.txSpeed = parseFloat(data.tx_speed) || 0
} catch (e) { } catch (e) {
// ignore malformed lines // ignore malformed lines