update bar

This commit is contained in:
Johannes Knopp
2026-04-08 02:21:01 +02:00
parent 586e4b6320
commit 63f99ff01a
6 changed files with 146 additions and 40 deletions

View File

@ -11,6 +11,10 @@ Item {
property string connType: "none" // "wifi", "ethernet", "none" property string connType: "none" // "wifi", "ethernet", "none"
property string connName: "" property string connName: ""
// accumulate results here, flush to displayed props on exit
property string _pendingType: "none"
property string _pendingName: ""
// \uf1eb = FA wifi, \uf0e8 = FA sitemap (wired proxy), \uf127 = FA chain-broken // \uf1eb = FA wifi, \uf0e8 = FA sitemap (wired proxy), \uf127 = FA chain-broken
readonly property string netIcon: readonly property string netIcon:
connType === "wifi" ? "\uf1eb" : connType === "wifi" ? "\uf1eb" :
@ -25,9 +29,9 @@ Item {
const state = line.substring(idx1 + 1, idx2) const state = line.substring(idx1 + 1, idx2)
const conn = line.substring(idx2 + 1).trim() const conn = line.substring(idx2 + 1).trim()
if (state === "connected" && (type === "wifi" || type === "ethernet")) { if (state === "connected" && (type === "wifi" || type === "ethernet")) {
if (root.connType === "none" || type === "wifi") { if (root._pendingType === "none" || type === "wifi") {
root.connType = type root._pendingType = type
root.connName = conn root._pendingName = conn
} }
} }
} }
@ -38,8 +42,8 @@ Item {
repeat: true repeat: true
triggeredOnStart: true triggeredOnStart: true
onTriggered: { onTriggered: {
root.connType = "none" root._pendingType = "none"
root.connName = "" root._pendingName = ""
netProc.running = true netProc.running = true
} }
} }
@ -51,7 +55,11 @@ Item {
splitMarker: "\n" splitMarker: "\n"
onRead: data => root.parseLine(data) onRead: data => root.parseLine(data)
} }
onExited: running = false onExited: {
root.connType = root._pendingType
root.connName = root._pendingName
running = false
}
} }
Row { Row {

View File

@ -33,30 +33,10 @@ Item {
Behavior on color { ColorAnimation { duration: 80 } } Behavior on color { ColorAnimation { duration: 80 } }
} }
IconImage { TrayIcon {
id: iconImg
anchors.centerIn: parent anchors.centerIn: parent
implicitSize: 16 icon: trayDelegate.modelData.icon
visible: status === Image.Ready size: 16
source: {
const icon = trayDelegate.modelData.icon
if (!icon || icon === "") return ""
if (icon.startsWith("/") || icon.startsWith("file://") || icon.startsWith("image://")) return icon
const path = Quickshell.iconPath(icon, "")
if (path !== "") return "file://" + path
return "image://icon/" + icon
}
mipmap: true
}
// Letter fallback when icon fails to load
Text {
anchors.centerIn: parent
visible: iconImg.status !== Image.Ready
text: (trayDelegate.modelData.title ?? trayDelegate.modelData.id ?? "?").charAt(0).toUpperCase()
color: Theme.textDim
font.pixelSize: 11
font.bold: true
} }
MouseArea { MouseArea {

View File

@ -1,6 +1,6 @@
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Widgets // import Quickshell.Widgets
import QtQuick import QtQuick
import "../components" import "../components"
@ -27,17 +27,29 @@ Rectangle {
delegate: Item { delegate: Item {
id: iconItem id: iconItem
required property var modelData required property var modelData
property string appClass: modelData.lastIpcObject["class"] ?? ""
property var entry: appClass !== "" ? DesktopEntries.heuristicLookup(appClass) : null
width: 16 implicitWidth: 16
height: 16 implicitHeight: 16
IconImage { property string appClass: ""
Component.onCompleted: {
var cls = modelData?.lastIpcObject?.["class"] ?? ""
if (cls !== "") {
appClass = cls
} else if (modelData) {
modelData.lastIpcObjectChanged.connect(function() {
var c = iconItem.modelData?.lastIpcObject?.["class"] ?? ""
if (c !== "") iconItem.appClass = c
})
Qt.callLater(Hyprland.refreshToplevels)
}
}
TrayIcon {
anchors.fill: parent anchors.fill: parent
source: iconItem.entry && iconItem.entry.icon !== "" icon: iconItem.appClass
? "image://icon/" + iconItem.entry.icon size: 16
: ""
} }
} }
} }

View File

@ -1,3 +1,5 @@
pragma ComponentBehavior: Bound
import Quickshell.Hyprland import Quickshell.Hyprland
import QtQuick import QtQuick

View File

@ -0,0 +1,103 @@
// import QtQuick
// import Quickshell.Widgets
//
// Item {
// id: root
//
// property string icon: ""
// property int size: 16
//
// implicitWidth: size
// implicitHeight: size
//
// readonly property url resolvedSource: {
// if (!icon) return ""
// if (icon.startsWith("/") || icon.startsWith("file://") || icon.startsWith("image://"))
// return icon
// if (icon.includes("?path=")) {
// const [name, path] = icon.split("?path=")
// const baseName = name.slice(name.lastIndexOf("/") + 1)
// return `file://${path}/${baseName}`
// }
// return `image://icon/${icon}`
// }
//
// readonly property bool isIconTheme: resolvedSource.toString().startsWith("image://icon/")
// readonly property bool hasSource: resolvedSource.toString() !== ""
//
// IconImage {
// anchors.fill: parent
// source: root.resolvedSource
// visible: root.hasSource && root.isIconTheme
// asynchronous: true
// }
//
// Image {
// anchors.fill: parent
// source: root.hasSource && !root.isIconTheme ? root.resolvedSource : ""
// visible: root.hasSource && !root.isIconTheme
// asynchronous: true
// fillMode: Image.PreserveAspectFit
// }
// }
// pragma ComponentBehavior: Bound
import QtQuick
// import Quickshell
import Quickshell.Widgets
Item {
id: root
property string icon: ""
property int size: 16
implicitWidth: size
implicitHeight: size
readonly property url resolvedSource: {
if (!icon) return ""
if (icon.startsWith("/") || icon.startsWith("file://") || icon.startsWith("image://"))
return icon
if (icon.includes("?path=")) {
const [name, path] = icon.split("?path=")
const baseName = name.slice(name.lastIndexOf("/") + 1)
return `file://${path}/${baseName}`
}
// Use Quickshell's icon image provider instead of iconPath()
return `image://icon/${icon}`
}
Loader {
anchors.fill: parent
// asynchronous: true
sourceComponent: root.resolvedSource && root.resolvedSource.toString() !== ""
? root.resolvedSource.toString().startsWith("image://icon/")
? iconComponent
: imageComponent
: null
}
Component {
id: iconComponent
IconImage {
source: root.resolvedSource
asynchronous: true
// mipmap: true
}
}
Component {
id: imageComponent
Image {
source: root.resolvedSource
asynchronous: true
// mipmap: true
fillMode: Image.PreserveAspectFit
}
}
}

View File

@ -1,2 +1,3 @@
singleton Theme 1.0 Theme.qml singleton Theme 1.0 Theme.qml
Enclosure 1.0 Enclosure.qml Enclosure 1.0 Enclosure.qml
TrayIcon 1.0 TrayIcon.qml