mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
- added RAM pressure to BarChart widget
- added RAM pressure to LineChart widget
This commit is contained in:
@@ -16,9 +16,14 @@ public class BarChart: Widget {
|
||||
private var labelState: Bool = true
|
||||
private var boxState: Bool = true
|
||||
private var colorState: Bool = false
|
||||
private var pressureState: Bool = true
|
||||
|
||||
private let store: UnsafePointer<Store>?
|
||||
private var value: [Double] = []
|
||||
private var pressureLevel: Int = 0
|
||||
|
||||
private var pressureLevelSettingsView: NSView? = nil
|
||||
private var colorizeSettingsView: NSView? = nil
|
||||
|
||||
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
|
||||
var widgetTitle: String = title
|
||||
@@ -58,6 +63,7 @@ public class BarChart: Widget {
|
||||
self.boxState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_box", defaultValue: self.boxState)
|
||||
self.labelState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_label", defaultValue: self.labelState)
|
||||
self.colorState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_color", defaultValue: self.colorState)
|
||||
self.pressureState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_pressure", defaultValue: self.pressureState)
|
||||
}
|
||||
|
||||
if preview {
|
||||
@@ -66,6 +72,7 @@ public class BarChart: Widget {
|
||||
}
|
||||
self.setFrameSize(NSSize(width: 36, height: self.frame.size.height))
|
||||
self.invalidateIntrinsicContentSize()
|
||||
self.pressureState = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +162,8 @@ public class BarChart: Widget {
|
||||
|
||||
if self.colorState {
|
||||
partitionValue.usageColor().setFill()
|
||||
} else if self.pressureState {
|
||||
self.pressureLevel.pressureColor().setFill()
|
||||
} else {
|
||||
NSColor.controlAccentColor.set()
|
||||
}
|
||||
@@ -175,13 +184,35 @@ public class BarChart: Widget {
|
||||
})
|
||||
}
|
||||
|
||||
public func setPressure(_ level: Int) {
|
||||
guard self.pressureLevel != level else {
|
||||
return
|
||||
}
|
||||
|
||||
self.pressureLevel = level
|
||||
DispatchQueue.main.async(execute: {
|
||||
self.display()
|
||||
})
|
||||
}
|
||||
|
||||
public override func settings(superview: NSView) {
|
||||
let rowHeight: CGFloat = 30
|
||||
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 3) + Constants.Settings.margin
|
||||
let settingsNumber: CGFloat = self.title == "RAM" ? 4 : 3
|
||||
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * settingsNumber) + Constants.Settings.margin
|
||||
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
|
||||
|
||||
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
|
||||
|
||||
if self.title == "RAM" {
|
||||
self.pressureLevelSettingsView = ToggleTitleRow(
|
||||
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 3, width: view.frame.width, height: rowHeight),
|
||||
title: "Pressure level",
|
||||
action: #selector(togglePressure),
|
||||
state: self.pressureState
|
||||
)
|
||||
view.addSubview(self.pressureLevelSettingsView!)
|
||||
}
|
||||
|
||||
view.addSubview(ToggleTitleRow(
|
||||
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 2, width: view.frame.width, height: rowHeight),
|
||||
title: "Label",
|
||||
@@ -196,12 +227,13 @@ public class BarChart: Widget {
|
||||
state: self.boxState
|
||||
))
|
||||
|
||||
view.addSubview(ToggleTitleRow(
|
||||
self.colorizeSettingsView = ToggleTitleRow(
|
||||
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 0, width: view.frame.width, height: rowHeight),
|
||||
title: "Colorize",
|
||||
action: #selector(toggleColor),
|
||||
state: self.colorState
|
||||
))
|
||||
)
|
||||
view.addSubview(self.colorizeSettingsView!)
|
||||
|
||||
superview.addSubview(view)
|
||||
}
|
||||
@@ -239,6 +271,32 @@ public class BarChart: Widget {
|
||||
}
|
||||
self.colorState = state! == .on ? true : false
|
||||
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_color", value: self.colorState)
|
||||
|
||||
if self.colorState {
|
||||
self.pressureState = false
|
||||
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_pressure", value: self.pressureState)
|
||||
ToggleNSControlState(self.pressureLevelSettingsView, state: .off)
|
||||
}
|
||||
|
||||
self.display()
|
||||
}
|
||||
|
||||
@objc private func togglePressure(_ sender: NSControl) {
|
||||
var state: NSControl.StateValue? = nil
|
||||
if #available(OSX 10.15, *) {
|
||||
state = sender is NSSwitch ? (sender as! NSSwitch).state: nil
|
||||
} else {
|
||||
state = sender is NSButton ? (sender as! NSButton).state: nil
|
||||
}
|
||||
self.pressureState = state! == .on ? true : false
|
||||
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_pressure", value: self.pressureState)
|
||||
|
||||
if self.pressureState {
|
||||
self.colorState = false
|
||||
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_color", value: self.colorState)
|
||||
ToggleNSControlState(self.colorizeSettingsView, state: .off)
|
||||
}
|
||||
|
||||
self.display()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ public class LineChart: Widget {
|
||||
private var boxState: Bool = true
|
||||
private var valueState: Bool = false
|
||||
private var colorState: Bool = false
|
||||
private var pressureState: Bool = true
|
||||
|
||||
private let store: UnsafePointer<Store>?
|
||||
private var chart: LineChartView
|
||||
private var value: Double = 0
|
||||
private var pressureLevel: Int = 0
|
||||
|
||||
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
|
||||
var widgetTitle: String = title
|
||||
@@ -54,6 +56,7 @@ public class LineChart: Widget {
|
||||
self.valueState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_value", defaultValue: self.valueState)
|
||||
self.labelState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_label", defaultValue: self.labelState)
|
||||
self.colorState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_color", defaultValue: self.colorState)
|
||||
self.pressureState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_pressure", defaultValue: self.pressureState)
|
||||
}
|
||||
|
||||
if self.labelState {
|
||||
@@ -67,6 +70,7 @@ public class LineChart: Widget {
|
||||
}
|
||||
self.chart.points = list
|
||||
self.value = 0.38
|
||||
self.pressureState = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +146,11 @@ public class LineChart: Widget {
|
||||
}
|
||||
|
||||
chart.setFrameSize(NSSize(width: box.bounds.width - chartPadding, height: box.bounds.height - (chartPadding*2)))
|
||||
if self.pressureState {
|
||||
self.chart.color = self.pressureLevel.pressureColor()
|
||||
} else {
|
||||
self.chart.color = NSColor.controlAccentColor
|
||||
}
|
||||
chart.draw(NSRect(x: box.bounds.origin.x + 1, y: chartPadding, width: chart.frame.width, height: chart.frame.height))
|
||||
|
||||
ctx.restoreGState()
|
||||
@@ -154,11 +163,21 @@ public class LineChart: Widget {
|
||||
|
||||
public override func settings(superview: NSView) {
|
||||
let rowHeight: CGFloat = 30
|
||||
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 4) + Constants.Settings.margin
|
||||
let settingsNumber: CGFloat = self.title == "RAM" ? 5 : 4
|
||||
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * settingsNumber) + Constants.Settings.margin
|
||||
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
|
||||
|
||||
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
|
||||
|
||||
if self.title == "RAM" {
|
||||
view.addSubview(ToggleTitleRow(
|
||||
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 4, width: view.frame.width, height: rowHeight),
|
||||
title: "Pressure level",
|
||||
action: #selector(togglePressure),
|
||||
state: self.pressureState
|
||||
))
|
||||
}
|
||||
|
||||
view.addSubview(ToggleTitleRow(
|
||||
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 3, width: view.frame.width, height: rowHeight),
|
||||
title: "Label",
|
||||
@@ -205,6 +224,17 @@ public class LineChart: Widget {
|
||||
})
|
||||
}
|
||||
|
||||
public func setPressure(_ level: Int) {
|
||||
guard self.pressureLevel != level else {
|
||||
return
|
||||
}
|
||||
|
||||
self.pressureLevel = level
|
||||
DispatchQueue.main.async(execute: {
|
||||
self.display()
|
||||
})
|
||||
}
|
||||
|
||||
@objc private func toggleLabel(_ sender: NSControl) {
|
||||
var state: NSControl.StateValue? = nil
|
||||
if #available(OSX 10.15, *) {
|
||||
@@ -252,4 +282,16 @@ public class LineChart: Widget {
|
||||
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_color", value: self.colorState)
|
||||
self.display()
|
||||
}
|
||||
|
||||
@objc private func togglePressure(_ sender: NSControl) {
|
||||
var state: NSControl.StateValue? = nil
|
||||
if #available(OSX 10.15, *) {
|
||||
state = sender is NSSwitch ? (sender as! NSSwitch).state: nil
|
||||
} else {
|
||||
state = sender is NSButton ? (sender as! NSButton).state: nil
|
||||
}
|
||||
self.pressureState = state! == .on ? true : false
|
||||
self.store?.pointee.set(key: "\(self.title)_\(self.type.rawValue)_pressure", value: self.pressureState)
|
||||
self.display()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ open class Module: Module_p {
|
||||
|
||||
// load and setup widget
|
||||
private func setWidget() {
|
||||
self.widget = LoadWidget(self.activeWidget, preview: false, title: self.config.name, config: self.config.widgetsConfig, store: self.store)
|
||||
self.widget = LoadWidget(self.activeWidget, preview: false, name: self.config.name, config: self.config.widgetsConfig, store: self.store)
|
||||
if self.widget == nil {
|
||||
self.enabled = false
|
||||
os_log(.error, log: log, "widget with type %s not found", "\(self.activeWidget)")
|
||||
|
||||
@@ -120,7 +120,7 @@ open class Settings: NSView, Settings_p {
|
||||
var x: CGFloat = Constants.Settings.margin
|
||||
for i in 0...self.config.pointee.availableWidgets.count - 1 {
|
||||
let widgetType = self.config.pointee.availableWidgets[i]
|
||||
if let widget = LoadWidget(widgetType, preview: true, title: self.config.pointee.name, config: self.config.pointee.widgetsConfig, store: nil) {
|
||||
if let widget = LoadWidget(widgetType, preview: true, name: self.config.pointee.name, config: self.config.pointee.widgetsConfig, store: nil) {
|
||||
let preview = WidgetPreview(
|
||||
frame: NSRect(x: x, y: Constants.Settings.margin, width: widget.frame.width, height: self.widgetSelectorHeight - (Constants.Settings.margin*2)),
|
||||
title: self.config.pointee.name,
|
||||
|
||||
@@ -72,31 +72,31 @@ open class Widget: NSView, Widget_p {
|
||||
open func setValues(_ values: [value_t]) {}
|
||||
}
|
||||
|
||||
func LoadWidget(_ type: widget_t, preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) -> Widget_p? {
|
||||
func LoadWidget(_ type: widget_t, preview: Bool, name: String, config: NSDictionary?, store: UnsafePointer<Store>?) -> Widget_p? {
|
||||
var widget: Widget_p? = nil
|
||||
let widgetConfig: NSDictionary? = config?[type.rawValue] as? NSDictionary
|
||||
|
||||
switch type {
|
||||
case .mini:
|
||||
widget = Mini(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = Mini(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
case .lineChart:
|
||||
widget = LineChart(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = LineChart(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
case .barChart:
|
||||
widget = BarChart(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = BarChart(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
case .network:
|
||||
widget = NetworkWidget(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = NetworkWidget(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
case .battery:
|
||||
widget = BatterykWidget(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = BatterykWidget(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
case .sensors:
|
||||
widget = SensorsWidget(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = SensorsWidget(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
case .disk:
|
||||
widget = DiskWidget(preview: preview, title: title, config: widgetConfig, store: store)
|
||||
widget = DiskWidget(preview: preview, title: name, config: widgetConfig, store: store)
|
||||
break
|
||||
default: break
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ public struct RAM_Usage: value_t {
|
||||
var used: Double?
|
||||
var free: Double?
|
||||
|
||||
var pressureLevel: Int
|
||||
|
||||
public var widget_value: Double {
|
||||
get {
|
||||
return self.usage ?? 0
|
||||
@@ -63,9 +65,11 @@ public class Memory: Module {
|
||||
}
|
||||
if let widget = self.widget as? LineChart {
|
||||
widget.setValue(value!.usage ?? 0)
|
||||
widget.setPressure(value?.pressureLevel ?? 0)
|
||||
}
|
||||
if let widget = self.widget as? BarChart {
|
||||
widget.setValue([value!.usage ?? 0])
|
||||
widget.setPressure(value?.pressureLevel ?? 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ internal class UsageReader: Reader<RAM_Usage> {
|
||||
self.totalSize = Double(stats.max_mem)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
self.totalSize = 0
|
||||
print("Error with host_info(): " + (String(cString: mach_error_string(kerr), encoding: String.Encoding.ascii) ?? "unknown error"))
|
||||
}
|
||||
@@ -37,22 +37,26 @@ internal class UsageReader: Reader<RAM_Usage> {
|
||||
public override func read() {
|
||||
var stats = vm_statistics64()
|
||||
var count = UInt32(MemoryLayout<vm_statistics64_data_t>.size / MemoryLayout<integer_t>.size)
|
||||
|
||||
|
||||
let result: kern_return_t = withUnsafeMutablePointer(to: &stats) {
|
||||
$0.withMemoryRebound(to: integer_t.self, capacity: 1) {
|
||||
host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &count)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if result == KERN_SUCCESS {
|
||||
let active = Double(stats.active_count) * Double(PAGE_SIZE)
|
||||
let inactive = Double(stats.inactive_count) * Double(PAGE_SIZE)
|
||||
let wired = Double(stats.wire_count) * Double(PAGE_SIZE)
|
||||
let compressed = Double(stats.compressor_page_count) * Double(PAGE_SIZE)
|
||||
|
||||
|
||||
let used = active + wired + compressed
|
||||
let free = self.totalSize - used
|
||||
|
||||
var size: size_t = MemoryLayout<uint>.size
|
||||
var pressureLevel: Int = 0
|
||||
sysctlbyname("kern.memorystatus_vm_pressure_level", &pressureLevel, &size, nil, 0)
|
||||
|
||||
self.callback(RAM_Usage(
|
||||
active: active,
|
||||
inactive: inactive,
|
||||
@@ -62,11 +66,13 @@ internal class UsageReader: Reader<RAM_Usage> {
|
||||
usage: Double((self.totalSize - free) / self.totalSize),
|
||||
total: Double(self.totalSize),
|
||||
used: Double(used),
|
||||
free: Double(free))
|
||||
)
|
||||
free: Double(free),
|
||||
|
||||
pressureLevel: pressureLevel
|
||||
))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
print("Error with host_statistics64(): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ public class LineChartView: NSView {
|
||||
public var points: [Double]? = nil
|
||||
public var transparent: Bool = true
|
||||
|
||||
public var color: NSColor = NSColor.controlAccentColor
|
||||
|
||||
public init(frame: NSRect, num: Int) {
|
||||
self.points = Array(repeating: 0, count: num)
|
||||
super.init(frame: frame)
|
||||
@@ -40,10 +42,10 @@ public class LineChartView: NSView {
|
||||
return
|
||||
}
|
||||
|
||||
let lineColor: NSColor = NSColor.controlAccentColor
|
||||
var gradientColor: NSColor = NSColor.controlAccentColor.withAlphaComponent(0.5)
|
||||
let lineColor: NSColor = self.color
|
||||
var gradientColor: NSColor = self.color.withAlphaComponent(0.5)
|
||||
if !self.transparent {
|
||||
gradientColor = NSColor.controlAccentColor.withAlphaComponent(0.8)
|
||||
gradientColor = self.color.withAlphaComponent(0.8)
|
||||
}
|
||||
|
||||
let context = NSGraphicsContext.current!.cgContext
|
||||
|
||||
@@ -154,6 +154,21 @@ extension String: LocalizedError {
|
||||
}
|
||||
}
|
||||
|
||||
public extension Int {
|
||||
func pressureColor() -> NSColor {
|
||||
switch self {
|
||||
case 1:
|
||||
return NSColor.systemGreen
|
||||
case 2:
|
||||
return NSColor.systemYellow
|
||||
case 3:
|
||||
return NSColor.systemRed
|
||||
default:
|
||||
return NSColor.controlAccentColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Float {
|
||||
init?(_ bytes: [UInt8]) {
|
||||
self = bytes.withUnsafeBytes {
|
||||
@@ -559,3 +574,17 @@ public extension Array where Element : Equatable {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public func ToggleNSControlState(_ view: NSView?, state: NSControl.StateValue) {
|
||||
if let control = view?.subviews.first(where: { $0 is NSControl }) {
|
||||
if #available(OSX 10.15, *) {
|
||||
if let checkbox = control as? NSSwitch {
|
||||
checkbox.state = state
|
||||
}
|
||||
} else {
|
||||
if let checkbox = control as? NSButton {
|
||||
checkbox.state = state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user