mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
re-work nightmode setting to use gammastep
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Common
|
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Common
|
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ Singleton {
|
|||||||
property string wallpaperLastPath: ""
|
property string wallpaperLastPath: ""
|
||||||
property string profileLastPath: ""
|
property string profileLastPath: ""
|
||||||
property bool doNotDisturb: false
|
property bool doNotDisturb: false
|
||||||
|
property bool nightModeEnabled: false
|
||||||
|
property int nightModeTemperature: 4500
|
||||||
property var pinnedApps: []
|
property var pinnedApps: []
|
||||||
property int selectedGpuIndex: 0
|
property int selectedGpuIndex: 0
|
||||||
property bool nvidiaGpuTempEnabled: false
|
property bool nvidiaGpuTempEnabled: false
|
||||||
@@ -45,6 +47,8 @@ Singleton {
|
|||||||
!== undefined ? settings.wallpaperLastPath : ""
|
!== undefined ? settings.wallpaperLastPath : ""
|
||||||
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
|
||||||
|
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
|
||||||
|
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500
|
||||||
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : []
|
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : []
|
||||||
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
|
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0
|
||||||
nvidiaGpuTempEnabled = settings.nvidiaGpuTempEnabled !== undefined ? settings.nvidiaGpuTempEnabled : false
|
nvidiaGpuTempEnabled = settings.nvidiaGpuTempEnabled !== undefined ? settings.nvidiaGpuTempEnabled : false
|
||||||
@@ -67,6 +71,8 @@ Singleton {
|
|||||||
"wallpaperLastPath": wallpaperLastPath,
|
"wallpaperLastPath": wallpaperLastPath,
|
||||||
"profileLastPath": profileLastPath,
|
"profileLastPath": profileLastPath,
|
||||||
"doNotDisturb": doNotDisturb,
|
"doNotDisturb": doNotDisturb,
|
||||||
|
"nightModeEnabled": nightModeEnabled,
|
||||||
|
"nightModeTemperature": nightModeTemperature,
|
||||||
"pinnedApps": pinnedApps,
|
"pinnedApps": pinnedApps,
|
||||||
"selectedGpuIndex": selectedGpuIndex,
|
"selectedGpuIndex": selectedGpuIndex,
|
||||||
"nvidiaGpuTempEnabled": nvidiaGpuTempEnabled,
|
"nvidiaGpuTempEnabled": nvidiaGpuTempEnabled,
|
||||||
@@ -89,6 +95,16 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setNightModeEnabled(enabled) {
|
||||||
|
nightModeEnabled = enabled
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNightModeTemperature(temperature) {
|
||||||
|
nightModeTemperature = temperature
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
function setWallpaperPath(path) {
|
function setWallpaperPath(path) {
|
||||||
wallpaperPath = path
|
wallpaperPath = path
|
||||||
saveSettings()
|
saveSettings()
|
||||||
|
|||||||
@@ -39,28 +39,6 @@ Item {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
|
||||||
id: nightModeEnableProcess
|
|
||||||
|
|
||||||
command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"]
|
|
||||||
running: false
|
|
||||||
onExited: (exitCode) => {
|
|
||||||
if (exitCode !== 0)
|
|
||||||
SettingsData.setNightModeEnabled(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: nightModeDisableProcess
|
|
||||||
|
|
||||||
command: ["bash", "-c", "pkill wlsunset; pkill redshift; if command -v wlsunset > /dev/null; then wlsunset -t 6500 -T 6500 & sleep 1; pkill wlsunset; elif command -v redshift > /dev/null; then redshift -P -O 6500; redshift -x; fi"]
|
|
||||||
running: false
|
|
||||||
onExited: (exitCode) => {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: brightnessComponent
|
id: brightnessComponent
|
||||||
@@ -155,25 +133,25 @@ Item {
|
|||||||
width: (parent.width - Theme.spacingM) / 2
|
width: (parent.width - Theme.spacingM) / 2
|
||||||
height: 80
|
height: 80
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: SettingsData.nightModeEnabled ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : (nightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
color: BrightnessService.nightModeActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : (nightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||||
border.color: SettingsData.nightModeEnabled ? Theme.primary : "transparent"
|
border.color: BrightnessService.nightModeActive ? Theme.primary : "transparent"
|
||||||
border.width: SettingsData.nightModeEnabled ? 1 : 0
|
border.width: BrightnessService.nightModeActive ? 1 : 0
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: SettingsData.nightModeEnabled ? "nightlight" : "dark_mode"
|
name: BrightnessService.nightModeActive ? "nightlight" : "dark_mode"
|
||||||
size: Theme.iconSizeLarge
|
size: Theme.iconSizeLarge
|
||||||
color: SettingsData.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
color: BrightnessService.nightModeActive ? Theme.primary : Theme.surfaceText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Night Mode"
|
text: "Night Mode"
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: SettingsData.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
color: BrightnessService.nightModeActive ? Theme.primary : Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -187,13 +165,7 @@ Item {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (SettingsData.nightModeEnabled) {
|
BrightnessService.toggleNightMode();
|
||||||
nightModeDisableProcess.running = true;
|
|
||||||
SettingsData.setNightModeEnabled(false);
|
|
||||||
} else {
|
|
||||||
nightModeEnableProcess.running = true;
|
|
||||||
SettingsData.setNightModeEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,15 @@ Column {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
width: 60
|
width: 60
|
||||||
height: 20
|
height: 20
|
||||||
color: processHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
color: {
|
||||||
Theme.surfaceText.g,
|
if (DgopService.currentSort === "name") {
|
||||||
Theme.surfaceText.b,
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||||
0.08) : "transparent"
|
}
|
||||||
|
return processHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
||||||
|
Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b,
|
||||||
|
0.08) : "transparent"
|
||||||
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 0
|
anchors.leftMargin: 0
|
||||||
@@ -39,9 +44,9 @@ Column {
|
|||||||
text: "Process"
|
text: "Process"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: DgopService.sortBy === "name" ? Font.Bold : Font.Medium
|
font.weight: DgopService.currentSort === "name" ? Font.Bold : Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: DgopService.sortBy === "name" ? 1 : 0.7
|
opacity: DgopService.currentSort === "name" ? 1 : 0.7
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,10 +71,15 @@ Column {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
width: 80
|
width: 80
|
||||||
height: 20
|
height: 20
|
||||||
color: cpuHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
color: {
|
||||||
Theme.surfaceText.g,
|
if (DgopService.currentSort === "cpu") {
|
||||||
Theme.surfaceText.b,
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||||
0.08) : "transparent"
|
}
|
||||||
|
return cpuHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
||||||
|
Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b,
|
||||||
|
0.08) : "transparent"
|
||||||
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 200
|
anchors.rightMargin: 200
|
||||||
@@ -79,9 +89,9 @@ Column {
|
|||||||
text: "CPU"
|
text: "CPU"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: DgopService.sortBy === "cpu" ? Font.Bold : Font.Medium
|
font.weight: DgopService.currentSort === "cpu" ? Font.Bold : Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: DgopService.sortBy === "cpu" ? 1 : 0.7
|
opacity: DgopService.currentSort === "cpu" ? 1 : 0.7
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +116,15 @@ Column {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
width: 80
|
width: 80
|
||||||
height: 20
|
height: 20
|
||||||
color: memoryHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
color: {
|
||||||
Theme.surfaceText.g,
|
if (DgopService.currentSort === "memory") {
|
||||||
Theme.surfaceText.b,
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||||
0.08) : "transparent"
|
}
|
||||||
|
return memoryHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
||||||
|
Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b,
|
||||||
|
0.08) : "transparent"
|
||||||
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 112
|
anchors.rightMargin: 112
|
||||||
@@ -119,9 +134,9 @@ Column {
|
|||||||
text: "RAM"
|
text: "RAM"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: DgopService.sortBy === "memory" ? Font.Bold : Font.Medium
|
font.weight: DgopService.currentSort === "memory" ? Font.Bold : Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: DgopService.sortBy === "memory" ? 1 : 0.7
|
opacity: DgopService.currentSort === "memory" ? 1 : 0.7
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,10 +161,15 @@ Column {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
width: 50
|
width: 50
|
||||||
height: 20
|
height: 20
|
||||||
color: pidHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
color: {
|
||||||
Theme.surfaceText.g,
|
if (DgopService.currentSort === "pid") {
|
||||||
Theme.surfaceText.b,
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||||
0.08) : "transparent"
|
}
|
||||||
|
return pidHeaderArea.containsMouse ? Qt.rgba(Theme.surfaceText.r,
|
||||||
|
Theme.surfaceText.g,
|
||||||
|
Theme.surfaceText.b,
|
||||||
|
0.08) : "transparent"
|
||||||
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 53
|
anchors.rightMargin: 53
|
||||||
@@ -159,9 +179,9 @@ Column {
|
|||||||
text: "PID"
|
text: "PID"
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
font.family: SettingsData.monoFontFamily
|
font.family: SettingsData.monoFontFamily
|
||||||
font.weight: DgopService.sortBy === "pid" ? Font.Bold : Font.Medium
|
font.weight: DgopService.currentSort === "pid" ? Font.Bold : Font.Medium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: DgopService.sortBy === "pid" ? 1 : 0.7
|
opacity: DgopService.currentSort === "pid" ? 1 : 0.7
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,17 +60,46 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankToggle {
|
DankToggle {
|
||||||
|
id: nightModeToggle
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: "Night Mode"
|
text: "Night Mode"
|
||||||
description: "Apply warm color temperature to reduce eye strain"
|
description: "Apply warm color temperature to reduce eye strain"
|
||||||
checked: SettingsData.nightModeEnabled
|
checked: BrightnessService.nightModeActive
|
||||||
onToggled: checked => {
|
onToggled: checked => {
|
||||||
SettingsData.setNightModeEnabled(checked)
|
if (checked !== BrightnessService.nightModeActive) {
|
||||||
if (checked)
|
if (checked)
|
||||||
nightModeEnableProcess.running = true
|
BrightnessService.enableNightMode()
|
||||||
else
|
else
|
||||||
nightModeDisableProcess.running = true
|
BrightnessService.disableNightMode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: BrightnessService
|
||||||
|
function onNightModeActiveChanged() {
|
||||||
|
nightModeToggle.checked = BrightnessService.nightModeActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankDropdown {
|
||||||
|
width: parent.width
|
||||||
|
text: "Night Mode Temperature"
|
||||||
|
description: BrightnessService.nightModeActive ? "Disable night mode to adjust" : "Set temperature for night mode"
|
||||||
|
enabled: !BrightnessService.nightModeActive
|
||||||
|
opacity: !BrightnessService.nightModeActive ? 1.0 : 0.6
|
||||||
|
currentValue: SessionData.nightModeTemperature + "K"
|
||||||
|
options: {
|
||||||
|
var temps = [];
|
||||||
|
for (var i = 2500; i <= 6000; i += 500) {
|
||||||
|
temps.push(i + "K");
|
||||||
|
}
|
||||||
|
return temps;
|
||||||
|
}
|
||||||
|
onValueChanged: value => {
|
||||||
|
var temp = parseInt(value.replace("K", ""));
|
||||||
|
SessionData.setNightModeTemperature(temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankToggle {
|
DankToggle {
|
||||||
@@ -904,25 +933,4 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: nightModeEnableProcess
|
|
||||||
|
|
||||||
command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"]
|
|
||||||
running: false
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode !== 0)
|
|
||||||
SettingsData.setNightModeEnabled(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: nightModeDisableProcess
|
|
||||||
|
|
||||||
command: ["bash", "-c", "pkill wlsunset; pkill redshift; if command -v wlsunset > /dev/null; then wlsunset -t 6500 -T 6500 & sleep 1; pkill wlsunset; elif command -v redshift > /dev/null; then redshift -P -O 6500; redshift -x; fi"]
|
|
||||||
running: false
|
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode !== 0)
|
|
||||||
SettingsData.setNightModeEnabled(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ make && sudo make install
|
|||||||
```bash
|
```bash
|
||||||
# Arch Linux
|
# Arch Linux
|
||||||
pacman -S cava wl-clipboard cliphist brightnessctl
|
pacman -S cava wl-clipboard cliphist brightnessctl
|
||||||
paru -S matugen dgop-git
|
paru -S matugen dgop
|
||||||
|
|
||||||
# Fedora
|
# Fedora
|
||||||
sudo dnf install cava wl-clipboard brightnessctl
|
sudo dnf install cava wl-clipboard brightnessctl
|
||||||
@@ -175,12 +175,13 @@ sudo dnf copr enable heus-sueh/packages && sudo dnf install matugen
|
|||||||
|
|
||||||
**What you get:**
|
**What you get:**
|
||||||
|
|
||||||
- `dgop-git`: Ability to have system resource widgets, process list modal, and temperature monitoring.
|
- `dgop`: Ability to have system resource widgets, process list modal, and temperature monitoring.
|
||||||
- `matugen`: Wallpaper-based dynamic theming
|
- `matugen`: Wallpaper-based dynamic theming
|
||||||
- `brightnessctl`: Backlight and LED brightness control
|
- `brightnessctl`: Backlight and LED brightness control
|
||||||
- `wl-clipboard`: Required for copying various elements to clipboard.
|
- `wl-clipboard`: Required for copying various elements to clipboard.
|
||||||
- `cava`: Audio visualizer
|
- `cava`: Audio visualizer
|
||||||
- `cliphist`: Clipboard history
|
- `cliphist`: Clipboard history
|
||||||
|
- `gammastep`: Night mode support
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import qs.Common
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior
|
pragma ComponentBehavior
|
||||||
|
|
||||||
@@ -21,6 +22,12 @@ Singleton {
|
|||||||
|
|
||||||
signal brightnessChanged()
|
signal brightnessChanged()
|
||||||
signal deviceSwitched()
|
signal deviceSwitched()
|
||||||
|
signal nightModeActiveChanged()
|
||||||
|
|
||||||
|
property bool nightModeActive: false
|
||||||
|
onNightModeActiveChanged: {
|
||||||
|
// Emit signal when property changes for UI reactivity
|
||||||
|
}
|
||||||
|
|
||||||
function setBrightnessInternal(percentage, device) {
|
function setBrightnessInternal(percentage, device) {
|
||||||
const clampedValue = Math.max(1, Math.min(100, percentage));
|
const clampedValue = Math.max(1, Math.min(100, percentage));
|
||||||
@@ -86,9 +93,52 @@ Singleton {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enableNightMode() {
|
||||||
|
if (nightModeActive) return;
|
||||||
|
|
||||||
|
nightModeActive = true;
|
||||||
|
SessionData.setNightModeEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateNightModeTemperature(temperature) {
|
||||||
|
SessionData.setNightModeTemperature(temperature);
|
||||||
|
|
||||||
|
// If night mode is active, restart it with new temperature
|
||||||
|
if (nightModeActive) {
|
||||||
|
// Temporarily disable and re-enable to restart with new temp
|
||||||
|
nightModeActive = false;
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (SessionData.nightModeEnabled) {
|
||||||
|
nightModeActive = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableNightMode() {
|
||||||
|
nightModeActive = false;
|
||||||
|
SessionData.setNightModeEnabled(false);
|
||||||
|
|
||||||
|
// Also kill any stray gammastep processes
|
||||||
|
Quickshell.execDetached(["pkill", "gammastep"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleNightMode() {
|
||||||
|
if (nightModeActive) {
|
||||||
|
disableNightMode();
|
||||||
|
} else {
|
||||||
|
enableNightMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
refreshDevices();
|
refreshDevices();
|
||||||
|
|
||||||
|
// Check if night mode was enabled on startup
|
||||||
|
if (SessionData.nightModeEnabled) {
|
||||||
|
enableNightMode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
@@ -189,6 +239,26 @@ Singleton {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: gammaStepProcess
|
||||||
|
|
||||||
|
command: {
|
||||||
|
const temperature = SessionData.nightModeTemperature || 4500;
|
||||||
|
return ["gammastep", "-m", "wayland", "-O", String(temperature)];
|
||||||
|
}
|
||||||
|
running: nightModeActive
|
||||||
|
|
||||||
|
onExited: function(exitCode) {
|
||||||
|
// Only show error if we're still supposed to be active (not manually disabled)
|
||||||
|
if (exitCode !== 0 && nightModeActive) {
|
||||||
|
console.warn("BrightnessService: Failed to enable night mode (gammastep not found or error)");
|
||||||
|
nightModeActive = false;
|
||||||
|
SessionData.setNightModeEnabled(false);
|
||||||
|
ToastService.showWarning("Night mode failed: gammastep not found or error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IPC Handler for external control
|
// IPC Handler for external control
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function set(percentage: string, device: string) : string {
|
function set(percentage: string, device: string) : string {
|
||||||
@@ -269,5 +339,64 @@ Singleton {
|
|||||||
|
|
||||||
target: "brightness"
|
target: "brightness"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IPC Handler for night mode control
|
||||||
|
IpcHandler {
|
||||||
|
function toggle() : string {
|
||||||
|
root.toggleNightMode();
|
||||||
|
return root.nightModeActive ? "Night mode enabled" : "Night mode disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable() : string {
|
||||||
|
root.enableNightMode();
|
||||||
|
return "Night mode enabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable() : string {
|
||||||
|
root.disableNightMode();
|
||||||
|
return "Night mode disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
function status() : string {
|
||||||
|
return root.nightModeActive ? "Night mode is enabled" : "Night mode is disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
function temperature(value: string) : string {
|
||||||
|
if (!value) {
|
||||||
|
return "Current temperature: " + SessionData.nightModeTemperature + "K";
|
||||||
|
}
|
||||||
|
|
||||||
|
const temp = parseInt(value);
|
||||||
|
if (isNaN(temp)) {
|
||||||
|
return "Invalid temperature. Use a value between 2500 and 6000 (in steps of 500)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate temperature is in valid range and steps
|
||||||
|
if (temp < 2500 || temp > 6000) {
|
||||||
|
return "Temperature must be between 2500K and 6000K";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round to nearest 500
|
||||||
|
const rounded = Math.round(temp / 500) * 500;
|
||||||
|
|
||||||
|
SessionData.setNightModeTemperature(rounded);
|
||||||
|
|
||||||
|
// If night mode is active, restart it with new temperature
|
||||||
|
if (root.nightModeActive) {
|
||||||
|
root.nightModeActive = false;
|
||||||
|
Qt.callLater(() => {
|
||||||
|
root.nightModeActive = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rounded !== temp) {
|
||||||
|
return "Night mode temperature set to " + rounded + "K (rounded from " + temp + "K)";
|
||||||
|
} else {
|
||||||
|
return "Night mode temperature set to " + rounded + "K";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "night"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ Singleton {
|
|||||||
property var diskDevices: []
|
property var diskDevices: []
|
||||||
|
|
||||||
property var processes: []
|
property var processes: []
|
||||||
|
property var allProcesses: []
|
||||||
|
property string currentSort: "cpu"
|
||||||
property var availableGpus: []
|
property var availableGpus: []
|
||||||
|
|
||||||
property string kernelVersion: ""
|
property string kernelVersion: ""
|
||||||
@@ -264,10 +266,8 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enabledModules.indexOf("processes") !== -1 || enabledModules.indexOf("all") !== -1) {
|
if (enabledModules.indexOf("processes") !== -1 || enabledModules.indexOf("all") !== -1) {
|
||||||
if (processLimit > 0) {
|
cmd.push("--limit", "100") // Get more data for client sorting
|
||||||
cmd.push("--limit", processLimit.toString())
|
cmd.push("--sort", "cpu") // Always get CPU sorted data
|
||||||
}
|
|
||||||
cmd.push("--sort", processSort)
|
|
||||||
if (noCpu) {
|
if (noCpu) {
|
||||||
cmd.push("--no-cpu")
|
cmd.push("--no-cpu")
|
||||||
}
|
}
|
||||||
@@ -388,7 +388,8 @@ Singleton {
|
|||||||
proc.command.substring(0, 15) + "..." : (proc.command || "")
|
proc.command.substring(0, 15) + "..." : (proc.command || "")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
processes = newProcesses
|
allProcesses = newProcesses
|
||||||
|
applySorting()
|
||||||
|
|
||||||
// Store the single opaque cursor string for the entire process list
|
// Store the single opaque cursor string for the entire process list
|
||||||
if (data.cursor) {
|
if (data.cursor) {
|
||||||
@@ -508,10 +509,43 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setSortBy(newSortBy) {
|
function setSortBy(newSortBy) {
|
||||||
if (newSortBy !== processSort) {
|
if (newSortBy !== currentSort) {
|
||||||
processSort = newSortBy
|
currentSort = newSortBy
|
||||||
|
applySorting()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applySorting() {
|
||||||
|
if (!allProcesses || allProcesses.length === 0) return
|
||||||
|
|
||||||
|
const sorted = allProcesses.slice()
|
||||||
|
sorted.sort((a, b) => {
|
||||||
|
let valueA, valueB
|
||||||
|
|
||||||
|
switch (currentSort) {
|
||||||
|
case "cpu":
|
||||||
|
valueA = a.cpu || 0
|
||||||
|
valueB = b.cpu || 0
|
||||||
|
return valueB - valueA
|
||||||
|
case "memory":
|
||||||
|
valueA = a.memoryKB || 0
|
||||||
|
valueB = b.memoryKB || 0
|
||||||
|
return valueB - valueA
|
||||||
|
case "name":
|
||||||
|
valueA = (a.command || "").toLowerCase()
|
||||||
|
valueB = (b.command || "").toLowerCase()
|
||||||
|
return valueA.localeCompare(valueB)
|
||||||
|
case "pid":
|
||||||
|
valueA = a.pid || 0
|
||||||
|
valueB = b.pid || 0
|
||||||
|
return valueA - valueB
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
processes = sorted.slice(0, processLimit)
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: updateTimer
|
id: updateTimer
|
||||||
|
|||||||
@@ -1,254 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Outputs dynamic system stats as JSON.
|
|
||||||
# Args:
|
|
||||||
# $1 sort_key (cpu|memory|name|pid)
|
|
||||||
# $2 max_procs
|
|
||||||
# $3 collect_gpu_temps (0/1)
|
|
||||||
# $4 collect_nvidia_only (0/1)
|
|
||||||
# $5 collect_non_nvidia (0/1)
|
|
||||||
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
sort_key=${1:-cpu}
|
|
||||||
max_procs=${2:-20}
|
|
||||||
collect_gpu_temps=${3:-0}
|
|
||||||
collect_nvidia_only=${4:-0}
|
|
||||||
collect_non_nvidia=${5:-1}
|
|
||||||
|
|
||||||
json_escape() { sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e ':a;N;$!ba;s/\n/\\n/g'; }
|
|
||||||
|
|
||||||
printf "{"
|
|
||||||
|
|
||||||
# ---- Memory block (exact fields/keys) ----
|
|
||||||
mem_line="$(awk '
|
|
||||||
/^MemTotal:/ {t=$2}
|
|
||||||
/^MemFree:/ {f=$2}
|
|
||||||
/^MemAvailable:/ {a=$2}
|
|
||||||
/^Buffers:/ {b=$2}
|
|
||||||
/^Cached:/ {c=$2}
|
|
||||||
/^Shmem:/ {s=$2}
|
|
||||||
/^SwapTotal:/ {st=$2}
|
|
||||||
/^SwapFree:/ {sf=$2}
|
|
||||||
END{printf "%d %d %d %d %d %d %d %d", t,f,a,b,c,s,st,sf}
|
|
||||||
' /proc/meminfo)"
|
|
||||||
read -r MT MF MA BU CA SH ST SF <<< "$mem_line"
|
|
||||||
|
|
||||||
printf '"memory":{"total":%d,"free":%d,"available":%d,"buffers":%d,"cached":%d,"shared":%d,"swaptotal":%d,"swapfree":%d},' \
|
|
||||||
"$MT" "$MF" "$MA" "$BU" "$CA" "$SH" "$ST" "$SF"
|
|
||||||
|
|
||||||
# ---- Helper: PSS in KiB ----
|
|
||||||
get_pss_kb() {
|
|
||||||
local pid="$1" k v rest total=0 f
|
|
||||||
f="/proc/$pid/smaps_rollup"
|
|
||||||
if [ -r "$f" ]; then
|
|
||||||
while read -r k v rest; 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
|
|
||||||
while read -r k v rest; do
|
|
||||||
if [ "$k" = "Pss:" ]; then
|
|
||||||
: "${v:=0}"
|
|
||||||
total=$(( total + v ))
|
|
||||||
fi
|
|
||||||
done < "$f"
|
|
||||||
printf '%s\n' "$total"; return
|
|
||||||
fi
|
|
||||||
printf '0\n'
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---- CPU (meta + temp) ----
|
|
||||||
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=0
|
|
||||||
for hwmon_dir in /sys/class/hwmon/hwmon*/; do
|
|
||||||
[ -d "$hwmon_dir" ] || continue
|
|
||||||
name_file="${hwmon_dir}name"
|
|
||||||
[ -r "$name_file" ] || continue
|
|
||||||
if grep -qE 'coretemp|k10temp|k8temp|cpu_thermal|soc_thermal' "$name_file" 2>/dev/null; then
|
|
||||||
for temp_file in "${hwmon_dir}"temp*_input; do
|
|
||||||
[ -r "$temp_file" ] || continue
|
|
||||||
cpu_temp=$(awk '{printf "%.1f", $1/1000}' "$temp_file" 2>/dev/null || echo 0)
|
|
||||||
break 2
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
printf '"cpu":{"count":%d,"model":"%s","frequency":%s,"temperature":%s,' \
|
|
||||||
"$cpu_count" "$cpu_model" "$cpu_freq" "$cpu_temp"
|
|
||||||
|
|
||||||
# cpu.total (first line of /proc/stat, fields 2..)
|
|
||||||
printf '"total":'
|
|
||||||
awk 'NR==1 {
|
|
||||||
printf "[";
|
|
||||||
for(i=2; i<=NF; i++) { if(i>2) printf ","; printf "%d", $i; }
|
|
||||||
printf "]";
|
|
||||||
exit
|
|
||||||
}' /proc/stat
|
|
||||||
|
|
||||||
# cpu.cores (each cpuN line, 8 columns)
|
|
||||||
printf ',"cores":['
|
|
||||||
cpu_cores=$(nproc)
|
|
||||||
awk -v n="$cpu_cores" 'BEGIN{c=0}
|
|
||||||
/^cpu[0-9]+/ {
|
|
||||||
if(c>0) printf ",";
|
|
||||||
printf "[%d,%d,%d,%d,%d,%d,%d,%d]", $2,$3,$4,$5,$6,$7,$8,$9;
|
|
||||||
c++;
|
|
||||||
if(c==n) exit
|
|
||||||
}' /proc/stat
|
|
||||||
printf ']},'
|
|
||||||
|
|
||||||
# ---- Network (rx/tx bytes per iface) ----
|
|
||||||
printf '"network":['
|
|
||||||
tmp_net=$(mktemp)
|
|
||||||
grep -E '(wlan|eth|enp|wlp|ens|eno)' /proc/net/dev > "$tmp_net" || true
|
|
||||||
nfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
iface=$(echo "$line" | awk '{print $1}' | sed 's/://')
|
|
||||||
rx_bytes=$(echo "$line" | awk '{print $2}')
|
|
||||||
tx_bytes=$(echo "$line" | awk '{print $10}')
|
|
||||||
[ $nfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"name":"%s","rx":%d,"tx":%d}' "$iface" "$rx_bytes" "$tx_bytes"
|
|
||||||
nfirst=0
|
|
||||||
done < "$tmp_net"
|
|
||||||
rm -f "$tmp_net"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- Disk (/proc/diskstats sectors; read/write) ----
|
|
||||||
printf '"disk":['
|
|
||||||
tmp_disk=$(mktemp)
|
|
||||||
grep -E ' (sd[a-z]+|nvme[0-9]+n[0-9]+|vd[a-z]+|dm-[0-9]+|mmcblk[0-9]+) ' /proc/diskstats > "$tmp_disk" || true
|
|
||||||
dfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
name=$(echo "$line" | awk '{print $3}')
|
|
||||||
read_sectors=$(echo "$line" | awk '{print $6}')
|
|
||||||
write_sectors=$(echo "$line" | awk '{print $10}')
|
|
||||||
[ $dfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"name":"%s","read":%d,"write":%d}' "$name" "$read_sectors" "$write_sectors"
|
|
||||||
dfirst=0
|
|
||||||
done < "$tmp_disk"
|
|
||||||
rm -f "$tmp_disk"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- Processes (shape & fields match your QML) ----
|
|
||||||
case "$sort_key" in
|
|
||||||
cpu) SORT_OPT="--sort=-pcpu" ;;
|
|
||||||
memory) SORT_OPT="--sort=-pmem" ;;
|
|
||||||
name) SORT_OPT="--sort=+comm" ;;
|
|
||||||
pid) SORT_OPT="--sort=+pid" ;;
|
|
||||||
*) SORT_OPT="--sort=-pcpu" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
printf '"processes":['
|
|
||||||
tmp_ps=$(mktemp)
|
|
||||||
ps -eo pid,ppid,pcpu,pmem,rss,comm,cmd --no-headers $SORT_OPT | head -n "$max_procs" > "$tmp_ps" || true
|
|
||||||
pfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
# split the first 6 columns, rest is full command tail
|
|
||||||
pid=$( awk '{print $1}' <<<"$line")
|
|
||||||
ppid=$( awk '{print $2}' <<<"$line")
|
|
||||||
cpu=$( awk '{print $3}' <<<"$line")
|
|
||||||
pmem=$( awk '{print $4}' <<<"$line")
|
|
||||||
rss_kib=$(awk '{print $5}' <<<"$line")
|
|
||||||
comm=$( awk '{print $6}' <<<"$line")
|
|
||||||
rest=$( printf '%s\n' "$line" | cut -d' ' -f7- )
|
|
||||||
|
|
||||||
# CPU ticks (utime+stime)
|
|
||||||
pticks=$(awk '{print $14+$15}' "/proc/$pid/stat" 2>/dev/null || echo 0)
|
|
||||||
|
|
||||||
# PSS in KiB and % of MemTotal
|
|
||||||
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_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"}')
|
|
||||||
|
|
||||||
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,"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"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- System (dynamic bits) ----
|
|
||||||
load_avg=$(cut -d' ' -f1-3 /proc/loadavg)
|
|
||||||
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":{"loadavg":"%s","processes":%d,"threads":%d,"boottime":"%s"},' \
|
|
||||||
"$load_avg" "$proc_count" "$thread_count" "$boot_time"
|
|
||||||
|
|
||||||
# ---- Mounts (same df -h shape/strings) ----
|
|
||||||
printf '"diskmounts":['
|
|
||||||
tmp_mounts=$(mktemp)
|
|
||||||
df -h --output=source,target,fstype,size,used,avail,pcent | tail -n +2 | grep -vE '^(tmpfs|devtmpfs)' > "$tmp_mounts" || true
|
|
||||||
mfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
device=$(echo "$line" | awk '{print $1}' | json_escape)
|
|
||||||
mount=$( echo "$line" | awk '{print $2}' | json_escape)
|
|
||||||
fstype=$(echo "$line" | awk '{print $3}')
|
|
||||||
size=$( echo "$line" | awk '{print $4}')
|
|
||||||
used=$( echo "$line" | awk '{print $5}')
|
|
||||||
avail=$( echo "$line" | awk '{print $6}')
|
|
||||||
percent=$(echo "$line" | awk '{print $7}')
|
|
||||||
[ $mfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"device":"%s","mount":"%s","fstype":"%s","size":"%s","used":"%s","avail":"%s","percent":"%s"}' \
|
|
||||||
"$device" "$mount" "$fstype" "$size" "$used" "$avail" "$percent"
|
|
||||||
mfirst=0
|
|
||||||
done < "$tmp_mounts"
|
|
||||||
rm -f "$tmp_mounts"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- GPU temps (optional) ----
|
|
||||||
printf '"gputemps":['
|
|
||||||
if [ "$collect_gpu_temps" = "1" ]; then
|
|
||||||
gfirst=1
|
|
||||||
for card in /sys/class/drm/card*; do
|
|
||||||
[ -e "$card/device/driver" ] || continue
|
|
||||||
drv=$(basename "$(readlink -f "$card/device/driver")"); drv=${drv##*/}
|
|
||||||
hw=""; temp="0"
|
|
||||||
|
|
||||||
if [ "$collect_non_nvidia" = "1" ]; then
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$drv" = "nvidia" ] && [ "$temp" = "0" ] && [ "$collect_nvidia_only" = "1" ] && 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
|
|
||||||
|
|
||||||
if [ "$temp" != "0" ]; then
|
|
||||||
[ $gfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "${hw:-unknown}" "${temp:-0}"
|
|
||||||
gfirst=0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Fallback: nvidia-smi only
|
|
||||||
if [ ${gfirst:-1} -eq 1 ] && [ "$collect_nvidia_only" = "1" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
|
||||||
temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
|
||||||
[ -n "$temp" ] && printf '{"driver":"nvidia","hwmon":"nvidia","temperature":%s}' "$temp"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
printf ']'
|
|
||||||
|
|
||||||
printf "}\n"
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Lightweight version of sysmon_dynamic.sh that skips expensive PSS calculations
|
|
||||||
# Args:
|
|
||||||
# $1 sort_key (cpu|memory|name|pid)
|
|
||||||
# $2 max_procs
|
|
||||||
# $3 collect_gpu_temps (0/1)
|
|
||||||
# $4 collect_nvidia_only (0/1)
|
|
||||||
# $5 collect_non_nvidia (0/1)
|
|
||||||
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
sort_key=${1:-cpu}
|
|
||||||
max_procs=${2:-20}
|
|
||||||
collect_gpu_temps=${3:-0}
|
|
||||||
collect_nvidia_only=${4:-0}
|
|
||||||
collect_non_nvidia=${5:-1}
|
|
||||||
|
|
||||||
json_escape() { sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e ':a;N;$!ba;s/\n/\\n/g'; }
|
|
||||||
|
|
||||||
printf "{"
|
|
||||||
|
|
||||||
# ---- Memory block (exact fields/keys) ----
|
|
||||||
mem_line="$(awk '
|
|
||||||
/^MemTotal:/ {t=$2}
|
|
||||||
/^MemFree:/ {f=$2}
|
|
||||||
/^MemAvailable:/ {a=$2}
|
|
||||||
/^Buffers:/ {b=$2}
|
|
||||||
/^Cached:/ {c=$2}
|
|
||||||
/^Shmem:/ {s=$2}
|
|
||||||
/^SwapTotal:/ {st=$2}
|
|
||||||
/^SwapFree:/ {sf=$2}
|
|
||||||
END{printf "%d %d %d %d %d %d %d %d", t,f,a,b,c,s,st,sf}
|
|
||||||
' /proc/meminfo)"
|
|
||||||
read -r MT MF MA BU CA SH ST SF <<< "$mem_line"
|
|
||||||
|
|
||||||
printf '"memory":{"total":%d,"free":%d,"available":%d,"buffers":%d,"cached":%d,"shared":%d,"swaptotal":%d,"swapfree":%d},' \
|
|
||||||
"$MT" "$MF" "$MA" "$BU" "$CA" "$SH" "$ST" "$SF"
|
|
||||||
|
|
||||||
# ---- CPU (meta + temp) ----
|
|
||||||
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=0
|
|
||||||
for hwmon_dir in /sys/class/hwmon/hwmon*/; do
|
|
||||||
[ -d "$hwmon_dir" ] || continue
|
|
||||||
name_file="${hwmon_dir}name"
|
|
||||||
[ -r "$name_file" ] || continue
|
|
||||||
if grep -qE 'coretemp|k10temp|k8temp|cpu_thermal|soc_thermal' "$name_file" 2>/dev/null; then
|
|
||||||
for temp_file in "${hwmon_dir}"temp*_input; do
|
|
||||||
[ -r "$temp_file" ] || continue
|
|
||||||
cpu_temp=$(awk '{printf "%.1f", $1/1000}' "$temp_file" 2>/dev/null || echo 0)
|
|
||||||
break 2
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
printf '"cpu":{"count":%d,"model":"%s","frequency":%s,"temperature":%s,' \
|
|
||||||
"$cpu_count" "$cpu_model" "$cpu_freq" "$cpu_temp"
|
|
||||||
|
|
||||||
# cpu.total (first line of /proc/stat, fields 2..)
|
|
||||||
printf '"total":'
|
|
||||||
awk 'NR==1 {
|
|
||||||
printf "[";
|
|
||||||
for(i=2; i<=NF; i++) { if(i>2) printf ","; printf "%d", $i; }
|
|
||||||
printf "]";
|
|
||||||
exit
|
|
||||||
}' /proc/stat
|
|
||||||
|
|
||||||
# cpu.cores (each cpuN line, 8 columns)
|
|
||||||
printf ',"cores":['
|
|
||||||
cpu_cores=$(nproc)
|
|
||||||
awk -v n="$cpu_cores" 'BEGIN{c=0}
|
|
||||||
/^cpu[0-9]+/ {
|
|
||||||
if(c>0) printf ",";
|
|
||||||
printf "[%d,%d,%d,%d,%d,%d,%d,%d]", $2,$3,$4,$5,$6,$7,$8,$9;
|
|
||||||
c++;
|
|
||||||
if(c==n) exit
|
|
||||||
}' /proc/stat
|
|
||||||
printf ']},'
|
|
||||||
|
|
||||||
# ---- Network (rx/tx bytes per iface) ----
|
|
||||||
printf '"network":['
|
|
||||||
tmp_net=$(mktemp)
|
|
||||||
grep -E '(wlan|eth|enp|wlp|ens|eno)' /proc/net/dev > "$tmp_net" || true
|
|
||||||
nfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
iface=$(echo "$line" | awk '{print $1}' | sed 's/://')
|
|
||||||
rx_bytes=$(echo "$line" | awk '{print $2}')
|
|
||||||
tx_bytes=$(echo "$line" | awk '{print $10}')
|
|
||||||
[ $nfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"name":"%s","rx":%d,"tx":%d}' "$iface" "$rx_bytes" "$tx_bytes"
|
|
||||||
nfirst=0
|
|
||||||
done < "$tmp_net"
|
|
||||||
rm -f "$tmp_net"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- Disk (/proc/diskstats sectors; read/write) ----
|
|
||||||
printf '"disk":['
|
|
||||||
tmp_disk=$(mktemp)
|
|
||||||
grep -E ' (sd[a-z]+|nvme[0-9]+n[0-9]+|vd[a-z]+|dm-[0-9]+|mmcblk[0-9]+) ' /proc/diskstats > "$tmp_disk" || true
|
|
||||||
dfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
name=$(echo "$line" | awk '{print $3}')
|
|
||||||
read_sectors=$(echo "$line" | awk '{print $6}')
|
|
||||||
write_sectors=$(echo "$line" | awk '{print $10}')
|
|
||||||
[ $dfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"name":"%s","read":%d,"write":%d}' "$name" "$read_sectors" "$write_sectors"
|
|
||||||
dfirst=0
|
|
||||||
done < "$tmp_disk"
|
|
||||||
rm -f "$tmp_disk"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- Processes (SIMPLIFIED - no PSS, use RSS from ps directly) ----
|
|
||||||
case "$sort_key" in
|
|
||||||
cpu) SORT_OPT="--sort=-pcpu" ;;
|
|
||||||
memory) SORT_OPT="--sort=-pmem" ;;
|
|
||||||
name) SORT_OPT="--sort=+comm" ;;
|
|
||||||
pid) SORT_OPT="--sort=+pid" ;;
|
|
||||||
*) SORT_OPT="--sort=-pcpu" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
printf '"processes":['
|
|
||||||
tmp_ps=$(mktemp)
|
|
||||||
ps -eo pid,ppid,pcpu,pmem,rss,comm,cmd --no-headers $SORT_OPT | head -n "$max_procs" > "$tmp_ps" || true
|
|
||||||
pfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
pid=$( awk '{print $1}' <<<"$line")
|
|
||||||
ppid=$( awk '{print $2}' <<<"$line")
|
|
||||||
cpu=$( awk '{print $3}' <<<"$line")
|
|
||||||
pmem=$( awk '{print $4}' <<<"$line")
|
|
||||||
rss_kib=$(awk '{print $5}' <<<"$line")
|
|
||||||
comm=$( awk '{print $6}' <<<"$line")
|
|
||||||
rest=$( printf '%s\n' "$line" | cut -d' ' -f7- )
|
|
||||||
|
|
||||||
# CPU ticks (utime+stime)
|
|
||||||
pticks=$(awk '{print $14+$15}' "/proc/$pid/stat" 2>/dev/null || echo 0)
|
|
||||||
|
|
||||||
# Use RSS-based memory percentage (skip expensive PSS calculation)
|
|
||||||
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,"pticks":%s,"memoryPercent":%s,"memoryKB":%s,"pssKB":%s,"pssPercent":%s,"command":"%s","fullCommand":"%s"}' \
|
|
||||||
"$pid" "$ppid" "$cpu" "$pticks" "$pmem" "$rss_kib" "$rss_kib" "$pmem" "$comm_esc" "$cmd"
|
|
||||||
pfirst=0
|
|
||||||
done < "$tmp_ps"
|
|
||||||
rm -f "$tmp_ps"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- System (dynamic bits) ----
|
|
||||||
load_avg=$(cut -d' ' -f1-3 /proc/loadavg)
|
|
||||||
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":{"loadavg":"%s","processes":%d,"threads":%d,"boottime":"%s"},' \
|
|
||||||
"$load_avg" "$proc_count" "$thread_count" "$boot_time"
|
|
||||||
|
|
||||||
# ---- Mounts (same df -h shape/strings) ----
|
|
||||||
printf '"diskmounts":['
|
|
||||||
tmp_mounts=$(mktemp)
|
|
||||||
df -h --output=source,target,fstype,size,used,avail,pcent | tail -n +2 | grep -vE '^(tmpfs|devtmpfs)' > "$tmp_mounts" || true
|
|
||||||
mfirst=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
[ -z "$line" ] && continue
|
|
||||||
device=$(echo "$line" | awk '{print $1}' | json_escape)
|
|
||||||
mount=$( echo "$line" | awk '{print $2}' | json_escape)
|
|
||||||
fstype=$(echo "$line" | awk '{print $3}')
|
|
||||||
size=$( echo "$line" | awk '{print $4}')
|
|
||||||
used=$( echo "$line" | awk '{print $5}')
|
|
||||||
avail=$( echo "$line" | awk '{print $6}')
|
|
||||||
percent=$(echo "$line" | awk '{print $7}')
|
|
||||||
[ $mfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"device":"%s","mount":"%s","fstype":"%s","size":"%s","used":"%s","avail":"%s","percent":"%s"}' \
|
|
||||||
"$device" "$mount" "$fstype" "$size" "$used" "$avail" "$percent"
|
|
||||||
mfirst=0
|
|
||||||
done < "$tmp_mounts"
|
|
||||||
rm -f "$tmp_mounts"
|
|
||||||
printf '],'
|
|
||||||
|
|
||||||
# ---- GPU temps (optional) ----
|
|
||||||
printf '"gputemps":['
|
|
||||||
if [ "$collect_gpu_temps" = "1" ]; then
|
|
||||||
gfirst=1
|
|
||||||
for card in /sys/class/drm/card*; do
|
|
||||||
[ -e "$card/device/driver" ] || continue
|
|
||||||
drv=$(basename "$(readlink -f "$card/device/driver")"); drv=${drv##*/}
|
|
||||||
hw=""; temp="0"
|
|
||||||
|
|
||||||
if [ "$collect_non_nvidia" = "1" ]; then
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$drv" = "nvidia" ] && [ "$temp" = "0" ] && [ "$collect_nvidia_only" = "1" ] && 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
|
|
||||||
|
|
||||||
if [ "$temp" != "0" ]; then
|
|
||||||
[ $gfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"driver":"%s","hwmon":"%s","temperature":%s}' "$drv" "${hw:-unknown}" "${temp:-0}"
|
|
||||||
gfirst=0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Fallback: nvidia-smi only
|
|
||||||
if [ ${gfirst:-1} -eq 1 ] && [ "$collect_nvidia_only" = "1" ] && command -v nvidia-smi >/dev/null 2>&1; then
|
|
||||||
temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null | head -1)
|
|
||||||
[ -n "$temp" ] && printf '{"driver":"nvidia","hwmon":"nvidia","temperature":%s}' "$temp"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
printf ']'
|
|
||||||
|
|
||||||
printf "}\n"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Outputs static system info + detected GPUs as JSON (no temps)
|
|
||||||
|
|
||||||
set -o pipefail
|
|
||||||
exec 2>/dev/null
|
|
||||||
|
|
||||||
json_escape() { sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e ':a;N;$!ba;s/\n/\\n/g'; }
|
|
||||||
|
|
||||||
printf "{"
|
|
||||||
|
|
||||||
cpu_count=$(nproc)
|
|
||||||
cpu_model=$(grep -m1 'model name' /proc/cpuinfo | cut -d: -f2- | sed 's/^ *//' | json_escape || echo 'Unknown')
|
|
||||||
printf '"cpu":{"count":%d,"model":"%s"},' "$cpu_count" "$cpu_model"
|
|
||||||
|
|
||||||
dmip="/sys/class/dmi/id"
|
|
||||||
[ -d "$dmip" ] || dmip="/sys/devices/virtual/dmi/id"
|
|
||||||
mb_vendor=$([ -r "$dmip/board_vendor" ] && cat "$dmip/board_vendor" | json_escape || echo "Unknown")
|
|
||||||
mb_name=$([ -r "$dmip/board_name" ] && cat "$dmip/board_name" | json_escape || echo "")
|
|
||||||
bios_ver=$([ -r "$dmip/bios_version" ] && cat "$dmip/bios_version" | json_escape || echo "Unknown")
|
|
||||||
bios_date=$([ -r "$dmip/bios_date" ] && cat "$dmip/bios_date" | json_escape || echo "")
|
|
||||||
|
|
||||||
kern_ver=$(uname -r | json_escape)
|
|
||||||
distro=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2- | tr -d '"' | json_escape || echo 'Unknown')
|
|
||||||
host_name=$(hostname | json_escape)
|
|
||||||
arch_name=$(uname -m)
|
|
||||||
|
|
||||||
printf '"system":{"kernel":"%s","distro":"%s","hostname":"%s","arch":"%s","motherboard":"%s %s","bios":"%s %s"},' \
|
|
||||||
"$kern_ver" "$distro" "$host_name" "$arch_name" "$mb_vendor" "$mb_name" "$bios_ver" "$bios_date"
|
|
||||||
|
|
||||||
printf '"gpus":['
|
|
||||||
gfirst=1
|
|
||||||
tmp_gpu=$(mktemp)
|
|
||||||
|
|
||||||
infer_vendor() {
|
|
||||||
case "$1" in
|
|
||||||
nvidia|nouveau) echo NVIDIA ;;
|
|
||||||
amdgpu|radeon) echo AMD ;;
|
|
||||||
i915|xe) echo Intel ;;
|
|
||||||
*) case "$2" in
|
|
||||||
*NVIDIA*|*Nvidia*|*nvidia*) echo NVIDIA ;;
|
|
||||||
*AMD*|*ATI*|*amd*|*ati*) echo AMD ;;
|
|
||||||
*Intel*|*intel*) echo Intel ;;
|
|
||||||
*) echo Unknown ;;
|
|
||||||
esac ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
prio_of() {
|
|
||||||
local drv="$1" bdf="$2"
|
|
||||||
case "$drv" in
|
|
||||||
nvidia) echo 3 ;;
|
|
||||||
amdgpu|radeon)
|
|
||||||
local dd="${bdf##*:}"; dd="${dd%%.*}"
|
|
||||||
[ "$dd" = "00" ] && echo 1 || echo 2
|
|
||||||
;;
|
|
||||||
i915|xe) echo 0 ;;
|
|
||||||
*) echo 0 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
LC_ALL=C lspci -nnD 2>/dev/null | grep -iE ' VGA| 3D| 2D| Display' | while IFS= read -r line; do
|
|
||||||
bdf="${line%% *}"
|
|
||||||
drv=""
|
|
||||||
[ -e "/sys/bus/pci/devices/$bdf/driver" ] && drv="$(basename "$(readlink -f "/sys/bus/pci/devices/$bdf/driver")")"
|
|
||||||
vendor="$(infer_vendor "$drv" "$line")"
|
|
||||||
raw_line="$(printf '%s' "$line" | json_escape)"
|
|
||||||
prio="$(prio_of "$drv" "$bdf")"
|
|
||||||
printf '%s|%s|%s|%s\n' "$prio" "$drv" "$vendor" "$raw_line" >> "$tmp_gpu"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -s "$tmp_gpu" ]; then
|
|
||||||
while IFS='|' read -r pr drv vendor raw_line; do
|
|
||||||
[ $gfirst -eq 1 ] || printf ","
|
|
||||||
printf '{"driver":"%s","vendor":"%s","rawLine":"%s"}' "$drv" "$vendor" "$raw_line"
|
|
||||||
gfirst=0
|
|
||||||
done < <(sort -t'|' -k1,1nr -k2,2 "$tmp_gpu")
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "$tmp_gpu"
|
|
||||||
printf ']'
|
|
||||||
printf "}\n"
|
|
||||||
Reference in New Issue
Block a user