mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 16:14:44 +00:00
feat: add screen refresh rate display in status view
This commit is contained in:
@@ -37,11 +37,12 @@ type MetricsSnapshot struct {
|
||||
}
|
||||
|
||||
type HardwareInfo struct {
|
||||
Model string // MacBook Pro 14-inch, 2021
|
||||
CPUModel string // Apple M1 Pro / Intel Core i7
|
||||
TotalRAM string // 16GB
|
||||
DiskSize string // 512GB
|
||||
OSVersion string // macOS Sonoma 14.5
|
||||
Model string // MacBook Pro 14-inch, 2021
|
||||
CPUModel string // Apple M1 Pro / Intel Core i7
|
||||
TotalRAM string // 16GB
|
||||
DiskSize string // 512GB
|
||||
OSVersion string // macOS Sonoma 14.5
|
||||
RefreshRate string // 120Hz / 60Hz
|
||||
}
|
||||
|
||||
type DiskIOStatus struct {
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -10,11 +11,12 @@ import (
|
||||
func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
||||
if runtime.GOOS != "darwin" {
|
||||
return HardwareInfo{
|
||||
Model: "Unknown",
|
||||
CPUModel: runtime.GOARCH,
|
||||
TotalRAM: humanBytes(totalRAM),
|
||||
DiskSize: "Unknown",
|
||||
OSVersion: runtime.GOOS,
|
||||
Model: "Unknown",
|
||||
CPUModel: runtime.GOARCH,
|
||||
TotalRAM: humanBytes(totalRAM),
|
||||
DiskSize: "Unknown",
|
||||
OSVersion: runtime.GOOS,
|
||||
RefreshRate: "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +24,7 @@ func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var model, cpuModel, osVersion string
|
||||
var model, cpuModel, osVersion, refreshRate string
|
||||
|
||||
out, err := runCmd(ctx, "system_profiler", "SPHardwareDataType")
|
||||
if err == nil {
|
||||
@@ -58,16 +60,79 @@ func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
||||
osVersion = "macOS " + strings.TrimSpace(out2)
|
||||
}
|
||||
|
||||
// Get refresh rate from display info (use mini detail to keep it fast).
|
||||
ctx3, cancel3 := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel3()
|
||||
out3, err := runCmd(ctx3, "system_profiler", "-detailLevel", "mini", "SPDisplaysDataType")
|
||||
if err == nil {
|
||||
refreshRate = parseRefreshRate(out3)
|
||||
}
|
||||
|
||||
diskSize := "Unknown"
|
||||
if len(disks) > 0 {
|
||||
diskSize = humanBytes(disks[0].Total)
|
||||
}
|
||||
|
||||
return HardwareInfo{
|
||||
Model: model,
|
||||
CPUModel: cpuModel,
|
||||
TotalRAM: humanBytes(totalRAM),
|
||||
DiskSize: diskSize,
|
||||
OSVersion: osVersion,
|
||||
Model: model,
|
||||
CPUModel: cpuModel,
|
||||
TotalRAM: humanBytes(totalRAM),
|
||||
DiskSize: diskSize,
|
||||
OSVersion: osVersion,
|
||||
RefreshRate: refreshRate,
|
||||
}
|
||||
}
|
||||
|
||||
// parseRefreshRate extracts the highest refresh rate from system_profiler display output.
|
||||
func parseRefreshRate(output string) string {
|
||||
lines := strings.Split(output, "\n")
|
||||
maxHz := 0
|
||||
|
||||
for _, line := range lines {
|
||||
lower := strings.ToLower(line)
|
||||
// Look for patterns like "@ 60Hz", "@ 60.00Hz", or "Refresh Rate: 120 Hz".
|
||||
if strings.Contains(lower, "hz") {
|
||||
fields := strings.Fields(lower)
|
||||
for i, field := range fields {
|
||||
if field == "hz" && i > 0 {
|
||||
if hz := parseInt(fields[i-1]); hz > maxHz && hz < 500 {
|
||||
maxHz = hz
|
||||
}
|
||||
continue
|
||||
}
|
||||
if strings.HasSuffix(field, "hz") {
|
||||
numStr := strings.TrimSuffix(field, "hz")
|
||||
if numStr == "" && i > 0 {
|
||||
numStr = fields[i-1]
|
||||
}
|
||||
if hz := parseInt(numStr); hz > maxHz && hz < 500 {
|
||||
maxHz = hz
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if maxHz > 0 {
|
||||
return fmt.Sprintf("%dHz", maxHz)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// parseInt safely parses an integer from a string.
|
||||
func parseInt(s string) int {
|
||||
// Trim away non-numeric padding, keep digits and '.' for decimals.
|
||||
cleaned := strings.TrimSpace(s)
|
||||
cleaned = strings.TrimLeftFunc(cleaned, func(r rune) bool {
|
||||
return (r < '0' || r > '9') && r != '.'
|
||||
})
|
||||
cleaned = strings.TrimRightFunc(cleaned, func(r rune) bool {
|
||||
return (r < '0' || r > '9') && r != '.'
|
||||
})
|
||||
if cleaned == "" {
|
||||
return 0
|
||||
}
|
||||
var num int
|
||||
fmt.Sscanf(cleaned, "%d", &num)
|
||||
return num
|
||||
}
|
||||
|
||||
@@ -125,6 +125,9 @@ func renderHeader(m MetricsSnapshot, errMsg string, animFrame int, termWidth int
|
||||
if len(specs) > 0 {
|
||||
infoParts = append(infoParts, strings.Join(specs, "/"))
|
||||
}
|
||||
if m.Hardware.RefreshRate != "" {
|
||||
infoParts = append(infoParts, m.Hardware.RefreshRate)
|
||||
}
|
||||
if m.Hardware.OSVersion != "" {
|
||||
infoParts = append(infoParts, m.Hardware.OSVersion)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user