1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

feat: add temperature widgets, separate ram/cpu widgets, update

calculations
- make CPU calculations per-process mirror gnome (of all CPUs)
This commit is contained in:
bbedward
2025-08-08 14:43:43 -04:00
parent 105353c2a4
commit 03276b7d9a
27 changed files with 794 additions and 254 deletions

View File

@@ -29,7 +29,11 @@ Singleton {
property bool showWeather: true
property bool showMusic: true
property bool showClipboard: true
property bool showSystemResources: true
property bool showCpuUsage: true
property bool showMemUsage: true
property bool showCpuTemp: true
property bool showGpuTemp: true
property int selectedGpuIndex: 0
property bool showSystemTray: true
property bool showClock: true
property bool showNotificationButton: true
@@ -41,13 +45,14 @@ Singleton {
property bool mediaCompactMode: false
property var topBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
property var topBarCenterWidgets: ["music", "clock", "weather"]
property var topBarRightWidgets: ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"]
property var topBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
property alias topBarLeftWidgetsModel: leftWidgetsModel
property alias topBarCenterWidgetsModel: centerWidgetsModel
property alias topBarRightWidgetsModel: rightWidgetsModel
signal forceTopBarLayoutRefresh()
signal widgetDataChanged()
ListModel {
id: leftWidgetsModel
@@ -150,7 +155,11 @@ Singleton {
showWeather = settings.showWeather !== undefined ? settings.showWeather : true;
showMusic = settings.showMusic !== undefined ? settings.showMusic : true;
showClipboard = settings.showClipboard !== undefined ? settings.showClipboard : true;
showSystemResources = settings.showSystemResources !== undefined ? settings.showSystemResources : true;
showCpuUsage = settings.showCpuUsage !== undefined ? settings.showCpuUsage : true;
showMemUsage = settings.showMemUsage !== undefined ? settings.showMemUsage : true;
showCpuTemp = settings.showCpuTemp !== undefined ? settings.showCpuTemp : true;
showGpuTemp = settings.showGpuTemp !== undefined ? settings.showGpuTemp : true;
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0;
showSystemTray = settings.showSystemTray !== undefined ? settings.showSystemTray : true;
showClock = settings.showClock !== undefined ? settings.showClock : true;
showNotificationButton = settings.showNotificationButton !== undefined ? settings.showNotificationButton : true;
@@ -167,7 +176,7 @@ Singleton {
} else {
var leftWidgets = settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"];
var centerWidgets = settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"];
var rightWidgets = settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"];
var rightWidgets = settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"];
topBarLeftWidgets = leftWidgets;
topBarCenterWidgets = centerWidgets;
@@ -227,7 +236,11 @@ Singleton {
"showWeather": showWeather,
"showMusic": showMusic,
"showClipboard": showClipboard,
"showSystemResources": showSystemResources,
"showCpuUsage": showCpuUsage,
"showMemUsage": showMemUsage,
"showCpuTemp": showCpuTemp,
"showGpuTemp": showGpuTemp,
"selectedGpuIndex": selectedGpuIndex,
"showSystemTray": showSystemTray,
"showClock": showClock,
"showNotificationButton": showNotificationButton,
@@ -370,8 +383,28 @@ Singleton {
saveSettings();
}
function setShowSystemResources(enabled) {
showSystemResources = enabled;
function setShowCpuUsage(enabled) {
showCpuUsage = enabled;
saveSettings();
}
function setShowMemUsage(enabled) {
showMemUsage = enabled;
saveSettings();
}
function setShowCpuTemp(enabled) {
showCpuTemp = enabled;
saveSettings();
}
function setShowGpuTemp(enabled) {
showGpuTemp = enabled;
saveSettings();
}
function setSelectedGpuIndex(index) {
selectedGpuIndex = index;
saveSettings();
}
@@ -429,19 +462,25 @@ Singleton {
var widgetId = typeof order[i] === "string" ? order[i] : order[i].id;
var enabled = typeof order[i] === "string" ? true : order[i].enabled;
var size = typeof order[i] === "string" ? undefined : order[i].size;
var selectedGpuIndex = typeof order[i] === "string" ? undefined : order[i].selectedGpuIndex;
var item = {"widgetId": widgetId, "enabled": enabled};
if (size !== undefined) {
item.size = size;
}
if (selectedGpuIndex !== undefined) {
item.selectedGpuIndex = selectedGpuIndex;
}
listModel.append(item);
}
// Emit signal to notify widgets that data has changed
widgetDataChanged();
}
function resetTopBarWidgetsToDefault() {
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"];
var defaultCenter = ["music", "clock", "weather"];
var defaultRight = ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"];
var defaultRight = ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"];
topBarLeftWidgets = defaultLeft;
topBarCenterWidgets = defaultCenter;
@@ -457,7 +496,10 @@ Singleton {
showWeather = true;
showMusic = true;
showClipboard = true;
showSystemResources = true;
showCpuUsage = true;
showMemUsage = true;
showCpuTemp = true;
showGpuTemp = true;
showSystemTray = true;
showClock = true;
showNotificationButton = true;

View File

@@ -354,6 +354,10 @@ Singleton {
property color info: "#2196F3"
property color error: "#F2B8B5"
// Temperature-specific colors
property color tempWarning: "#ff9933" // Balanced orange for warm temperatures
property color tempDanger: "#ff5555" // Balanced red for dangerous temperatures
property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12)
property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, 0.08)
property color primaryPressed: Qt.rgba(primary.r, primary.g, primary.b, 0.16)

View File

@@ -285,7 +285,6 @@ DankModal {
DankListView {
id: resultsList
mouseWheelSpeed: 20
property int itemHeight: 60
property int iconSize: 40

View File

@@ -370,7 +370,6 @@ PanelWindow {
DankListView {
id: appList
mouseWheelSpeed: 20
property int itemHeight: 72
property int iconSize: 56

View File

@@ -41,7 +41,6 @@ Item {
clip: true
contentHeight: outputColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: outputColumn
@@ -68,7 +67,6 @@ Item {
clip: true
contentHeight: inputColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: inputColumn

View File

@@ -19,7 +19,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn

View File

@@ -28,7 +28,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn

View File

@@ -51,12 +51,44 @@ Row {
opacity: SysMonitorService.sortBy === "cpu" ? 1 : 0.8
}
StyledText {
text: SysMonitorService.totalCpuUsage.toFixed(1) + "%"
font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
color: Theme.surfaceText
Row {
spacing: Theme.spacingS
StyledText {
text: SysMonitorService.totalCpuUsage.toFixed(1) + "%"
font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: 1
height: 20
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (SysMonitorService.cpuTemperature === undefined || SysMonitorService.cpuTemperature === null || SysMonitorService.cpuTemperature < 0) {
return "--°";
}
return Math.round(SysMonitorService.cpuTemperature) + "°";
}
font.pixelSize: Theme.fontSizeMedium
font.family: SettingsData.monoFontFamily
font.weight: Font.Medium
color: {
if (SysMonitorService.cpuTemperature > 80)
return Theme.error;
if (SysMonitorService.cpuTemperature > 60)
return Theme.warning;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
@@ -123,16 +155,44 @@ Row {
opacity: SysMonitorService.sortBy === "memory" ? 1 : 0.8
}
StyledText {
text: SysMonitorService.formatSystemMemory(SysMonitorService.usedMemoryKB)
font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
color: Theme.surfaceText
Row {
spacing: Theme.spacingS
StyledText {
text: SysMonitorService.formatSystemMemory(SysMonitorService.usedMemoryKB)
font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: 1
height: 20
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
anchors.verticalCenter: parent.verticalCenter
visible: SysMonitorService.totalSwapKB > 0
}
StyledText {
text: SysMonitorService.totalSwapKB > 0 ? SysMonitorService.formatSystemMemory(SysMonitorService.usedSwapKB) : ""
font.pixelSize: Theme.fontSizeMedium
font.family: SettingsData.monoFontFamily
font.weight: Font.Medium
color: SysMonitorService.usedSwapKB > 0 ? Theme.warning : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: SysMonitorService.totalSwapKB > 0
}
}
StyledText {
text: "of " + SysMonitorService.formatSystemMemory(SysMonitorService.totalMemoryKB)
text: {
if (SysMonitorService.totalSwapKB > 0) {
return "of " + SysMonitorService.formatSystemMemory(SysMonitorService.totalMemoryKB) + " + swap";
}
return "of " + SysMonitorService.formatSystemMemory(SysMonitorService.totalMemoryKB);
}
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
color: Theme.surfaceText
@@ -161,8 +221,8 @@ Row {
width: (parent.width - Theme.spacingM * 2) / 3
height: 80
radius: Theme.cornerRadiusLarge
color: SysMonitorService.totalSwapKB > 0 ? Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.08) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.04)
border.color: SysMonitorService.totalSwapKB > 0 ? Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.2) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.12)
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
border.color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
border.width: 1
Column {
@@ -172,23 +232,74 @@ Row {
spacing: 2
StyledText {
text: "Swap"
text: "Graphics"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: SysMonitorService.totalSwapKB > 0 ? Theme.warning : Theme.surfaceText
color: Theme.secondary
opacity: 0.8
}
StyledText {
text: SysMonitorService.totalSwapKB > 0 ? SysMonitorService.formatSystemMemory(SysMonitorService.usedSwapKB) : "None"
text: {
if (!SysMonitorService.availableGpus || 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 "--°";
}
font.pixelSize: Theme.fontSizeLarge
font.family: SettingsData.monoFontFamily
font.weight: Font.Bold
color: Theme.surfaceText
color: {
if (!SysMonitorService.availableGpus || SysMonitorService.availableGpus.length === 0) {
return Theme.surfaceText;
}
if (SysMonitorService.availableGpus.length === 1) {
var temp = SysMonitorService.availableGpus[0].temperature || 0;
if (temp > 80) return Theme.tempDanger;
if (temp > 60) return Theme.tempWarning;
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;
}
}
StyledText {
text: SysMonitorService.totalSwapKB > 0 ? "of " + SysMonitorService.formatSystemMemory(SysMonitorService.totalSwapKB) : "No swap configured"
text: {
if (!SysMonitorService.availableGpus || SysMonitorService.availableGpus.length === 0) {
return "No GPUs detected";
}
if (SysMonitorService.availableGpus.length === 1) {
return SysMonitorService.availableGpus[0].driver.toUpperCase();
}
return SysMonitorService.availableGpus.length + " GPUs detected";
}
font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily
color: Theme.surfaceText

View File

@@ -15,7 +15,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn

View File

@@ -14,7 +14,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn

View File

@@ -20,7 +20,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn

View File

@@ -13,7 +13,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn

View File

@@ -49,11 +49,29 @@ Item {
"icon": "content_paste",
"enabled": true
}, {
"id": "systemResources",
"text": "System Resources",
"description": "CPU and memory usage indicators",
"id": "cpuUsage",
"text": "CPU Usage",
"description": "CPU usage indicator",
"icon": "memory",
"enabled": true
}, {
"id": "memUsage",
"text": "Memory Usage",
"description": "Memory usage indicator",
"icon": "storage",
"enabled": true
}, {
"id": "cpuTemp",
"text": "CPU Temperature",
"description": "CPU temperature display",
"icon": "device_thermostat",
"enabled": true
}, {
"id": "gpuTemp",
"text": "GPU Temperature",
"description": "GPU temperature display",
"icon": "auto_awesome_mosaic",
"enabled": true
}, {
"id": "systemTray",
"text": "System Tray",
@@ -127,7 +145,10 @@ Item {
"id": "clipboard",
"enabled": true
}, {
"id": "systemResources",
"id": "cpuUsage",
"enabled": true
}, {
"id": "memUsage",
"enabled": true
}, {
"id": "notificationButton",
@@ -147,6 +168,8 @@ Item {
};
if (widgetId === "spacer")
widgetObj.size = 20;
if (widgetId === "gpuTemp")
widgetObj.selectedGpuIndex = 0;
var widgets = [];
if (targetSection === "left") {
@@ -164,28 +187,25 @@ Item {
}
}
function removeWidgetFromSection(sectionId, itemId) {
function removeWidgetFromSection(sectionId, widgetIndex) {
var widgets = [];
if (sectionId === "left") {
widgets = SettingsData.topBarLeftWidgets.slice();
widgets = widgets.filter((widget) => {
var widgetId = typeof widget === "string" ? widget : widget.id;
return widgetId !== itemId;
});
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1);
}
SettingsData.setTopBarLeftWidgets(widgets);
} else if (sectionId === "center") {
widgets = SettingsData.topBarCenterWidgets.slice();
widgets = widgets.filter((widget) => {
var widgetId = typeof widget === "string" ? widget : widget.id;
return widgetId !== itemId;
});
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1);
}
SettingsData.setTopBarCenterWidgets(widgets);
} else if (sectionId === "right") {
widgets = SettingsData.topBarRightWidgets.slice();
widgets = widgets.filter((widget) => {
var widgetId = typeof widget === "string" ? widget : widget.id;
return widgetId !== itemId;
});
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1);
}
SettingsData.setTopBarRightWidgets(widgets);
}
}
@@ -208,7 +228,8 @@ Item {
} : {
"id": widget.id,
"enabled": enabled,
"size": widget.size
"size": widget.size,
"selectedGpuIndex": widget.selectedGpuIndex
};
break;
}
@@ -249,7 +270,8 @@ Item {
} : {
"id": widget.id,
"enabled": widget.enabled,
"size": newSize
"size": newSize,
"selectedGpuIndex": widget.selectedGpuIndex
};
break;
}
@@ -262,6 +284,37 @@ Item {
SettingsData.setTopBarRightWidgets(widgets);
}
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
var widgets = [];
if (sectionId === "left")
widgets = SettingsData.topBarLeftWidgets.slice();
else if (sectionId === "center")
widgets = SettingsData.topBarCenterWidgets.slice();
else if (sectionId === "right")
widgets = SettingsData.topBarRightWidgets.slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex];
widgets[widgetIndex] = typeof widget === "string" ? {
"id": widget,
"enabled": true,
"selectedGpuIndex": selectedGpuIndex
} : {
"id": widget.id,
"enabled": widget.enabled,
"size": widget.size,
"selectedGpuIndex": selectedGpuIndex
};
}
if (sectionId === "left")
SettingsData.setTopBarLeftWidgets(widgets);
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(widgets);
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(widgets);
}
function getItemsForSection(sectionId) {
var widgets = [];
var widgetData = [];
@@ -275,6 +328,7 @@ Item {
var widgetId = typeof widget === "string" ? widget : widget.id;
var widgetEnabled = typeof widget === "string" ? true : widget.enabled;
var widgetSize = typeof widget === "string" ? undefined : widget.size;
var widgetSelectedGpuIndex = typeof widget === "string" ? undefined : widget.selectedGpuIndex;
var widgetDef = baseWidgetDefinitions.find((w) => {
return w.id === widgetId;
});
@@ -284,6 +338,8 @@ Item {
item.enabled = widgetEnabled;
if (widgetSize !== undefined)
item.size = widgetSize;
if (widgetSelectedGpuIndex !== undefined)
item.selectedGpuIndex = widgetSelectedGpuIndex;
widgets.push(item);
}
@@ -338,7 +394,6 @@ Item {
clip: true
contentHeight: mainColumn.height
contentWidth: width
mouseWheelSpeed: 20
Column {
id: mainColumn
@@ -487,7 +542,7 @@ Item {
width: parent.width
spacing: Theme.spacingL
DankSections {
WidgetsTabSection {
width: parent.width
title: "Left Section"
titleIcon: "format_align_left"
@@ -505,8 +560,8 @@ Item {
widgetSelectionPopup.targetSection = sectionId;
widgetSelectionPopup.safeOpen();
}
onRemoveWidget: (sectionId, itemId) => {
widgetsTab.removeWidgetFromSection(sectionId, itemId);
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId, widgetIndex);
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId, itemId, newSize);
@@ -518,9 +573,12 @@ Item {
SettingsData.setMediaCompactMode(enabled);
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(sectionId, widgetIndex, selectedIndex);
}
}
DankSections {
WidgetsTabSection {
width: parent.width
title: "Center Section"
titleIcon: "format_align_center"
@@ -538,8 +596,8 @@ Item {
widgetSelectionPopup.targetSection = sectionId;
widgetSelectionPopup.safeOpen();
}
onRemoveWidget: (sectionId, itemId) => {
widgetsTab.removeWidgetFromSection(sectionId, itemId);
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId, widgetIndex);
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId, itemId, newSize);
@@ -551,9 +609,12 @@ Item {
SettingsData.setMediaCompactMode(enabled);
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(sectionId, widgetIndex, selectedIndex);
}
}
DankSections {
WidgetsTabSection {
width: parent.width
title: "Right Section"
titleIcon: "format_align_right"
@@ -571,8 +632,8 @@ Item {
widgetSelectionPopup.targetSection = sectionId;
widgetSelectionPopup.safeOpen();
}
onRemoveWidget: (sectionId, itemId) => {
widgetsTab.removeWidgetFromSection(sectionId, itemId);
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId, widgetIndex);
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId, itemId, newSize);
@@ -584,6 +645,9 @@ Item {
SettingsData.setMediaCompactMode(enabled);
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(sectionId, widgetIndex, selectedIndex);
}
}
}
}

View File

@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
import qs.Services
Column {
id: root
@@ -15,9 +16,10 @@ Column {
signal itemEnabledChanged(string sectionId, string itemId, bool enabled)
signal itemOrderChanged(var newOrder)
signal addWidget(string sectionId)
signal removeWidget(string sectionId, string itemId)
signal removeWidget(string sectionId, int widgetIndex)
signal spacerSizeChanged(string sectionId, string itemId, int newSize)
signal compactModeChanged(string widgetId, bool enabled)
signal gpuSelectionChanged(string sectionId, int widgetIndex, int selectedIndex)
width: parent.width
height: implicitHeight
@@ -133,6 +135,41 @@ Column {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
Item {
width: 120
height: 32
visible: modelData.id === "gpuTemp"
DankDropdown {
id: gpuDropdown
anchors.fill: parent
currentValue: {
var selectedIndex = modelData.selectedGpuIndex !== undefined ? modelData.selectedGpuIndex : 0;
if (SysMonitorService.availableGpus && SysMonitorService.availableGpus.length > selectedIndex && selectedIndex >= 0) {
var gpu = SysMonitorService.availableGpus[selectedIndex];
return gpu.driver.toUpperCase() + " (" + Math.round(gpu.temperature || 0) + "°C)";
}
return SysMonitorService.availableGpus && SysMonitorService.availableGpus.length > 0 ? SysMonitorService.availableGpus[0].driver.toUpperCase() + " (" + Math.round(SysMonitorService.availableGpus[0].temperature || 0) + "°C)" : "";
}
options: {
var gpuOptions = [];
if (SysMonitorService.availableGpus && SysMonitorService.availableGpus.length > 0) {
for (var i = 0; i < SysMonitorService.availableGpus.length; i++) {
var gpu = SysMonitorService.availableGpus[i];
gpuOptions.push(gpu.driver.toUpperCase() + " (" + Math.round(gpu.temperature || 0) + "°C)");
}
}
return gpuOptions;
}
onValueChanged: (value) => {
var gpuIndex = options.indexOf(value);
if (gpuIndex >= 0) {
root.gpuSelectionChanged(root.sectionId, index, gpuIndex);
}
}
}
}
Item {
width: 32
height: 32
@@ -240,7 +277,7 @@ Column {
iconSize: 18
iconColor: Theme.error
onClicked: {
root.removeWidget(root.sectionId, modelData.id);
root.removeWidget(root.sectionId, index);
}
}

View File

@@ -57,10 +57,10 @@ Rectangle {
size: Theme.iconSize - 8
color: {
if (SysMonitorService.cpuUsage > 80)
return Theme.error;
return Theme.tempDanger;
if (SysMonitorService.cpuUsage > 60)
return Theme.warning;
return Theme.tempWarning;
return Theme.surfaceText;
}
@@ -68,7 +68,12 @@ Rectangle {
}
StyledText {
text: (SysMonitorService.cpuUsage || 0).toFixed(0) + "%"
text: {
if (SysMonitorService.cpuUsage === undefined || SysMonitorService.cpuUsage === null || SysMonitorService.cpuUsage === 0) {
return "--%";
}
return SysMonitorService.cpuUsage.toFixed(0) + "%";
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText

View File

@@ -0,0 +1,91 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
width: 55
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = cpuTempArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Component.onCompleted: {
SysMonitorService.addRef();
}
Component.onDestruction: {
SysMonitorService.removeRef();
}
MouseArea {
id: cpuTempArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, Theme.barHeight + Theme.spacingXS, width, section, currentScreen);
}
SysMonitorService.setSortBy("cpu");
if (root.toggleProcessList)
root.toggleProcessList();
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "memory"
size: Theme.iconSize - 8
color: {
if (SysMonitorService.cpuTemperature > 85)
return Theme.tempDanger;
if (SysMonitorService.cpuTemperature > 69)
return Theme.tempWarning;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (SysMonitorService.cpuTemperature === undefined || SysMonitorService.cpuTemperature === null || SysMonitorService.cpuTemperature < 0) {
return "--°";
}
return Math.round(SysMonitorService.cpuTemperature) + "°";
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -0,0 +1,111 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
Rectangle {
id: root
property bool showPercentage: true
property bool showIcon: true
property var toggleProcessList
property string section: "right"
property var popupTarget: null
property var parentScreen: null
property var widgetData: null
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
Connections {
target: SettingsData
function onWidgetDataChanged() {
// Force property re-evaluation by triggering change detection
root.selectedGpuIndex = Qt.binding(() => {
return (root.widgetData && root.widgetData.selectedGpuIndex !== undefined) ? root.widgetData.selectedGpuIndex : 0;
});
}
}
width: 55
height: 30
radius: Theme.cornerRadius
color: {
const baseColor = gpuArea.containsMouse ? Theme.primaryPressed : Theme.secondaryHover;
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
}
Component.onCompleted: {
SysMonitorService.addRef();
}
Component.onDestruction: {
SysMonitorService.removeRef();
}
property real displayTemp: {
if (!SysMonitorService.availableGpus || SysMonitorService.availableGpus.length === 0) return 0;
if (selectedGpuIndex >= 0 && selectedGpuIndex < SysMonitorService.availableGpus.length) {
return SysMonitorService.availableGpus[selectedGpuIndex].temperature || 0;
}
return 0;
}
MouseArea {
id: gpuArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (popupTarget && popupTarget.setTriggerPosition) {
var globalPos = mapToGlobal(0, 0);
var currentScreen = parentScreen || Screen;
var screenX = currentScreen.x || 0;
var relativeX = globalPos.x - screenX;
popupTarget.setTriggerPosition(relativeX, Theme.barHeight + Theme.spacingXS, width, section, currentScreen);
}
SysMonitorService.setSortBy("cpu");
if (root.toggleProcessList)
root.toggleProcessList();
}
}
Row {
anchors.centerIn: parent
spacing: 3
DankIcon {
name: "auto_awesome_mosaic"
size: Theme.iconSize - 8
color: {
if (root.displayTemp > 80)
return Theme.tempDanger;
if (root.displayTemp > 65)
return Theme.tempWarning;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
return "--°";
}
return Math.round(root.displayTemp) + "°";
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -57,10 +57,10 @@ Rectangle {
size: Theme.iconSize - 8
color: {
if (SysMonitorService.memoryUsage > 90)
return Theme.error;
return Theme.tempDanger;
if (SysMonitorService.memoryUsage > 75)
return Theme.warning;
return Theme.tempWarning;
return Theme.surfaceText;
}
@@ -68,7 +68,12 @@ Rectangle {
}
StyledText {
text: (SysMonitorService.memoryUsage || 0).toFixed(0) + "%"
text: {
if (SysMonitorService.memoryUsage === undefined || SysMonitorService.memoryUsage === null || SysMonitorService.memoryUsage === 0) {
return "--%";
}
return SysMonitorService.memoryUsage.toFixed(0) + "%";
}
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText

View File

@@ -180,7 +180,13 @@ PanelWindow {
return true;
case "clipboard":
return true;
case "systemResources":
case "cpuUsage":
return true;
case "memUsage":
return true;
case "cpuTemp":
return true;
case "gpuTemp":
return true;
case "notificationButton":
return true;
@@ -217,8 +223,14 @@ PanelWindow {
return privacyIndicatorComponent;
case "clipboard":
return clipboardComponent;
case "systemResources":
return systemResourcesComponent;
case "cpuUsage":
return cpuUsageComponent;
case "memUsage":
return memUsageComponent;
case "cpuTemp":
return cpuTempComponent;
case "gpuTemp":
return gpuTempComponent;
case "notificationButton":
return notificationButtonComponent;
case "battery":
@@ -606,39 +618,78 @@ PanelWindow {
}
Component {
id: systemResourcesComponent
id: cpuUsageComponent
Row {
spacing: Theme.spacingXS
CpuMonitor {
section: {
if (parent && parent.parent && parent.parent.parent === leftSection) return "left";
if (parent && parent.parent && parent.parent.parent === rightSection) return "right";
if (parent && parent.parent && parent.parent.parent === centerSection) return "center";
return "right";
}
popupTarget: processListPopout
parentScreen: root.screen
toggleProcessList: () => {
return processListPopout.toggle();
}
CpuMonitor {
section: {
if (parent && parent.parent === leftSection) return "left";
if (parent && parent.parent === rightSection) return "right";
if (parent && parent.parent === centerSection) return "center";
return "right";
}
RamMonitor {
section: {
if (parent && parent.parent && parent.parent.parent === leftSection) return "left";
if (parent && parent.parent && parent.parent.parent === rightSection) return "right";
if (parent && parent.parent && parent.parent.parent === centerSection) return "center";
return "right";
}
popupTarget: processListPopout
parentScreen: root.screen
toggleProcessList: () => {
return processListPopout.toggle();
}
popupTarget: processListPopout
parentScreen: root.screen
toggleProcessList: () => {
return processListPopout.toggle();
}
}
}
Component {
id: memUsageComponent
RamMonitor {
section: {
if (parent && parent.parent === leftSection) return "left";
if (parent && parent.parent === rightSection) return "right";
if (parent && parent.parent === centerSection) return "center";
return "right";
}
popupTarget: processListPopout
parentScreen: root.screen
toggleProcessList: () => {
return processListPopout.toggle();
}
}
}
Component {
id: cpuTempComponent
CpuTemperature {
section: {
if (parent && parent.parent === leftSection) return "left";
if (parent && parent.parent === rightSection) return "right";
if (parent && parent.parent === centerSection) return "center";
return "right";
}
popupTarget: processListPopout
parentScreen: root.screen
toggleProcessList: () => {
return processListPopout.toggle();
}
}
}
Component {
id: gpuTempComponent
GpuTemperature {
section: {
if (parent && parent.parent === leftSection) return "left";
if (parent && parent.parent === rightSection) return "right";
if (parent && parent.parent === centerSection) return "center";
return "right";
}
popupTarget: processListPopout
parentScreen: root.screen
widgetData: parent.widgetData
toggleProcessList: () => {
return processListPopout.toggle();
}
}
}

View File

@@ -39,7 +39,13 @@ Rectangle {
}
StyledText {
text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" + (SettingsData.useFahrenheit ? "F" : "C")
text: {
var temp = SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp;
if (temp === undefined || temp === null || temp === 0) {
return "--°" + (SettingsData.useFahrenheit ? "F" : "C");
}
return temp + "°" + (SettingsData.useFahrenheit ? "F" : "C");
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter

View File

@@ -1,60 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property bool isIdle: false
property int idleThresholdSeconds: 300 // 5 minutes
property int checkInterval: 30000 // Check every 30 seconds
signal idleChanged(bool idle)
function checkIdleState() {
if (idleChecker.running) return
idleChecker.running = true
}
Timer {
id: idleTimer
interval: root.checkInterval
running: true
repeat: true
onTriggered: root.checkIdleState()
}
Process {
id: idleChecker
command: ["bash", "-c", "if command -v xprintidle >/dev/null 2>&1; then echo $(( $(xprintidle) / 1000 )); elif command -v qdbus >/dev/null 2>&1; then qdbus org.freedesktop.ScreenSaver /org/freedesktop/ScreenSaver GetSessionIdleTime 2>/dev/null || echo 0; else echo 0; fi"]
running: false
stdout: SplitParser {
splitMarker: "\n"
onRead: (data) => {
const idleSeconds = parseInt(data.trim()) || 0
const wasIdle = root.isIdle
root.isIdle = idleSeconds >= root.idleThresholdSeconds
if (wasIdle !== root.isIdle) {
console.log("IdleService: System idle state changed to:", root.isIdle ? "idle" : "active", "(" + idleSeconds + "s)")
root.idleChanged(root.isIdle)
}
}
}
onExited: (exitCode) => {
if (exitCode !== 0) {
console.warn("IdleService: Failed to check idle state, exit code:", exitCode)
}
}
}
Component.onCompleted: {
console.log("IdleService: Initialized with", root.idleThresholdSeconds + "s threshold")
checkIdleState()
}
}

View File

@@ -8,21 +8,23 @@ import qs.Services
Singleton {
id: root
property int refCount: 0
property int updateInterval: refCount > 0 ? 2000 : 30000
property int updateInterval: refCount > 0 ? 3000 : 30000
property int maxProcesses: 100
property bool isUpdating: false
property var processes: []
property string sortBy: "cpu"
property bool sortDescending: true
property var lastProcTicks: ({})
property real lastTotalJiffies: -1
property real cpuUsage: 0
property real totalCpuUsage: 0
property int cpuCores: 1
property int cpuCount: 1
property string cpuModel: ""
property real cpuFrequency: 0
property real cpuTemperature: 0
property real cpuTemperature: -1
property var perCoreCpuUsage: []
property var lastCpuStats: null
@@ -69,6 +71,7 @@ Singleton {
property string bootTime: ""
property string motherboard: ""
property string biosVersion: ""
property var availableGpus: []
function addRef() {
refCount++;
@@ -277,19 +280,43 @@ Singleton {
}
lastDiskStats = { "read": totalRead, "write": totalWrite };
}
let totalDiff = 0;
if (data.cpu && data.cpu.total && data.cpu.total.length >= 4) {
const currentTotal = data.cpu.total.reduce((s,v)=>s+v, 0);
if (lastTotalJiffies > 0)
totalDiff = currentTotal - lastTotalJiffies;
lastTotalJiffies = currentTotal;
}
if (data.processes) {
const newProcesses = [];
for (const proc of data.processes) {
const pid = proc.pid;
const pticks = Number(proc.pticks) || 0;
const prev = lastProcTicks[pid] ?? null;
let cpuShare = 0;
if (prev !== null && totalDiff > 0) {
// Per share all CPUs (matches gnome system monitor)
cpuShare = 100 * Math.max(0, pticks - prev) / totalDiff;
// per-share per-core
//cpuShare = 100 * cpuCores * Math.max(0, pticks - prev) / totalDiff;
}
lastProcTicks[pid] = pticks; // update cache
newProcesses.push({
"pid": proc.pid,
"pid": pid,
"ppid": proc.ppid,
"cpu": proc.cpu,
"cpu": cpuShare,
"memoryPercent": proc.pssPercent ?? proc.memoryPercent,
"memoryKB": proc.pssKB ?? proc.memoryKB,
"command": proc.command,
"fullCommand": proc.fullCommand,
"displayName": 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;
@@ -313,6 +340,10 @@ Singleton {
diskMounts = data.diskmounts;
}
if (data.gpus) {
availableGpus = data.gpus;
}
addToHistory(cpuHistory, cpuUsage);
addToHistory(memoryHistory, memoryUsage);
@@ -358,32 +389,16 @@ Singleton {
return (mem / (1024 * 1024)).toFixed(1) + " GB";
}
function getCpuTempCentigrade() {
cpuTempProcess.running = true;
}
Timer {
id: updateTimer
interval: root.updateInterval
running: root.refCount > 0 && !IdleService.isIdle
running: root.refCount > 0
repeat: true
triggeredOnStart: true
onTriggered: root.updateAllStats()
}
Connections {
target: IdleService
function onIdleChanged(idle) {
if (idle) {
console.log("SysMonitorService: System idle, pausing monitoring")
} else {
console.log("SysMonitorService: System active, resuming monitoring")
if (root.refCount > 0) {
root.updateAllStats()
}
}
}
}
readonly property string scriptBody: `set -Eeuo pipefail
trap 'echo "ERR at line $LINENO: $BASH_COMMAND (exit $?)" >&2' ERR
@@ -410,28 +425,53 @@ printf '"memory":{"total":%d,"free":%d,"available":%d,"buffers":%d,"cached":%d,"
# Get pss per pid
get_pss_kb() {
local pid="$1"
if [ -r "/proc/$pid/smaps_rollup" ]; then
awk '/^Pss:/{print $2; exit}' "/proc/$pid/smaps_rollup"
elif [ -r "/proc/$pid/smaps" ]; then
awk '/^Pss:/{t+=$2} END{print t+0}' "/proc/$pid/smaps"
else
echo 0
# Read PSS with zero external processes.
# 1) Prefer smaps_rollup (fast, single file)
# 2) Fallback to summing PSS in smaps
# Return 0 if unavailable.
local pid="$1" f total v k _
f="/proc/$pid/smaps_rollup"
if [ -r "$f" ]; then
# smaps_rollup has one Pss: line read it directly
while read -r k v _; do
if [ "$k" = "Pss:" ]; then
printf '%s\n' "\${v:-0}"
return
fi
done < "$f"
printf '0\n'
return
fi
f="/proc/$pid/smaps"
if [ -r "$f" ]; then
total=0
while read -r k v _; do
[ "$k" = "Pss:" ] && total=$(( total + (v:-0) ))
done < "$f"
printf '%s\n' "$total"
return
fi
printf '0\n'
}
cpu_count=$(nproc)
cpu_model=$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//' | json_escape || echo 'Unknown')
cpu_freq=$(awk -F: '/cpu MHz/{gsub(/ /,"",$2);print $2;exit}' /proc/cpuinfo || echo 0)
cpu_temp=$(if [ -r /sys/class/thermal/thermal_zone0/temp ]; then
awk '{printf "%.1f",$1/1000}' /sys/class/thermal/thermal_zone0/temp 2>/dev/null || echo 0
else echo 0; fi)
cpu_temp=$(grep -l 'coretemp\\|k10temp\\|k8temp\\|cpu_thermal\\|soc_thermal' /sys/class/hwmon/hwmon*/name 2>/dev/null | sed 's/name$/temp1_input/' | xargs cat 2>/dev/null | awk '{print $1/1000}' | head -1 || echo 0)
printf '"cpu":{"count":%d,"model":"%s","frequency":%s,"temperature":%s,' \\
"$cpu_count" "$cpu_model" "$cpu_freq" "$cpu_temp"
printf '"total":'
awk 'NR==1 {printf "[%d,%d,%d,%d,%d,%d,%d,%d]", $2,$3,$4,$5,$6,$7,$8,$9; exit}' /proc/stat
awk 'NR==1 {
printf "[";
for(i=2; i<=NF; i++) {
if(i>2) printf ",";
printf "%d", $i;
}
printf "]";
exit
}' /proc/stat
printf ',"cores":['
cpu_cores=$(nproc)
@@ -492,23 +532,19 @@ pfirst=1
while IFS=' ' read -r pid ppid cpu pmem_rss rss_kib comm rest; do
[ -z "$pid" ] && continue
# Optionally skip kernel threads / empty RSS lines (uncomment to filter)
# [ "$rss_kib" -eq 0 ] && continue
# Per-process CPU ticks (utime+stime)
pticks=$(awk '{print $14+$15}' "/proc/$pid/stat" 2>/dev/null || echo 0)
pss_kib=$(get_pss_kb "$pid" 2>/dev/null || true)
# Force numeric default if empty or non-numeric
if [ "\${rss_kib:-0}" -eq 0 ]; then pss_kib=0; else pss_kib=$(get_pss_kb "$pid"); fi
case "$pss_kib" in (''|*[!0-9]*) pss_kib=0 ;; esac
# PSS-based percent (locale-safe)
pss_pct=$(LC_ALL=C awk -v p="$pss_kib" -v t="$MT" 'BEGIN{if(t>0) printf "%.2f", (100*p)/t; else printf "0.00"}')
# Build full command; escape both fields
cmd=$(printf "%s %s" "$comm" "\${rest:-}" | json_escape)
comm_esc=$(printf "%s" "$comm" | json_escape)
[ "$pfirst" -eq 1 ] || printf ","
printf '{"pid":%s,"ppid":%s,"cpu":%s,"memoryPercent":%s,"memoryKB":%s,"pssKB":%s,"pssPercent":%s,"command":"%s","fullCommand":"%s"}' \
"$pid" "$ppid" "$cpu" "$pss_pct" "$rss_kib" "$pss_kib" "$pss_pct" "$comm_esc" "$cmd"
[ $pfirst -eq 1 ] || printf ","
printf '{"pid":%s,"ppid":%s,"cpu":%s,"pticks":%s,"memoryPercent":%s,"memoryKB":%s,"pssKB":%s,"pssPercent":%s,"command":"%s","fullCommand":"%s"}' \
"$pid" "$ppid" "$cpu" "$pticks" "$pss_pct" "$rss_kib" "$pss_kib" "$pss_pct" "$comm_esc" "$cmd"
pfirst=0
done < "$tmp_ps"
rm -f "$tmp_ps"
@@ -526,8 +562,8 @@ distro=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"'
host_name=$(hostname | json_escape)
arch_name=$(uname -m)
load_avg=$(cut -d' ' -f1-3 /proc/loadavg)
proc_count=$(( $(ps aux | wc -l) - 1 ))
thread_count=$(ps -eL | wc -l)
proc_count=$(ls -Ud /proc/[0-9]* 2>/dev/null | wc -l)
thread_count=$(ls -Ud /proc/[0-9]*/task/[0-9]* 2>/dev/null | wc -l)
boot_time=$(who -b 2>/dev/null | awk '{print $3, $4}' | json_escape || echo 'Unknown')
printf '"system":{"kernel":"%s","distro":"%s","hostname":"%s","arch":"%s","loadavg":"%s","processes":%d,"threads":%d,"boottime":"%s","motherboard":"%s %s","bios":"%s %s"},' \\
@@ -552,6 +588,78 @@ while IFS= read -r line; do
mfirst=0
done < "$tmp_mounts"
rm -f "$tmp_mounts"
printf ']',
printf '"gpus":['
gfirst=1
tmp_gpu=$(mktemp)
# Gather cards via DRM (much cheaper than lspci each tick)
for card in /sys/class/drm/card*; do
[ -e "$card/device/driver" ] || continue
drv=$(basename "$(readlink -f "$card/device/driver")") # e.g. nvidia, amdgpu, i915
drv=\${drv##*/}
# Determine PCI secondary bus to help identify integrated vs discrete
pci_path=$(readlink -f "$card/device") # .../0000:01:00.0
func=\${pci_path##*/} # 0000:01:00.0
sec=\${func#*:}; sec=\${sec%%:*} # "01" from 0000:01:00.0
# Priority: higher = more likely dedicated
prio=0
case "$drv" in
nvidia) prio=3 ;; # dGPU
amdgpu|radeon)
if [ "$sec" = "00" ]; then prio=1; else prio=2; fi # APU often on bus 00
;;
i915) prio=0 ;; # iGPU
*) prio=0 ;;
esac
# Temperature via per-device hwmon if available
hw=""; temp="0"
for h in "$card/device"/hwmon/hwmon*; do
[ -e "$h/temp1_input" ] || continue
hw=$(basename "$h")
temp=$(awk '{printf "%.1f",$1/1000}' "$h/temp1_input" 2>/dev/null || echo "0")
break
done
# NVIDIA fallback: use nvidia-smi (first GPU) if temp still 0
if [ "$drv" = "nvidia" ] && 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)
[ -n "$t" ] && { temp="$t"; hw="\${hw:-nvidia}"; }
fi
printf '%s|%s|%s|%s\n' "$prio" "$drv" "\${hw:-unknown}" "\${temp:-0}" >> "$tmp_gpu"
done
# Fallback if no DRM cards found (keep drivers but still sort)
if [ ! -s "$tmp_gpu" ]; then
for drv in nvidia amdgpu radeon i915; do
command -v "$drv" >/dev/null 2>&1 || true
prio=0; [ "$drv" = "nvidia" ] && prio=3
[ "$drv" = "amdgpu" ] && prio=2
[ "$drv" = "radeon" ] && prio=2
[ "$drv" = "i915" ] && prio=0
temp="0"; hw="$drv"
if [ "$drv" = "nvidia" ] && 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)
[ -n "$t" ] && temp="$t"
fi
printf '%s|%s|%s|%s\n' "$prio" "$drv" "$hw" "$temp" >> "$tmp_gpu"
done
fi
# Sort by priority (desc), then driver name for stability, and emit SAME JSON shape
while IFS='|' read -r pr drv hw temp; do
[ $gfirst -eq 1 ] || printf ","
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "$hw" "$temp"
gfirst=0
done < <(sort -t'|' -k1,1nr -k2,2 "$tmp_gpu")
rm -f "$tmp_gpu"
printf ']'
printf "}\\n"`
@@ -559,9 +667,9 @@ printf "}\\n"`
Process {
id: unifiedStatsProcess
command: [
"bash", "-c",
"bash -s \"$1\" \"$2\" <<'QS_EOF'\\n" + root.scriptBody + "\\nQS_EOF\\n",
"qsmon", root.sortBy, root.maxProcesses
"bash", "-c",
"bash -s \"$1\" \"$2\" <<'QS_EOF'\n" + root.scriptBody + "\nQS_EOF\n",
root.sortBy, String(root.maxProcesses)
]
running: false
onExited: (exitCode) => {
@@ -594,17 +702,5 @@ printf "}\\n"`
}
}
Process {
id: cpuTempProcess
command: ["bash", "-c", "grep -l 'coretemp\\|k10temp\\|k8temp\\|cpu_thermal\\|soc_thermal' /sys/class/hwmon/hwmon*/name | sed 's/name$/temp1_input/' | xargs cat | awk '{print $1/1000}'"]
running: false
stdout: StdioCollector {
onStreamFinished: {
const temp = parseFloat(text.trim());
if (!isNaN(temp)) {
cpuTemperature = temp;
}
}
}
}
}

View File

@@ -246,7 +246,7 @@ Singleton {
Timer {
id: updateTimer
interval: root.updateInterval
running: root.refCount > 0 && !IdleService.isIdle && SettingsData.weatherEnabled
running: root.refCount > 0 && SettingsData.weatherEnabled
repeat: true
triggeredOnStart: true
onTriggered: {
@@ -254,21 +254,6 @@ Singleton {
}
}
Connections {
target: IdleService
function onIdleChanged(idle) {
if (idle) {
console.log("WeatherService: System idle, pausing weather updates")
} else {
console.log("WeatherService: System active, resuming weather updates")
if (root.refCount > 0 && !root.weather.available && SettingsData.weatherEnabled) {
// Trigger immediate update when coming back from idle if no data and weather enabled
root.fetchWeather()
}
}
}
}
Timer {
id: retryTimer
interval: root.retryDelay

View File

@@ -22,7 +22,7 @@ Rectangle {
width: parent.width
height: 60
radius: Theme.cornerRadius
color: Theme.surfaceHover
color: "transparent"
Component.onCompleted: {
forceRecreateTimer.start();
}
@@ -272,6 +272,8 @@ Rectangle {
DankListView {
id: listView
property var popupRef: dropdownMenu
width: parent.width
height: parent.height - (root.enableFuzzySearch ? searchContainer.height + Theme.spacingXS : 0)
clip: true
@@ -339,7 +341,7 @@ Rectangle {
onClicked: {
root.currentValue = modelData;
root.valueChanged(modelData);
close();
dropdownMenu.close();
}
}

View File

@@ -5,7 +5,7 @@ import qs.Common
Flickable {
id: flickable
property real mouseWheelSpeed: 12
property real mouseWheelSpeed: 60
property real momentumVelocity: 0
property bool isMomentumActive: false
property real friction: 0.95

View File

@@ -22,7 +22,7 @@ GridView {
id: wheelHandler
// Tunable parameters for responsive scrolling
property real mouseWheelSpeed: 20
property real mouseWheelSpeed: 60
// Higher = faster mouse wheel
property real touchpadSpeed: 1.8
// Touchpad sensitivity

View File

@@ -4,7 +4,7 @@ import QtQuick.Controls
ListView {
id: listView
property real mouseWheelSpeed: 12
property real mouseWheelSpeed: 60
// Simple position preservation
property real savedY: 0