mirror of
https://github.com/tw93/Mole.git
synced 2026-02-09 14:54:19 +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 {
|
type HardwareInfo struct {
|
||||||
Model string // MacBook Pro 14-inch, 2021
|
Model string // MacBook Pro 14-inch, 2021
|
||||||
CPUModel string // Apple M1 Pro / Intel Core i7
|
CPUModel string // Apple M1 Pro / Intel Core i7
|
||||||
TotalRAM string // 16GB
|
TotalRAM string // 16GB
|
||||||
DiskSize string // 512GB
|
DiskSize string // 512GB
|
||||||
OSVersion string // macOS Sonoma 14.5
|
OSVersion string // macOS Sonoma 14.5
|
||||||
|
RefreshRate string // 120Hz / 60Hz
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiskIOStatus struct {
|
type DiskIOStatus struct {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -10,11 +11,12 @@ import (
|
|||||||
func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
||||||
if runtime.GOOS != "darwin" {
|
if runtime.GOOS != "darwin" {
|
||||||
return HardwareInfo{
|
return HardwareInfo{
|
||||||
Model: "Unknown",
|
Model: "Unknown",
|
||||||
CPUModel: runtime.GOARCH,
|
CPUModel: runtime.GOARCH,
|
||||||
TotalRAM: humanBytes(totalRAM),
|
TotalRAM: humanBytes(totalRAM),
|
||||||
DiskSize: "Unknown",
|
DiskSize: "Unknown",
|
||||||
OSVersion: runtime.GOOS,
|
OSVersion: runtime.GOOS,
|
||||||
|
RefreshRate: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var model, cpuModel, osVersion string
|
var model, cpuModel, osVersion, refreshRate string
|
||||||
|
|
||||||
out, err := runCmd(ctx, "system_profiler", "SPHardwareDataType")
|
out, err := runCmd(ctx, "system_profiler", "SPHardwareDataType")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -58,16 +60,79 @@ func collectHardware(totalRAM uint64, disks []DiskStatus) HardwareInfo {
|
|||||||
osVersion = "macOS " + strings.TrimSpace(out2)
|
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"
|
diskSize := "Unknown"
|
||||||
if len(disks) > 0 {
|
if len(disks) > 0 {
|
||||||
diskSize = humanBytes(disks[0].Total)
|
diskSize = humanBytes(disks[0].Total)
|
||||||
}
|
}
|
||||||
|
|
||||||
return HardwareInfo{
|
return HardwareInfo{
|
||||||
Model: model,
|
Model: model,
|
||||||
CPUModel: cpuModel,
|
CPUModel: cpuModel,
|
||||||
TotalRAM: humanBytes(totalRAM),
|
TotalRAM: humanBytes(totalRAM),
|
||||||
DiskSize: diskSize,
|
DiskSize: diskSize,
|
||||||
OSVersion: osVersion,
|
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 {
|
if len(specs) > 0 {
|
||||||
infoParts = append(infoParts, strings.Join(specs, "/"))
|
infoParts = append(infoParts, strings.Join(specs, "/"))
|
||||||
}
|
}
|
||||||
|
if m.Hardware.RefreshRate != "" {
|
||||||
|
infoParts = append(infoParts, m.Hardware.RefreshRate)
|
||||||
|
}
|
||||||
if m.Hardware.OSVersion != "" {
|
if m.Hardware.OSVersion != "" {
|
||||||
infoParts = append(infoParts, m.Hardware.OSVersion)
|
infoParts = append(infoParts, m.Hardware.OSVersion)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user