fix(quickshell): prefer wired over wifi in network widget
Update PKGBUILD version / update-pkgver (push) Successful in 6s

When both a wired and a wifi connection are up, NetworkManager routes
over ethernet (lower metric) and nm-applet shows the wired icon. The
network indicator and popout checked wifi first, so an ethernet-connected
machine with wifi still associated wrongly showed the wifi glyph and
SSID. Check wiredDev first in the icon, tooltip, popout activeDev, and
compact connection text.
This commit is contained in:
2026-07-16 15:13:56 +02:00
parent 9ce20a096f
commit 30c9b55be4
3 changed files with 10 additions and 9 deletions
+1 -1
View File
@@ -78,7 +78,7 @@ quickshell is the **default bar and notification daemon**, spawned by niri as `q
- **Hover affordance:** clickable bar widgets dim to `opacity: 0.8` on hover (110ms `animDurationShort` fade) so they read as interactive. Deliberately **opacity, not color** — the icon color already encodes status (muted/off → `subtext0`, active → `accent`, battery critical → red), so a color-based hover would clobber the state signal. The Launcher is the exception: no status color, so it uses an `accent` hover instead. Applied per widget (no shared parent to hoist it to); `Workspaces`/`Tray` keep their own per-element hover, non-clickable `PrivacyIndicator`/`WindowTitle` get none.
- **Network indicator + VPN:** quickshell's Networking API exposes no VPN, so `NetworkService.qml` (singleton) holds the VPN connection list via nmcli — event-driven through a long-running `nmcli monitor` process (debounced refresh) plus a 60s fallback poll; shared by `NetworkIndicator` and `NetworkPopout`. The indicator shows connecting (cycling strength glyphs), an active VPN (MDI `wifi-strength-N-lock` variants; wired+VPN → `security-network`), and wired (`ethernet` glyph, beats wifi-off in priority so ethernet-only machines don't show a dead wifi icon).
- **Network indicator + VPN:** quickshell's Networking API exposes no VPN, so `NetworkService.qml` (singleton) holds the VPN connection list via nmcli — event-driven through a long-running `nmcli monitor` process (debounced refresh) plus a 60s fallback poll; shared by `NetworkIndicator` and `NetworkPopout`. The indicator shows connecting (cycling strength glyphs), an active VPN (MDI `wifi-strength-N-lock` variants; wired+VPN → `security-network`), and wired (`ethernet` glyph). **Wired wins over wifi** in both indicator and popout: when both a wired and a wifi connection are up, NM routes over ethernet (lower metric) and nm-applet shows the wired icon — so the widget checks `wiredDev` first (also beats wifi-off, so ethernet-only machines don't show a dead wifi icon).
- **Keyboard navigation:** an open popout grabs the keyboard, so it is fully operable without the mouse. Controls (`Toggle`, `ListRow`, `VolumeSlider`, `IconButton`) set `activeFocusOnTab` and show a focus ring; `PopoutPanel` focuses the first control on open and maps ↑/↓ onto Qt's native Tab chain (`nextItemInFocusChain` + an `activeFocusOnTab` filter). Keys: Tab/↑/↓ move focus, ←/→ nudge a slider ±5%, Space/Enter activate, Esc closes. Icon actions use the shared `IconButton` (destructive ones set `activeColor: Theme.red`); Rectangle-shaped buttons (clear-all, notification actions) are made focusable inline.
@@ -62,6 +62,9 @@ Item {
}
readonly property string icon: {
// Wired wins over wifi — when both are up NM routes over ethernet (lower metric), matching nm-applet.
if (root.wiredDev)
return String.fromCodePoint(NetworkService.vpnActive ? 0xf0484 : 0xf0200); // security-network / ethernet
if (root.connecting)
return String.fromCodePoint(root.strengthRamp[root.animStep]);
if (root.conn) {
@@ -70,8 +73,6 @@ Item {
const i = s >= 0.75 ? 3 : s >= 0.5 ? 2 : s >= 0.25 ? 1 : 0;
return String.fromCodePoint(ramp[i]);
}
if (root.wiredDev)
return String.fromCodePoint(NetworkService.vpnActive ? 0xf0484 : 0xf0200); // security-network / ethernet
if (!Networking.wifiEnabled)
return String.fromCodePoint(0xf05aa); // wifi-off
return String.fromCodePoint(0xf092d); // wifi-strength-off (no connection)
@@ -99,12 +100,12 @@ Item {
id: hover
}
readonly property string tooltipBase: {
if (root.wiredDev)
return qsTr("Wired");
if (root.connecting)
return qsTr("Connecting…");
if (root.conn)
return root.conn.name + " · " + Math.round(root.conn.signalStrength * 100) + "%";
if (root.wiredDev)
return qsTr("Wired");
return Networking.wifiEnabled ? qsTr("Not connected") : qsTr("Wi-Fi off");
}
Tooltip {
@@ -29,8 +29,8 @@ PopoutPanel {
const ds = Networking.devices ? Networking.devices.values : [];
return ds.find(d => d && d.type === DeviceType.Wired && d.connected) || null;
}
// The device that carries the active connection — wifi wins, else a connected wired device.
readonly property var activeDev: root.wifiConn ? root.wifiDev : root.wiredDev
// The device that carries the active connection — wired wins (lower route metric), else the wifi device.
readonly property var activeDev: root.wiredDev ? root.wiredDev : (root.wifiConn ? root.wifiDev : null)
readonly property var nets: {
if (!root.wifiDev || !root.wifiDev.networks)
return [];
@@ -130,10 +130,10 @@ PopoutPanel {
Text {
width: root.contentWidth
text: {
if (root.wifiConn)
return root.wifiConn.name + " · " + Math.round(root.wifiConn.signalStrength * 100) + "%";
if (root.wiredDev)
return qsTr("Wired");
if (root.wifiConn)
return root.wifiConn.name + " · " + Math.round(root.wifiConn.signalStrength * 100) + "%";
return Networking.wifiEnabled ? qsTr("Not connected") : qsTr("Wi-Fi off");
}
elide: Text.ElideRight