From e7c30fd39d283f688a8c4708730c01f21a10f25b Mon Sep 17 00:00:00 2001 From: Erik Simon Date: Sat, 29 Aug 2026 03:30:35 +0200 Subject: [PATCH] feat(quickshell): show local and tailnet address in HostPanel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A third line under user // timezone, muted so the identity block stays a descending three tiers. Unlike the name, user and zone — none of which can change under a running shell — addresses can, so this polls on a 30s timer instead of joining the startup one-shot. The local one is read off the interface holding the default route with tailscale0 excluded: as an exit node tailscale0 holds that route itself, and the panel would show the tailnet address on both sides. Drops the expanded body's `height: 48`. A third line has to grow the panel, and BarPanel measures the body to decide how tall it is, so a fixed height would have clipped the new row instead. The bar follows through targetHeight. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01HEtXvseVb5gwAtKNhFx2PU --- .../hyprchrome/widgets/host/HostPanel.qml | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/dotfiles/quickshell/hyprchrome/widgets/host/HostPanel.qml b/dotfiles/quickshell/hyprchrome/widgets/host/HostPanel.qml index 7cdd2ce..ec2ad7a 100644 --- a/dotfiles/quickshell/hyprchrome/widgets/host/HostPanel.qml +++ b/dotfiles/quickshell/hyprchrome/widgets/host/HostPanel.qml @@ -27,6 +27,8 @@ BarPanel { property string hostName: "LOCAL" property string zoneName: "" // IANA, e.g. EUROPE/BERLIN property string userName: "" // whoever is logged in, e.g. DARMAN + property string localIp: "" // interface holding the default route + property string tailnetIp: "" // tailscale0, when the tailnet is up property date now: new Date() // Qt resolves the abbreviation ("CEST") against the same zone the offset @@ -82,6 +84,40 @@ BarPanel { } } + // Addresses, unlike the name and the zone, can change under a running + // shell — a lease renewal, `tailscale up`/`down` — so this one polls. + // + // The local address is taken from the interface carrying the default + // route, with tailscale0 excluded: as an exit node it holds the default + // route itself, and the panel would then show the tailnet address twice. + Process { + id: addresses + + command: ["sh", "-c", + "dev=$(ip -4 route show default | grep -v tailscale0 | awk '{print $5; exit}');" + + " ip -4 -o addr show dev \"$dev\" scope global 2>/dev/null | awk '{split($4,a,\"/\"); print a[1]; exit}';" + + " ip -4 -o addr show dev tailscale0 scope global 2>/dev/null | awk '{split($4,a,\"/\"); print a[1]; exit}'"] + + stdout: StdioCollector { + onStreamFinished: { + const lines = this.text.trim().split("\n"); + panel.localIp = lines.length > 0 ? lines[0].trim() : ""; + panel.tailnetIp = lines.length > 1 ? lines[1].trim() : ""; + } + } + } + + Timer { + interval: 30000 + running: true + repeat: true + triggeredOnStart: true + onTriggered: { + if (!addresses.running) + addresses.running = true; + } + } + // Collapsed: who and when, nothing else. summary: Row { spacing: 10 @@ -133,7 +169,8 @@ BarPanel { // Expanded: name left, clock stack right. RowLayout { width: parent.width - height: 48 + // No explicit height: a third line in the identity column has to grow + // the panel, and BarPanel measures the body to decide how tall it is. spacing: 16 Column { @@ -160,6 +197,15 @@ BarPanel { font.letterSpacing: 1.4 elide: Text.ElideRight } + + Text { + text: (panel.localIp || "--") + " // " + (panel.tailnetIp || "NO TAILNET") + color: Theme.muted + font.family: Theme.microFont + font.pixelSize: 9 + font.letterSpacing: 1.4 + elide: Text.ElideRight + } } // Rule between identity and clock, the same hairline the dense bar