mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 05:55:37 -05:00
anotehr qmlfmt round and extra GPU data
This commit is contained in:
@@ -17,6 +17,7 @@ Singleton {
|
|||||||
property string profileLastPath: ""
|
property string profileLastPath: ""
|
||||||
property bool doNotDisturb: false
|
property bool doNotDisturb: false
|
||||||
property var pinnedApps: []
|
property var pinnedApps: []
|
||||||
|
property int selectedGpuIndex: 0
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
loadSettings()
|
loadSettings()
|
||||||
@@ -37,6 +38,7 @@ Singleton {
|
|||||||
profileLastPath = settings.profileLastPath !== undefined ? settings.profileLastPath : ""
|
profileLastPath = settings.profileLastPath !== undefined ? settings.profileLastPath : ""
|
||||||
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false
|
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false
|
||||||
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : []
|
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : []
|
||||||
|
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
||||||
@@ -50,7 +52,8 @@ Singleton {
|
|||||||
"wallpaperLastPath": wallpaperLastPath,
|
"wallpaperLastPath": wallpaperLastPath,
|
||||||
"profileLastPath": profileLastPath,
|
"profileLastPath": profileLastPath,
|
||||||
"doNotDisturb": doNotDisturb,
|
"doNotDisturb": doNotDisturb,
|
||||||
"pinnedApps": pinnedApps
|
"pinnedApps": pinnedApps,
|
||||||
|
"selectedGpuIndex": selectedGpuIndex
|
||||||
}, null, 2))
|
}, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +118,11 @@ Singleton {
|
|||||||
return appId && pinnedApps.indexOf(appId) !== -1
|
return appId && pinnedApps.indexOf(appId) !== -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setSelectedGpuIndex(index) {
|
||||||
|
selectedGpuIndex = index
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: settingsFile
|
id: settingsFile
|
||||||
|
|
||||||
|
|||||||
@@ -237,12 +237,34 @@ Row {
|
|||||||
width: (parent.width - Theme.spacingM * 2) / 3
|
width: (parent.width - Theme.spacingM * 2) / 3
|
||||||
height: 80
|
height: 80
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
color: {
|
||||||
|
if (gpuCardMouseArea.containsMouse
|
||||||
|
&& SysMonitorService.availableGpus.length > 1)
|
||||||
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||||
|
Theme.surfaceVariant.b, 0.16)
|
||||||
|
else
|
||||||
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||||
Theme.surfaceVariant.b, 0.08)
|
Theme.surfaceVariant.b, 0.08)
|
||||||
|
}
|
||||||
border.color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
border.color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
|
||||||
Theme.surfaceVariant.b, 0.2)
|
Theme.surfaceVariant.b, 0.2)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: gpuCardMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: SysMonitorService.availableGpus.length
|
||||||
|
> 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
onClicked: {
|
||||||
|
if (SysMonitorService.availableGpus.length > 1) {
|
||||||
|
var nextIndex = (SessionData.selectedGpuIndex + 1)
|
||||||
|
% SysMonitorService.availableGpus.length
|
||||||
|
SessionData.setSelectedGpuIndex(nextIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.leftMargin: Theme.spacingM
|
||||||
@@ -250,7 +272,7 @@ Row {
|
|||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Graphics"
|
text: "GPU"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.secondary
|
color: Theme.secondary
|
||||||
@@ -261,30 +283,16 @@ Row {
|
|||||||
text: {
|
text: {
|
||||||
if (!SysMonitorService.availableGpus
|
if (!SysMonitorService.availableGpus
|
||||||
|| SysMonitorService.availableGpus.length === 0) {
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
return "None"
|
|
||||||
}
|
|
||||||
if (SysMonitorService.availableGpus.length === 1) {
|
|
||||||
var gpu = SysMonitorService.availableGpus[0]
|
|
||||||
var temp = gpu.temperature
|
|
||||||
var tempText = (temp === undefined || temp === null
|
|
||||||
|| temp === 0) ? "--°" : Math.round(temp) + "°"
|
|
||||||
return tempText
|
|
||||||
}
|
|
||||||
// Multiple GPUs - show average temp
|
|
||||||
var totalTemp = 0
|
|
||||||
var validTemps = 0
|
|
||||||
for (var i = 0; i < SysMonitorService.availableGpus.length; i++) {
|
|
||||||
var temp = SysMonitorService.availableGpus[i].temperature
|
|
||||||
if (temp !== undefined && temp !== null && temp > 0) {
|
|
||||||
totalTemp += temp
|
|
||||||
validTemps++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (validTemps > 0) {
|
|
||||||
return Math.round(totalTemp / validTemps) + "°"
|
|
||||||
}
|
|
||||||
return "--°"
|
return "--°"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length - 1)]
|
||||||
|
var temp = gpu.temperature
|
||||||
|
return (temp === undefined || temp === null
|
||||||
|
|| temp === 0) ? "--°" : Math.round(temp) + "°"
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
@@ -293,25 +301,15 @@ Row {
|
|||||||
|| SysMonitorService.availableGpus.length === 0) {
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
return Theme.surfaceText
|
return Theme.surfaceText
|
||||||
}
|
}
|
||||||
if (SysMonitorService.availableGpus.length === 1) {
|
|
||||||
var temp = SysMonitorService.availableGpus[0].temperature || 0
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length - 1)]
|
||||||
|
var temp = gpu.temperature || 0
|
||||||
if (temp > 80)
|
if (temp > 80)
|
||||||
return Theme.tempDanger
|
return Theme.error
|
||||||
if (temp > 60)
|
if (temp > 60)
|
||||||
return Theme.tempWarning
|
return Theme.warning
|
||||||
return Theme.surfaceText
|
|
||||||
}
|
|
||||||
// Multiple GPUs - get max temp for coloring
|
|
||||||
var maxTemp = 0
|
|
||||||
for (var i = 0; i < SysMonitorService.availableGpus.length; i++) {
|
|
||||||
var temp = SysMonitorService.availableGpus[i].temperature || 0
|
|
||||||
if (temp > maxTemp)
|
|
||||||
maxTemp = temp
|
|
||||||
}
|
|
||||||
if (maxTemp > 80)
|
|
||||||
return Theme.tempDanger
|
|
||||||
if (maxTemp > 60)
|
|
||||||
return Theme.tempWarning
|
|
||||||
return Theme.surfaceText
|
return Theme.surfaceText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,15 +320,25 @@ Row {
|
|||||||
|| SysMonitorService.availableGpus.length === 0) {
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
return "No GPUs detected"
|
return "No GPUs detected"
|
||||||
}
|
}
|
||||||
if (SysMonitorService.availableGpus.length === 1) {
|
|
||||||
return SysMonitorService.availableGpus[0].driver.toUpperCase()
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
}
|
SessionData.selectedGpuIndex,
|
||||||
return SysMonitorService.availableGpus.length + " GPUs detected"
|
SysMonitorService.availableGpus.length - 1)]
|
||||||
|
return gpu.vendor + " " + gpu.displayName
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
width: parent.parent.width - Theme.spacingM * 2
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,8 +104,7 @@ ScrollView {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: (parent.width - Theme.spacingXL) / 2
|
width: (parent.width - Theme.spacingXL) / 2
|
||||||
height: Math.max(hardwareColumn.implicitHeight,
|
height: hardwareColumn.implicitHeight + Theme.spacingL
|
||||||
memoryColumn.implicitHeight) + Theme.spacingM
|
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Qt.rgba(Theme.surfaceContainerHigh.r,
|
color: Qt.rgba(Theme.surfaceContainerHigh.r,
|
||||||
Theme.surfaceContainerHigh.g,
|
Theme.surfaceContainerHigh.g,
|
||||||
@@ -135,7 +134,7 @@ ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Hardware"
|
text: "System"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
@@ -180,23 +179,57 @@ ScrollView {
|
|||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: SysMonitorService.formatSystemMemory(
|
||||||
|
SysMonitorService.totalMemoryKB) + " RAM"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.family: SettingsData.monoFontFamily
|
||||||
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b, 0.8)
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: (parent.width - Theme.spacingXL) / 2
|
width: (parent.width - Theme.spacingXL) / 2
|
||||||
height: Math.max(hardwareColumn.implicitHeight,
|
height: gpuColumn.implicitHeight + Theme.spacingL
|
||||||
memoryColumn.implicitHeight) + Theme.spacingM
|
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Qt.rgba(Theme.surfaceContainerHigh.r,
|
color: {
|
||||||
|
if (gpuCardMouseArea.containsMouse
|
||||||
|
&& SysMonitorService.availableGpus.length > 1)
|
||||||
|
return Qt.rgba(Theme.surfaceContainerHigh.r,
|
||||||
|
Theme.surfaceContainerHigh.g,
|
||||||
|
Theme.surfaceContainerHigh.b, 0.6)
|
||||||
|
else
|
||||||
|
return Qt.rgba(Theme.surfaceContainerHigh.r,
|
||||||
Theme.surfaceContainerHigh.g,
|
Theme.surfaceContainerHigh.g,
|
||||||
Theme.surfaceContainerHigh.b, 0.4)
|
Theme.surfaceContainerHigh.b, 0.4)
|
||||||
|
}
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||||
Theme.outline.b, 0.1)
|
Theme.outline.b, 0.1)
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: gpuCardMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: SysMonitorService.availableGpus.length
|
||||||
|
> 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
onClicked: {
|
||||||
|
if (SysMonitorService.availableGpus.length > 1) {
|
||||||
|
var nextIndex = (SessionData.selectedGpuIndex + 1)
|
||||||
|
% SysMonitorService.availableGpus.length
|
||||||
|
SessionData.setSelectedGpuIndex(nextIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: memoryColumn
|
id: gpuColumn
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -209,14 +242,14 @@ ScrollView {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: "developer_board"
|
name: "auto_awesome_mosaic"
|
||||||
size: Theme.iconSizeSmall
|
size: Theme.iconSizeSmall
|
||||||
color: Theme.secondary
|
color: Theme.secondary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Memory"
|
text: "GPU"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
@@ -226,35 +259,113 @@ ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: SysMonitorService.formatSystemMemory(
|
text: {
|
||||||
SysMonitorService.totalMemoryKB) + " Total"
|
if (!SysMonitorService.availableGpus
|
||||||
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
|
return "No GPUs detected"
|
||||||
|
}
|
||||||
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length
|
||||||
|
- 1)]
|
||||||
|
return gpu.fullName
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: SysMonitorService.formatSystemMemory(
|
text: {
|
||||||
SysMonitorService.usedMemoryKB) + " Used • "
|
if (!SysMonitorService.availableGpus
|
||||||
+ SysMonitorService.formatSystemMemory(
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
SysMonitorService.totalMemoryKB
|
return "Vendor: N/A"
|
||||||
- SysMonitorService.usedMemoryKB) + " Available"
|
}
|
||||||
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length
|
||||||
|
- 1)]
|
||||||
|
return "Vendor: " + gpu.vendor
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||||
Theme.surfaceText.b, 0.7)
|
Theme.surfaceText.b, 0.8)
|
||||||
width: parent.width
|
width: parent.width
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
StyledText {
|
||||||
|
text: {
|
||||||
|
if (!SysMonitorService.availableGpus
|
||||||
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
|
return "Driver: N/A"
|
||||||
|
}
|
||||||
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length
|
||||||
|
- 1)]
|
||||||
|
return "Driver: " + gpu.driver
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.family: SettingsData.monoFontFamily
|
||||||
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b, 0.8)
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: Theme.fontSizeSmall + Theme.spacingXS
|
elide: Text.ElideRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: {
|
||||||
|
if (!SysMonitorService.availableGpus
|
||||||
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
|
return "Temp: --°"
|
||||||
|
}
|
||||||
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length
|
||||||
|
- 1)]
|
||||||
|
var temp = gpu.temperature
|
||||||
|
return "Temp: " + ((temp === undefined || temp === null
|
||||||
|
|| temp === 0) ? "--°" : Math.round(
|
||||||
|
temp) + "°C")
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.family: SettingsData.monoFontFamily
|
||||||
|
color: {
|
||||||
|
if (!SysMonitorService.availableGpus
|
||||||
|
|| SysMonitorService.availableGpus.length === 0) {
|
||||||
|
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b, 0.7)
|
||||||
|
}
|
||||||
|
var gpu = SysMonitorService.availableGpus[Math.min(
|
||||||
|
SessionData.selectedGpuIndex,
|
||||||
|
SysMonitorService.availableGpus.length
|
||||||
|
- 1)]
|
||||||
|
var temp = gpu.temperature || 0
|
||||||
|
if (temp > 80)
|
||||||
|
return Theme.error
|
||||||
|
if (temp > 60)
|
||||||
|
return Theme.warning
|
||||||
|
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b, 0.7)
|
||||||
|
}
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ Rectangle {
|
|||||||
|
|
||||||
SequentialAnimation on opacity {
|
SequentialAnimation on opacity {
|
||||||
id: pulseAnimation
|
id: pulseAnimation
|
||||||
running: parent.visible && hasActivePrivacy && PrivacyService.cameraActive
|
running: parent.visible && hasActivePrivacy
|
||||||
|
&& PrivacyService.cameraActive
|
||||||
loops: Animation.Infinite
|
loops: Animation.Infinite
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
pragma ComponentBehavior
|
pragma ComponentBehavior
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -75,324 +76,335 @@ Singleton {
|
|||||||
property var availableGpus: []
|
property var availableGpus: []
|
||||||
|
|
||||||
function addRef() {
|
function addRef() {
|
||||||
refCount++;
|
refCount++
|
||||||
if (refCount === 1) {
|
if (refCount === 1) {
|
||||||
updateAllStats();
|
updateAllStats()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeRef() {
|
function removeRef() {
|
||||||
refCount = Math.max(0, refCount - 1);
|
refCount = Math.max(0, refCount - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAllStats() {
|
function updateAllStats() {
|
||||||
if (refCount > 0) {
|
if (refCount > 0) {
|
||||||
isUpdating = true;
|
isUpdating = true
|
||||||
unifiedStatsProcess.running = true;
|
unifiedStatsProcess.running = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSortBy(newSortBy) {
|
function setSortBy(newSortBy) {
|
||||||
if (newSortBy !== sortBy) {
|
if (newSortBy !== sortBy) {
|
||||||
sortBy = newSortBy;
|
sortBy = newSortBy
|
||||||
sortProcessesInPlace();
|
sortProcessesInPlace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSortOrder() {
|
function toggleSortOrder() {
|
||||||
sortDescending = !sortDescending;
|
sortDescending = !sortDescending
|
||||||
sortProcessesInPlace();
|
sortProcessesInPlace()
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortProcessesInPlace() {
|
function sortProcessesInPlace() {
|
||||||
if (processes.length === 0)
|
if (processes.length === 0)
|
||||||
return;
|
return
|
||||||
const sortedProcesses = [...processes];
|
const sortedProcesses = [...processes]
|
||||||
|
|
||||||
sortedProcesses.sort((a, b) => {
|
sortedProcesses.sort((a, b) => {
|
||||||
let aVal, bVal;
|
let aVal, bVal
|
||||||
|
|
||||||
switch (sortBy) {
|
switch (sortBy) {
|
||||||
case "cpu":
|
case "cpu":
|
||||||
aVal = parseFloat(a.cpu) || 0;
|
aVal = parseFloat(a.cpu) || 0
|
||||||
bVal = parseFloat(b.cpu) || 0;
|
bVal = parseFloat(b.cpu) || 0
|
||||||
break;
|
break
|
||||||
case "memory":
|
case "memory":
|
||||||
aVal = parseFloat(a.memoryPercent) || 0;
|
aVal = parseFloat(a.memoryPercent) || 0
|
||||||
bVal = parseFloat(b.memoryPercent) || 0;
|
bVal = parseFloat(b.memoryPercent) || 0
|
||||||
break;
|
break
|
||||||
case "name":
|
case "name":
|
||||||
aVal = a.command || "";
|
aVal = a.command || ""
|
||||||
bVal = b.command || "";
|
bVal = b.command || ""
|
||||||
break;
|
break
|
||||||
case "pid":
|
case "pid":
|
||||||
aVal = parseInt(a.pid) || 0;
|
aVal = parseInt(a.pid) || 0
|
||||||
bVal = parseInt(b.pid) || 0;
|
bVal = parseInt(b.pid) || 0
|
||||||
break;
|
break
|
||||||
default:
|
default:
|
||||||
aVal = parseFloat(a.cpu) || 0;
|
aVal = parseFloat(a.cpu) || 0
|
||||||
bVal = parseFloat(b.cpu) || 0;
|
bVal = parseFloat(b.cpu) || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof aVal === "string") {
|
if (typeof aVal === "string") {
|
||||||
return sortDescending ? bVal.localeCompare(aVal) : aVal.localeCompare(bVal);
|
return sortDescending ? bVal.localeCompare(
|
||||||
|
aVal) : aVal.localeCompare(
|
||||||
|
bVal)
|
||||||
} else {
|
} else {
|
||||||
return sortDescending ? bVal - aVal : aVal - bVal;
|
return sortDescending ? bVal - aVal : aVal - bVal
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
processes = sortedProcesses;
|
processes = sortedProcesses
|
||||||
}
|
}
|
||||||
|
|
||||||
function killProcess(pid) {
|
function killProcess(pid) {
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
Quickshell.execDetached("kill", [pid.toString()]);
|
Quickshell.execDetached("kill", [pid.toString()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToHistory(array, value) {
|
function addToHistory(array, value) {
|
||||||
array.push(value);
|
array.push(value)
|
||||||
if (array.length > historySize)
|
if (array.length > historySize)
|
||||||
array.shift();
|
array.shift()
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateCpuUsage(currentStats, lastStats) {
|
function calculateCpuUsage(currentStats, lastStats) {
|
||||||
if (!lastStats || !currentStats || currentStats.length < 4) {
|
if (!lastStats || !currentStats || currentStats.length < 4) {
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentTotal = currentStats.reduce((sum, val) => sum + val, 0);
|
const currentTotal = currentStats.reduce((sum, val) => sum + val, 0)
|
||||||
const lastTotal = lastStats.reduce((sum, val) => sum + val, 0);
|
const lastTotal = lastStats.reduce((sum, val) => sum + val, 0)
|
||||||
|
|
||||||
const totalDiff = currentTotal - lastTotal;
|
const totalDiff = currentTotal - lastTotal
|
||||||
if (totalDiff <= 0)
|
if (totalDiff <= 0)
|
||||||
return 0;
|
return 0
|
||||||
|
|
||||||
const currentIdle = currentStats[3];
|
const currentIdle = currentStats[3]
|
||||||
const lastIdle = lastStats[3];
|
const lastIdle = lastStats[3]
|
||||||
const idleDiff = currentIdle - lastIdle;
|
const idleDiff = currentIdle - lastIdle
|
||||||
|
|
||||||
const usedDiff = totalDiff - idleDiff;
|
const usedDiff = totalDiff - idleDiff
|
||||||
return Math.max(0, Math.min(100, (usedDiff / totalDiff) * 100));
|
return Math.max(0, Math.min(100, (usedDiff / totalDiff) * 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseUnifiedStats(text) {
|
function parseUnifiedStats(text) {
|
||||||
function num(x) {
|
function num(x) {
|
||||||
return (typeof x === "number" && !isNaN(x)) ? x : 0;
|
return (typeof x === "number" && !isNaN(x)) ? x : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
let data;
|
let data
|
||||||
try {
|
try {
|
||||||
data = JSON.parse(text);
|
data = JSON.parse(text)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
isUpdating = false;
|
isUpdating = false
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.memory) {
|
if (data.memory) {
|
||||||
const m = data.memory;
|
const m = data.memory
|
||||||
totalMemoryKB = num(m.total);
|
totalMemoryKB = num(m.total)
|
||||||
const free = num(m.free);
|
const free = num(m.free)
|
||||||
const buf = num(m.buffers);
|
const buf = num(m.buffers)
|
||||||
const cached = num(m.cached);
|
const cached = num(m.cached)
|
||||||
const shared = num(m.shared);
|
const shared = num(m.shared)
|
||||||
usedMemoryKB = totalMemoryKB - free - buf - cached;
|
usedMemoryKB = totalMemoryKB - free - buf - cached
|
||||||
totalSwapKB = num(m.swaptotal);
|
totalSwapKB = num(m.swaptotal)
|
||||||
usedSwapKB = num(m.swaptotal) - num(m.swapfree);
|
usedSwapKB = num(m.swaptotal) - num(m.swapfree)
|
||||||
totalMemoryMB = totalMemoryKB / 1024;
|
totalMemoryMB = totalMemoryKB / 1024
|
||||||
usedMemoryMB = usedMemoryKB / 1024;
|
usedMemoryMB = usedMemoryKB / 1024
|
||||||
freeMemoryMB = (totalMemoryKB - usedMemoryKB) / 1024;
|
freeMemoryMB = (totalMemoryKB - usedMemoryKB) / 1024
|
||||||
availableMemoryMB = num(m.available) ? num(m.available) / 1024 : (free + buf + cached) / 1024;
|
availableMemoryMB = num(
|
||||||
memoryUsage = totalMemoryKB > 0 ? (usedMemoryKB / totalMemoryKB) * 100 : 0;
|
m.available) ? num(
|
||||||
|
m.available) / 1024 : (free + buf + cached) / 1024
|
||||||
|
memoryUsage = totalMemoryKB > 0 ? (usedMemoryKB / totalMemoryKB) * 100 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.cpu) {
|
if (data.cpu) {
|
||||||
cpuCores = data.cpu.count || 1;
|
cpuCores = data.cpu.count || 1
|
||||||
cpuCount = data.cpu.count || 1;
|
cpuCount = data.cpu.count || 1
|
||||||
cpuModel = data.cpu.model || "";
|
cpuModel = data.cpu.model || ""
|
||||||
cpuFrequency = data.cpu.frequency || 0;
|
cpuFrequency = data.cpu.frequency || 0
|
||||||
cpuTemperature = data.cpu.temperature || 0;
|
cpuTemperature = data.cpu.temperature || 0
|
||||||
|
|
||||||
if (data.cpu.total && data.cpu.total.length >= 8) {
|
if (data.cpu.total && data.cpu.total.length >= 8) {
|
||||||
const currentStats = data.cpu.total;
|
const currentStats = data.cpu.total
|
||||||
const usage = calculateCpuUsage(currentStats, lastCpuStats);
|
const usage = calculateCpuUsage(currentStats, lastCpuStats)
|
||||||
cpuUsage = usage;
|
cpuUsage = usage
|
||||||
totalCpuUsage = usage;
|
totalCpuUsage = usage
|
||||||
lastCpuStats = [...currentStats];
|
lastCpuStats = [...currentStats]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.cpu.cores) {
|
if (data.cpu.cores) {
|
||||||
const coreUsages = [];
|
const coreUsages = []
|
||||||
for (var i = 0; i < data.cpu.cores.length; i++) {
|
for (var i = 0; i < data.cpu.cores.length; i++) {
|
||||||
const currentCoreStats = data.cpu.cores[i];
|
const currentCoreStats = data.cpu.cores[i]
|
||||||
if (currentCoreStats && currentCoreStats.length >= 8) {
|
if (currentCoreStats && currentCoreStats.length >= 8) {
|
||||||
let lastCoreStats = null;
|
let lastCoreStats = null
|
||||||
if (lastPerCoreStats && lastPerCoreStats[i]) {
|
if (lastPerCoreStats && lastPerCoreStats[i]) {
|
||||||
lastCoreStats = lastPerCoreStats[i];
|
lastCoreStats = lastPerCoreStats[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
const usage = calculateCpuUsage(currentCoreStats, lastCoreStats);
|
const usage = calculateCpuUsage(currentCoreStats, lastCoreStats)
|
||||||
coreUsages.push(usage);
|
coreUsages.push(usage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON.stringify(perCoreCpuUsage) !== JSON.stringify(coreUsages)) {
|
if (JSON.stringify(perCoreCpuUsage) !== JSON.stringify(coreUsages)) {
|
||||||
perCoreCpuUsage = coreUsages;
|
perCoreCpuUsage = coreUsages
|
||||||
}
|
}
|
||||||
|
|
||||||
lastPerCoreStats = data.cpu.cores.map(core => [...core]);
|
lastPerCoreStats = data.cpu.cores.map(core => [...core])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.network) {
|
if (data.network) {
|
||||||
let totalRx = 0;
|
let totalRx = 0
|
||||||
let totalTx = 0;
|
let totalTx = 0
|
||||||
for (const iface of data.network) {
|
for (const iface of data.network) {
|
||||||
totalRx += iface.rx;
|
totalRx += iface.rx
|
||||||
totalTx += iface.tx;
|
totalTx += iface.tx
|
||||||
}
|
}
|
||||||
if (lastNetworkStats) {
|
if (lastNetworkStats) {
|
||||||
const timeDiff = updateInterval / 1000;
|
const timeDiff = updateInterval / 1000
|
||||||
const rxDiff = totalRx - lastNetworkStats.rx;
|
const rxDiff = totalRx - lastNetworkStats.rx
|
||||||
const txDiff = totalTx - lastNetworkStats.tx;
|
const txDiff = totalTx - lastNetworkStats.tx
|
||||||
networkRxRate = Math.max(0, rxDiff / timeDiff);
|
networkRxRate = Math.max(0, rxDiff / timeDiff)
|
||||||
networkTxRate = Math.max(0, txDiff / timeDiff);
|
networkTxRate = Math.max(0, txDiff / timeDiff)
|
||||||
addToHistory(networkHistory.rx, networkRxRate / 1024);
|
addToHistory(networkHistory.rx, networkRxRate / 1024)
|
||||||
addToHistory(networkHistory.tx, networkTxRate / 1024);
|
addToHistory(networkHistory.tx, networkTxRate / 1024)
|
||||||
}
|
}
|
||||||
lastNetworkStats = {
|
lastNetworkStats = {
|
||||||
"rx": totalRx,
|
"rx": totalRx,
|
||||||
"tx": totalTx
|
"tx": totalTx
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.disk) {
|
if (data.disk) {
|
||||||
let totalRead = 0;
|
let totalRead = 0
|
||||||
let totalWrite = 0;
|
let totalWrite = 0
|
||||||
for (const disk of data.disk) {
|
for (const disk of data.disk) {
|
||||||
totalRead += disk.read * 512;
|
totalRead += disk.read * 512
|
||||||
totalWrite += disk.write * 512;
|
totalWrite += disk.write * 512
|
||||||
}
|
}
|
||||||
if (lastDiskStats) {
|
if (lastDiskStats) {
|
||||||
const timeDiff = updateInterval / 1000;
|
const timeDiff = updateInterval / 1000
|
||||||
const readDiff = totalRead - lastDiskStats.read;
|
const readDiff = totalRead - lastDiskStats.read
|
||||||
const writeDiff = totalWrite - lastDiskStats.write;
|
const writeDiff = totalWrite - lastDiskStats.write
|
||||||
diskReadRate = Math.max(0, readDiff / timeDiff);
|
diskReadRate = Math.max(0, readDiff / timeDiff)
|
||||||
diskWriteRate = Math.max(0, writeDiff / timeDiff);
|
diskWriteRate = Math.max(0, writeDiff / timeDiff)
|
||||||
addToHistory(diskHistory.read, diskReadRate / (1024 * 1024));
|
addToHistory(diskHistory.read, diskReadRate / (1024 * 1024))
|
||||||
addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024));
|
addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024))
|
||||||
}
|
}
|
||||||
lastDiskStats = {
|
lastDiskStats = {
|
||||||
"read": totalRead,
|
"read": totalRead,
|
||||||
"write": totalWrite
|
"write": totalWrite
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalDiff = 0;
|
let totalDiff = 0
|
||||||
if (data.cpu && data.cpu.total && data.cpu.total.length >= 4) {
|
if (data.cpu && data.cpu.total && data.cpu.total.length >= 4) {
|
||||||
const currentTotal = data.cpu.total.reduce((s, v) => s + v, 0);
|
const currentTotal = data.cpu.total.reduce((s, v) => s + v, 0)
|
||||||
if (lastTotalJiffies > 0)
|
if (lastTotalJiffies > 0)
|
||||||
totalDiff = currentTotal - lastTotalJiffies;
|
totalDiff = currentTotal - lastTotalJiffies
|
||||||
lastTotalJiffies = currentTotal;
|
lastTotalJiffies = currentTotal
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.processes) {
|
if (data.processes) {
|
||||||
const newProcesses = [];
|
const newProcesses = []
|
||||||
for (const proc of data.processes) {
|
for (const proc of data.processes) {
|
||||||
const pid = proc.pid;
|
const pid = proc.pid
|
||||||
const pticks = Number(proc.pticks) || 0;
|
const pticks = Number(proc.pticks) || 0
|
||||||
const prev = lastProcTicks[pid] ?? null;
|
const prev = lastProcTicks[pid] ?? null
|
||||||
let cpuShare = 0;
|
let cpuShare = 0
|
||||||
|
|
||||||
if (prev !== null && totalDiff > 0) {
|
if (prev !== null && totalDiff > 0) {
|
||||||
// Per share all CPUs (matches gnome system monitor)
|
// Per share all CPUs (matches gnome system monitor)
|
||||||
//cpuShare = 100 * Math.max(0, pticks - prev) / totalDiff
|
//cpuShare = 100 * Math.max(0, pticks - prev) / totalDiff
|
||||||
|
|
||||||
// per-share per-core
|
// per-share per-core
|
||||||
cpuShare = 100 * cpuCores * Math.max(0, pticks - prev) / totalDiff;
|
cpuShare = 100 * cpuCores * Math.max(0, pticks - prev) / totalDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
lastProcTicks[pid] = pticks; // update cache
|
lastProcTicks[pid] = pticks // update cache
|
||||||
|
|
||||||
newProcesses.push({
|
newProcesses.push({
|
||||||
"pid": pid,
|
"pid": pid,
|
||||||
"ppid": proc.ppid,
|
"ppid": proc.ppid,
|
||||||
"cpu": cpuShare,
|
"cpu": cpuShare,
|
||||||
"memoryPercent": proc.pssPercent ?? proc.memoryPercent,
|
"memoryPercent": proc.pssPercent
|
||||||
|
?? proc.memoryPercent,
|
||||||
"memoryKB": proc.pssKB ?? proc.memoryKB,
|
"memoryKB": proc.pssKB ?? proc.memoryKB,
|
||||||
"command": proc.command,
|
"command": proc.command,
|
||||||
"fullCommand": proc.fullCommand,
|
"fullCommand": proc.fullCommand,
|
||||||
"displayName": (proc.command && proc.command.length > 15) ? proc.command.substring(0, 15) + "..." : proc.command
|
"displayName": (proc.command && proc.command.length
|
||||||
});
|
> 15) ? proc.command.substring(
|
||||||
|
0,
|
||||||
|
15) + "..." : proc.command
|
||||||
|
})
|
||||||
}
|
}
|
||||||
processes = newProcesses;
|
processes = newProcesses
|
||||||
sortProcessesInPlace();
|
sortProcessesInPlace()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.system) {
|
if (data.system) {
|
||||||
kernelVersion = data.system.kernel || "";
|
kernelVersion = data.system.kernel || ""
|
||||||
distribution = data.system.distro || "";
|
distribution = data.system.distro || ""
|
||||||
hostname = data.system.hostname || "";
|
hostname = data.system.hostname || ""
|
||||||
architecture = data.system.arch || "";
|
architecture = data.system.arch || ""
|
||||||
loadAverage = data.system.loadavg || "";
|
loadAverage = data.system.loadavg || ""
|
||||||
processCount = data.system.processes || 0;
|
processCount = data.system.processes || 0
|
||||||
threadCount = data.system.threads || 0;
|
threadCount = data.system.threads || 0
|
||||||
bootTime = data.system.boottime || "";
|
bootTime = data.system.boottime || ""
|
||||||
motherboard = data.system.motherboard || "";
|
motherboard = data.system.motherboard || ""
|
||||||
biosVersion = data.system.bios || "";
|
biosVersion = data.system.bios || ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.diskmounts) {
|
if (data.diskmounts) {
|
||||||
diskMounts = data.diskmounts;
|
diskMounts = data.diskmounts
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.gpus) {
|
if (data.gpus) {
|
||||||
availableGpus = data.gpus;
|
availableGpus = data.gpus
|
||||||
}
|
}
|
||||||
|
|
||||||
addToHistory(cpuHistory, cpuUsage);
|
addToHistory(cpuHistory, cpuUsage)
|
||||||
addToHistory(memoryHistory, memoryUsage);
|
addToHistory(memoryHistory, memoryUsage)
|
||||||
|
|
||||||
isUpdating = false;
|
isUpdating = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProcessIcon(command) {
|
function getProcessIcon(command) {
|
||||||
const cmd = command.toLowerCase();
|
const cmd = command.toLowerCase()
|
||||||
if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser"))
|
if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes(
|
||||||
return "web";
|
"browser"))
|
||||||
|
return "web"
|
||||||
if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim"))
|
if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim"))
|
||||||
return "code";
|
return "code"
|
||||||
if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh"))
|
if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh"))
|
||||||
return "terminal";
|
return "terminal"
|
||||||
if (cmd.includes("music") || cmd.includes("audio") || cmd.includes("spotify"))
|
if (cmd.includes("music") || cmd.includes("audio") || cmd.includes(
|
||||||
return "music_note";
|
"spotify"))
|
||||||
|
return "music_note"
|
||||||
if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv"))
|
if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv"))
|
||||||
return "play_circle";
|
return "play_circle"
|
||||||
if (cmd.includes("systemd") || cmd.includes("kernel") || cmd.includes("kthread"))
|
if (cmd.includes("systemd") || cmd.includes("kernel") || cmd.includes(
|
||||||
return "settings";
|
"kthread"))
|
||||||
return "memory";
|
return "settings"
|
||||||
|
return "memory"
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatCpuUsage(cpu) {
|
function formatCpuUsage(cpu) {
|
||||||
return (cpu || 0).toFixed(1) + "%";
|
return (cpu || 0).toFixed(1) + "%"
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMemoryUsage(memoryKB) {
|
function formatMemoryUsage(memoryKB) {
|
||||||
const mem = memoryKB || 0;
|
const mem = memoryKB || 0
|
||||||
if (mem < 1024)
|
if (mem < 1024)
|
||||||
return mem.toFixed(0) + " KB";
|
return mem.toFixed(0) + " KB"
|
||||||
else if (mem < 1024 * 1024)
|
else if (mem < 1024 * 1024)
|
||||||
return (mem / 1024).toFixed(1) + " MB";
|
return (mem / 1024).toFixed(1) + " MB"
|
||||||
else
|
else
|
||||||
return (mem / (1024 * 1024)).toFixed(1) + " GB";
|
return (mem / (1024 * 1024)).toFixed(1) + " GB"
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatSystemMemory(memoryKB) {
|
function formatSystemMemory(memoryKB) {
|
||||||
const mem = memoryKB || 0;
|
const mem = memoryKB || 0
|
||||||
if (mem < 1024 * 1024)
|
if (mem < 1024 * 1024)
|
||||||
return (mem / 1024).toFixed(0) + " MB";
|
return (mem / 1024).toFixed(0) + " MB"
|
||||||
else
|
else
|
||||||
return (mem / (1024 * 1024)).toFixed(1) + " GB";
|
return (mem / (1024 * 1024)).toFixed(1) + " GB"
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -612,30 +624,195 @@ Singleton {
|
|||||||
gfirst=1
|
gfirst=1
|
||||||
tmp_gpu=$(mktemp)
|
tmp_gpu=$(mktemp)
|
||||||
|
|
||||||
# Gather cards via DRM (much cheaper than lspci each tick)
|
# Function to extract display name from full GPU name
|
||||||
|
extract_display_name() {
|
||||||
|
local full_name="$1"
|
||||||
|
local drv="$2"
|
||||||
|
local display_name=""
|
||||||
|
|
||||||
|
# NVIDIA patterns
|
||||||
|
if [[ "$full_name" =~ GeForce|Quadro|Tesla|NVIDIA ]]; then
|
||||||
|
# Extract model like "RTX 4070", "GTX 1080", "RTX 4090", etc.
|
||||||
|
display_name=$(echo "$full_name" | grep -oE '(RTX|GTX|GT|MX|Tesla|Quadro|TITAN) [0-9]{3,4}( Ti| SUPER| Ti SUPER| Max-Q| Mobile)?' | head -1)
|
||||||
|
|
||||||
|
# If not found, try alternate patterns
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
display_name=$(echo "$full_name" | grep -oE 'GeForce [0-9]{3,4}' | sed 's/GeForce //')
|
||||||
|
fi
|
||||||
|
# AMD patterns
|
||||||
|
elif [[ "$full_name" =~ AMD|Radeon|ATI|Navi|Raphael|Rembrandt|Phoenix|Strix ]]; then
|
||||||
|
# Check for our special integrated graphics format
|
||||||
|
if [[ "$full_name" =~ "AMD Raphael (Integrated Graphics)" ]]; then
|
||||||
|
display_name="Raphael"
|
||||||
|
elif [[ "$full_name" =~ "AMD Phoenix (Integrated Graphics)" ]]; then
|
||||||
|
display_name="Phoenix"
|
||||||
|
elif [[ "$full_name" =~ "AMD Rembrandt (Integrated Graphics)" ]]; then
|
||||||
|
display_name="Rembrandt"
|
||||||
|
else
|
||||||
|
# Check if it contains actual Radeon model numbers
|
||||||
|
display_name=$(echo "$full_name" | grep -oE 'Radeon [0-9]{3,4}[A-Z]*( / [0-9]{3,4}[A-Z]*)?' | head -1)
|
||||||
|
|
||||||
|
# If not, try RX/R series cards
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
display_name=$(echo "$full_name" | grep -oE '(RX|R9|R7|R5|Vega|VII) [0-9]{3,4}( XT| XTX)?' | head -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Strix with Radeon model in brackets
|
||||||
|
if [ -z "$display_name" ] && [[ "$full_name" =~ "Strix" ]]; then
|
||||||
|
if [[ "$full_name" =~ Radeon ]]; then
|
||||||
|
# Extract everything after "Strix "
|
||||||
|
display_name=$(echo "$full_name" | sed 's/.*Strix //')
|
||||||
|
# Remove brackets if present
|
||||||
|
display_name=$(echo "$display_name" | tr -d '[]')
|
||||||
|
else
|
||||||
|
display_name="Strix"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for Navi
|
||||||
|
if [ -z "$display_name" ] && [[ "$full_name" =~ Navi ]]; then
|
||||||
|
display_name=$(echo "$full_name" | grep -oE 'Navi [0-9]+' | head -1)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Intel patterns
|
||||||
|
elif [[ "$full_name" =~ Intel ]]; then
|
||||||
|
# Extract Arc models
|
||||||
|
display_name=$(echo "$full_name" | grep -oE 'Arc A[0-9]{3,4}' | head -1)
|
||||||
|
|
||||||
|
# If not Arc, try Iris/UHD
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
display_name=$(echo "$full_name" | grep -oE '(Iris Xe|UHD|HD) Graphics( [0-9]+)?' | head -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generic Intel graphics
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
display_name="Intel Graphics"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback - but don't cut off at 3 words if it's our special format
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
if [[ "$full_name" =~ "(Integrated Graphics)" ]]; then
|
||||||
|
# Just use the codename part
|
||||||
|
display_name=$(echo "$full_name" | sed 's/AMD //' | sed 's/ (Integrated Graphics)//')
|
||||||
|
else
|
||||||
|
display_name="$full_name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$display_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gather cards via DRM
|
||||||
for card in /sys/class/drm/card*; do
|
for card in /sys/class/drm/card*; do
|
||||||
[ -e "$card/device/driver" ] || continue
|
[ -e "$card/device/driver" ] || continue
|
||||||
|
|
||||||
drv=$(basename "$(readlink -f "$card/device/driver")") # e.g. nvidia, amdgpu, i915
|
drv=$(basename "$(readlink -f "$card/device/driver")")
|
||||||
drv=\${drv##*/}
|
drv=\${drv##*/}
|
||||||
|
|
||||||
# Determine PCI secondary bus to help identify integrated vs discrete
|
# Get PCI path and info
|
||||||
pci_path=$(readlink -f "$card/device") # .../0000:01:00.0
|
pci_path=$(readlink -f "$card/device")
|
||||||
func=\${pci_path##*/} # 0000:01:00.0
|
func=\${pci_path##*/}
|
||||||
sec=\${func#*:}; sec=\${sec%%:*} # "01" from 0000:01:00.0
|
sec=\${func#*:}; sec=\${sec%%:*}
|
||||||
|
|
||||||
# Priority: higher = more likely dedicated
|
# Determine vendor
|
||||||
|
vendor="Unknown"
|
||||||
|
case "$drv" in
|
||||||
|
nvidia) vendor="NVIDIA" ;;
|
||||||
|
amdgpu|radeon) vendor="AMD" ;;
|
||||||
|
i915|xe) vendor="Intel" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Priority
|
||||||
prio=0
|
prio=0
|
||||||
case "$drv" in
|
case "$drv" in
|
||||||
nvidia) prio=3 ;; # dGPU
|
nvidia) prio=3 ;;
|
||||||
amdgpu|radeon)
|
amdgpu|radeon)
|
||||||
if [ "$sec" = "00" ]; then prio=1; else prio=2; fi # APU often on bus 00
|
if [ "$sec" = "00" ]; then prio=1; else prio=2; fi
|
||||||
;;
|
;;
|
||||||
i915) prio=0 ;; # iGPU
|
i915|xe) prio=0 ;;
|
||||||
*) prio=0 ;;
|
*) prio=0 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Temperature via per-device hwmon if available
|
# Get full GPU name
|
||||||
|
full_name=""
|
||||||
|
display_name=""
|
||||||
|
|
||||||
|
# Special handling for NVIDIA with nvidia-smi
|
||||||
|
if [ "$drv" = "nvidia" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
||||||
|
# Get the GPU index for this card
|
||||||
|
gpu_name=$(nvidia-smi --query-gpu=name --format=csv,noheader,nounits 2>/dev/null | head -1 | sed 's/^ *//;s/ *$//' | json_escape)
|
||||||
|
if [ -n "$gpu_name" ]; then
|
||||||
|
full_name="$gpu_name"
|
||||||
|
# Extract display name from nvidia-smi output
|
||||||
|
display_name=$(echo "$gpu_name" | grep -oE '(RTX|GTX|GT|MX|Tesla|Quadro|TITAN) [0-9]{3,4}( Ti| SUPER| Ti SUPER)?' | head -1)
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
display_name="$gpu_name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# AMD specific detection
|
||||||
|
if [ -z "$full_name" ] && [ "$drv" = "amdgpu" -o "$drv" = "radeon" ]; then
|
||||||
|
# Try lspci with proper parsing for AMD GPUs
|
||||||
|
if command -v lspci >/dev/null 2>&1; then
|
||||||
|
pci_addr="\${func}"
|
||||||
|
# Get the full device name
|
||||||
|
lspci_out=$(lspci -s "$pci_addr" 2>/dev/null)
|
||||||
|
# Remove PCI address and device class prefix (everything before the colon)
|
||||||
|
temp_name=$(echo "$lspci_out" | cut -d: -f2- | sed 's/^ *//')
|
||||||
|
|
||||||
|
# Check for AMD/ATI format and extract the GPU name
|
||||||
|
if echo "$temp_name" | grep -q 'AMD/ATI'; then
|
||||||
|
# Extract everything after "] " which comes after [AMD/ATI]
|
||||||
|
# This handles both "Raphael" and "Strix [Radeon 880M / 890M]" formats
|
||||||
|
gpu_name=$(echo "$temp_name" | sed 's/.*\] //' | sed 's/ (rev .*)$//')
|
||||||
|
|
||||||
|
# For codenames like Raphael, add context for full name
|
||||||
|
if [[ "$gpu_name" == "Raphael" ]] || [[ "$gpu_name" == "Phoenix" ]] || [[ "$gpu_name" == "Rembrandt" ]]; then
|
||||||
|
full_name="AMD $gpu_name (Integrated Graphics)"
|
||||||
|
else
|
||||||
|
full_name="$gpu_name"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Fallback: just clean up vendor name
|
||||||
|
full_name=$(echo "$temp_name" | sed 's/Advanced Micro Devices, Inc\. //' | sed 's/ (rev .*)$//')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up and escape for JSON
|
||||||
|
full_name=$(echo "$full_name" | json_escape)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Intel and generic fallback
|
||||||
|
if [ -z "$full_name" ]; then
|
||||||
|
if command -v lspci >/dev/null 2>&1; then
|
||||||
|
pci_addr="\${func}"
|
||||||
|
lspci_out=$(lspci -s "$pci_addr" 2>/dev/null)
|
||||||
|
# Extract device name after the colon
|
||||||
|
full_name=$(echo "$lspci_out" | sed 's/^[0-9a-f:.]* [^:]*: //' | sed 's/ (rev .*)$//' | json_escape)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Final fallback - use driver name
|
||||||
|
if [ -z "$full_name" ] || [[ "$full_name" =~ ^[0-9a-f] ]]; then
|
||||||
|
case "$drv" in
|
||||||
|
nvidia) full_name="NVIDIA GPU" ;;
|
||||||
|
amdgpu|radeon) full_name="AMD GPU" ;;
|
||||||
|
i915|xe) full_name="Intel GPU" ;;
|
||||||
|
*) full_name="Unknown GPU" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract display name
|
||||||
|
display_name=$(extract_display_name "$full_name" "$drv")
|
||||||
|
|
||||||
|
# If display name is still empty, use a simplified version of full name
|
||||||
|
if [ -z "$display_name" ]; then
|
||||||
|
display_name="$full_name"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Temperature
|
||||||
hw=""; temp="0"
|
hw=""; temp="0"
|
||||||
for h in "$card/device"/hwmon/hwmon*; do
|
for h in "$card/device"/hwmon/hwmon*; do
|
||||||
[ -e "$h/temp1_input" ] || continue
|
[ -e "$h/temp1_input" ] || continue
|
||||||
@@ -644,36 +821,35 @@ Singleton {
|
|||||||
break
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
# NVIDIA fallback: use nvidia-smi (first GPU) if temp still 0
|
# NVIDIA temperature fallback
|
||||||
if [ "$drv" = "nvidia" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
if [ "$drv" = "nvidia" ] && [ "$temp" = "0" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
||||||
t=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
t=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
||||||
[ -n "$t" ] && { temp="$t"; hw="\${hw:-nvidia}"; }
|
[ -n "$t" ] && { temp="$t"; hw="\${hw:-nvidia}"; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s|%s|%s|%s\n' "$prio" "$drv" "\${hw:-unknown}" "\${temp:-0}" >> "$tmp_gpu"
|
printf '%s|%s|%s|%s|%s|%s|%s\n' "$prio" "$drv" "\${hw:-unknown}" "\${temp:-0}" "$vendor" "$display_name" "$full_name" >> "$tmp_gpu"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Fallback if no DRM cards found (keep drivers but still sort)
|
# Fallback if no DRM cards found but nvidia-smi is available
|
||||||
if [ ! -s "$tmp_gpu" ]; then
|
if [ ! -s "$tmp_gpu" ]; then
|
||||||
for drv in nvidia amdgpu radeon i915; do
|
if command -v nvidia-smi >/dev/null 2>&1; then
|
||||||
command -v "$drv" >/dev/null 2>&1 || true
|
gpu_info=$(nvidia-smi --query-gpu=name,temperature.gpu --format=csv,noheader 2>/dev/null | head -1)
|
||||||
prio=0; [ "$drv" = "nvidia" ] && prio=3
|
if [ -n "$gpu_info" ]; then
|
||||||
[ "$drv" = "amdgpu" ] && prio=2
|
IFS=',' read -r gpu_name temp <<< "$gpu_info"
|
||||||
[ "$drv" = "radeon" ] && prio=2
|
gpu_name=$(echo "$gpu_name" | sed 's/^ *//;s/ *$//' | json_escape)
|
||||||
[ "$drv" = "i915" ] && prio=0
|
temp=$(echo "$temp" | sed 's/^ *//;s/ *$//')
|
||||||
temp="0"; hw="$drv"
|
display_name=$(echo "$gpu_name" | grep -oE '(RTX|GTX|GT|MX|Tesla|Quadro) [0-9]{3,4}( Ti| SUPER| Ti SUPER)?' | head -1)
|
||||||
if [ "$drv" = "nvidia" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
[ -z "$display_name" ] && display_name="$gpu_name"
|
||||||
t=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
printf '3|nvidia|nvidia|%s|NVIDIA|%s|%s\n' "\${temp:-0}" "$display_name" "$gpu_name" >> "$tmp_gpu"
|
||||||
[ -n "$t" ] && temp="$t"
|
fi
|
||||||
fi
|
fi
|
||||||
printf '%s|%s|%s|%s\n' "$prio" "$drv" "$hw" "$temp" >> "$tmp_gpu"
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Sort by priority (desc), then driver name for stability, and emit SAME JSON shape
|
# Sort and output JSON
|
||||||
while IFS='|' read -r pr drv hw temp; do
|
while IFS='|' read -r pr drv hw temp vendor display_name full_name; do
|
||||||
[ $gfirst -eq 1 ] || printf ","
|
[ $gfirst -eq 1 ] || printf ","
|
||||||
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "$hw" "$temp"
|
printf '{"driver":"%s","hwmon":"%s","temperature":%s,"vendor":"%s","displayName":"%s","fullName":"%s"}' \\
|
||||||
|
"$drv" "$hw" "$temp" "$vendor" "$display_name" "$full_name"
|
||||||
gfirst=0
|
gfirst=0
|
||||||
done < <(sort -t'|' -k1,1nr -k2,2 "$tmp_gpu")
|
done < <(sort -t'|' -k1,1nr -k2,2 "$tmp_gpu")
|
||||||
|
|
||||||
@@ -684,30 +860,31 @@ Singleton {
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: unifiedStatsProcess
|
id: unifiedStatsProcess
|
||||||
command: ["bash", "-c", "bash -s \"$1\" \"$2\" <<'QS_EOF'\n" + root.scriptBody + "\nQS_EOF\n", root.sortBy, String(root.maxProcesses)]
|
command: ["bash", "-c", "bash -s \"$1\" \"$2\" <<'QS_EOF'\n"
|
||||||
|
+ root.scriptBody + "\nQS_EOF\n", root.sortBy, String(root.maxProcesses)]
|
||||||
running: false
|
running: false
|
||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
isUpdating = false;
|
isUpdating = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
if (text.trim()) {
|
if (text.trim()) {
|
||||||
const fullText = text.trim();
|
const fullText = text.trim()
|
||||||
const lastBraceIndex = fullText.lastIndexOf('}');
|
const lastBraceIndex = fullText.lastIndexOf('}')
|
||||||
if (lastBraceIndex === -1) {
|
if (lastBraceIndex === -1) {
|
||||||
isUpdating = false;
|
isUpdating = false
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
const jsonText = fullText.substring(0, lastBraceIndex + 1);
|
const jsonText = fullText.substring(0, lastBraceIndex + 1)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(jsonText);
|
const data = JSON.parse(jsonText)
|
||||||
parseUnifiedStats(jsonText);
|
parseUnifiedStats(jsonText)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isUpdating = false;
|
isUpdating = false
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user