From 1100bd460b457b12a4ffa1a5aa8c780c6a1a418f Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 8 Sep 2026 20:00:24 +0100 Subject: [PATCH] quickshell: detect NetworkManager down, add restart button Co-Authored-By: Claude Opus 5 --- settings/quickshell.nix | 47 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/settings/quickshell.nix b/settings/quickshell.nix index 3474484..61e3214 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -4056,11 +4056,21 @@ in property string netConn: "" property string netType: "" property int netStrength: 0 + // nmcli exits non-zero when NetworkManager itself + // isn't running ("Error: NetworkManager is not + // running.", exit 8). The kernel keeps the link's + // address and routes when the daemon dies, so the + // machine is still online while nmcli reports nothing + // — without this the widget claimed "Not connected" + // over a working ethernet link. + property bool nmDown: false + // Signal strength picks the arc glyph. Lucide draws four // wifi levels where Material Symbols drew five, so the // bottom two of caelestia's buckets collapse into one. readonly property string netIcon: - netState !== "connected" + nmDown ? "triangle-alert" + : netState !== "connected" ? (netType === "ethernet" ? "unplug" : "wifi-off") : netType === "ethernet" ? "cable" : netStrength >= 80 ? "wifi" @@ -4119,6 +4129,7 @@ in Process { id: netProc command: [Commands.nmcli, "-t", "-f", "DEVICE,TYPE,STATE,CONNECTION", "device"] + onExited: exitCode => netWidget.nmDown = exitCode !== 0 stdout: SplitParser { onRead: data => { let fields = data.split(":"); @@ -4215,6 +4226,17 @@ in command: [Commands.nmcli, "device", "disconnect", targetDevice] } + Process { + id: nmRestartProc + command: [Commands.systemctl, "restart", "NetworkManager.service"] + } + + Timer { + id: netRestartDelay + interval: 5000 + onTriggered: netWidget.refreshNet() + } + function openNetDropdown() { bar.toggleDropdown(netDropdown, function() { wifiScanProc.running = true; @@ -5350,7 +5372,8 @@ in SText { anchors.verticalCenter: parent.verticalCenter width: parent.width - 22 - text: netWidget.netState === "connected" + text: netWidget.nmDown ? "NetworkManager down" + : netWidget.netState === "connected" ? netWidget.netConn : "Not connected" color: Theme.base05 font.pixelSize: 13 @@ -5360,7 +5383,25 @@ in } HoverRow { - visible: netWidget.netState === "connected" + visible: netWidget.nmDown + width: parent.width + height: 28 + onClicked: { + nmRestartProc.running = true; + bar.closeAllDropdowns(); + netRestartDelay.start(); + } + + SText { + anchors.centerIn: parent + text: "Restart NetworkManager" + color: Theme.accent + font.pixelSize: 12 + } + } + + HoverRow { + visible: netWidget.netState === "connected" && !netWidget.nmDown width: parent.width height: 28 onClicked: {