Now using SensorsUI

This commit is contained in:
macmade
2023-02-08 21:49:53 +01:00
parent d51f5f72df
commit 9fa4663763
30 changed files with 52 additions and 8258 deletions

View File

@@ -17,27 +17,6 @@
052FBCD5251F842C00C4322E /* CPUTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCD1251F842C00C4322E /* CPUTemplate.pdf */; };
052FBCD6251F842C00C4322E /* TemperatureTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCD2251F842C00C4322E /* TemperatureTemplate.pdf */; };
052FBCD7251F842C00C4322E /* SchedulerTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCD3251F842C00C4322E /* SchedulerTemplate.pdf */; };
05566A082990F85200E7A5F1 /* SensorIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669EA2990F85200E7A5F1 /* SensorIcon.swift */; };
05566A092990F85200E7A5F1 /* SensorsWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669EB2990F85200E7A5F1 /* SensorsWindowController.swift */; };
05566A0A2990F85200E7A5F1 /* VoltageTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 055669ED2990F85200E7A5F1 /* VoltageTemplate.pdf */; };
05566A0B2990F85200E7A5F1 /* CurrentTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 055669EE2990F85200E7A5F1 /* CurrentTemplate.pdf */; };
05566A0C2990F85200E7A5F1 /* ThermalTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 055669EF2990F85200E7A5F1 /* ThermalTemplate.pdf */; };
05566A0D2990F85200E7A5F1 /* SensorValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F02990F85200E7A5F1 /* SensorValue.swift */; };
05566A0E2990F85200E7A5F1 /* SensorHistoryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F12990F85200E7A5F1 /* SensorHistoryData.swift */; };
05566A0F2990F85200E7A5F1 /* ArrayIsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F22990F85200E7A5F1 /* ArrayIsNotEmpty.swift */; };
05566A102990F85200E7A5F1 /* SensorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F32990F85200E7A5F1 /* SensorItem.swift */; };
05566A112990F85200E7A5F1 /* SensorItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 055669F42990F85200E7A5F1 /* SensorItem.xib */; };
05566A122990F85200E7A5F1 /* SensorsWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 055669F62990F85200E7A5F1 /* SensorsWindowController.xib */; };
05566A132990F85200E7A5F1 /* ArrayIsEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F82990F85200E7A5F1 /* ArrayIsEmpty.swift */; };
05566A142990F85200E7A5F1 /* SensorGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F92990F85200E7A5F1 /* SensorGraphView.swift */; };
05566A152990F85200E7A5F1 /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FA2990F85200E7A5F1 /* NSImage.swift */; };
05566A162990F85200E7A5F1 /* Sensors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FB2990F85200E7A5F1 /* Sensors.swift */; };
05566A172990F85200E7A5F1 /* Synchronizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FC2990F85200E7A5F1 /* Synchronizable.swift */; };
05566A182990F85200E7A5F1 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FD2990F85200E7A5F1 /* Colors.swift */; };
05566A192990F85200E7A5F1 /* IOHIDData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05566A012990F85200E7A5F1 /* IOHIDData.swift */; };
05566A1A2990F85200E7A5F1 /* IOHID.m in Sources */ = {isa = PBXBuildFile; fileRef = 05566A022990F85200E7A5F1 /* IOHID.m */; };
05566A1B2990F85200E7A5F1 /* SMC.m in Sources */ = {isa = PBXBuildFile; fileRef = 05566A042990F85200E7A5F1 /* SMC.m */; };
05566A1C2990F85200E7A5F1 /* SMCData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05566A052990F85200E7A5F1 /* SMCData.swift */; };
05566A75299195F400E7A5F1 /* GraphWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05566A74299195F400E7A5F1 /* GraphWindowController.swift */; };
05566A782991963400E7A5F1 /* GraphWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05566A772991963400E7A5F1 /* GraphWindowController.xib */; };
055A9320252778C10070F771 /* InfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055A931F252778C10070F771 /* InfoViewController.swift */; };
@@ -53,6 +32,12 @@
057F8B1B251D2A970048F1E1 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 057F8B1A251D2A970048F1E1 /* Icon.icns */; };
057F8B65251D2D5F0048F1E1 /* GitHubUpdates.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 057F8B5C251D2D510048F1E1 /* GitHubUpdates.framework */; };
057F8B67251D2D680048F1E1 /* GitHubUpdates.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 057F8B5C251D2D510048F1E1 /* GitHubUpdates.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
058B8EFC2994421200263FE9 /* IOHIDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058B8EFA2994421200263FE9 /* IOHIDKit.framework */; };
058B8EFD2994421200263FE9 /* IOHIDKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 058B8EFA2994421200263FE9 /* IOHIDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
058B8EFE2994421200263FE9 /* SensorsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058B8EF9299441F600263FE9 /* SensorsUI.framework */; };
058B8EFF2994421200263FE9 /* SensorsUI.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 058B8EF9299441F600263FE9 /* SensorsUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
058B8F002994421200263FE9 /* SMCKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058B8EFB2994421200263FE9 /* SMCKit.framework */; };
058B8F012994421200263FE9 /* SMCKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 058B8EFB2994421200263FE9 /* SMCKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
05AA407A251CF3D200106CEA /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA4079251CF3D200106CEA /* ApplicationDelegate.swift */; };
05AA407F251CF3D600106CEA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05AA407D251CF3D600106CEA /* MainMenu.xib */; };
05AA408D251CFA0600106CEA /* ThermalLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA408C251CFA0600106CEA /* ThermalLog.swift */; };
@@ -90,6 +75,13 @@
remoteGlobalIDString = 05F82B241EF32EA700EC8A93;
remoteInfo = GitHubUpdates;
};
058B8EF8299441F600263FE9 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 058B8EF1299441F500263FE9 /* SensorsUI.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 058B8EA22994383300263FE9;
remoteInfo = SensorsUI;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -100,6 +92,9 @@
dstSubfolderSpec = 10;
files = (
057F8B67251D2D680048F1E1 /* GitHubUpdates.framework in CopyFiles */,
058B8EFF2994421200263FE9 /* SensorsUI.framework in CopyFiles */,
058B8EFD2994421200263FE9 /* IOHIDKit.framework in CopyFiles */,
058B8F012994421200263FE9 /* SMCKit.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -116,31 +111,6 @@
052FBCD1251F842C00C4322E /* CPUTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = CPUTemplate.pdf; sourceTree = "<group>"; };
052FBCD2251F842C00C4322E /* TemperatureTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = TemperatureTemplate.pdf; sourceTree = "<group>"; };
052FBCD3251F842C00C4322E /* SchedulerTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = SchedulerTemplate.pdf; sourceTree = "<group>"; };
055669EA2990F85200E7A5F1 /* SensorIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorIcon.swift; sourceTree = "<group>"; };
055669EB2990F85200E7A5F1 /* SensorsWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorsWindowController.swift; sourceTree = "<group>"; };
055669ED2990F85200E7A5F1 /* VoltageTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = VoltageTemplate.pdf; sourceTree = "<group>"; };
055669EE2990F85200E7A5F1 /* CurrentTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = CurrentTemplate.pdf; sourceTree = "<group>"; };
055669EF2990F85200E7A5F1 /* ThermalTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = ThermalTemplate.pdf; sourceTree = "<group>"; };
055669F02990F85200E7A5F1 /* SensorValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorValue.swift; sourceTree = "<group>"; };
055669F12990F85200E7A5F1 /* SensorHistoryData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorHistoryData.swift; sourceTree = "<group>"; };
055669F22990F85200E7A5F1 /* ArrayIsNotEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayIsNotEmpty.swift; sourceTree = "<group>"; };
055669F32990F85200E7A5F1 /* SensorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorItem.swift; sourceTree = "<group>"; };
055669F52990F85200E7A5F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorItem.xib; sourceTree = "<group>"; };
055669F72990F85200E7A5F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorsWindowController.xib; sourceTree = "<group>"; };
055669F82990F85200E7A5F1 /* ArrayIsEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayIsEmpty.swift; sourceTree = "<group>"; };
055669F92990F85200E7A5F1 /* SensorGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorGraphView.swift; sourceTree = "<group>"; };
055669FA2990F85200E7A5F1 /* NSImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = "<group>"; };
055669FB2990F85200E7A5F1 /* Sensors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sensors.swift; sourceTree = "<group>"; };
055669FC2990F85200E7A5F1 /* Synchronizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Synchronizable.swift; sourceTree = "<group>"; };
055669FD2990F85200E7A5F1 /* Colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
055669FF2990F85200E7A5F1 /* IOHID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOHID.h; sourceTree = "<group>"; };
05566A002990F85200E7A5F1 /* IOHID-Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IOHID-Internal.h"; sourceTree = "<group>"; };
05566A012990F85200E7A5F1 /* IOHIDData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IOHIDData.swift; sourceTree = "<group>"; };
05566A022990F85200E7A5F1 /* IOHID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IOHID.m; sourceTree = "<group>"; };
05566A042990F85200E7A5F1 /* SMC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMC.m; sourceTree = "<group>"; };
05566A052990F85200E7A5F1 /* SMCData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMCData.swift; sourceTree = "<group>"; };
05566A062990F85200E7A5F1 /* SMC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMC.h; sourceTree = "<group>"; };
05566A072990F85200E7A5F1 /* SMC-Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SMC-Internal.h"; sourceTree = "<group>"; };
05566A74299195F400E7A5F1 /* GraphWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphWindowController.swift; sourceTree = "<group>"; };
05566A772991963400E7A5F1 /* GraphWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GraphWindowController.xib; sourceTree = "<group>"; };
055A931F252778C10070F771 /* InfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoViewController.swift; sourceTree = "<group>"; };
@@ -203,6 +173,10 @@
057F8B53251D2C840048F1E1 /* ccache.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ccache.sh; sourceTree = "<group>"; };
057F8B54251D2C840048F1E1 /* Debug - zld.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Debug - zld.xcconfig"; sourceTree = "<group>"; };
057F8B56251D2D510048F1E1 /* GitHubUpdates.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GitHubUpdates.xcodeproj; path = Submodules/GitHubUpdates/GitHubUpdates.xcodeproj; sourceTree = "<group>"; };
058B8EEF299441CE00263FE9 /* CODE_OF_CONDUCT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CODE_OF_CONDUCT.md; sourceTree = "<group>"; };
058B8EF1299441F500263FE9 /* SensorsUI.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SensorsUI.xcodeproj; path = Submodules/Sensors/SensorsUI.xcodeproj; sourceTree = "<group>"; };
058B8EFA2994421200263FE9 /* IOHIDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = IOHIDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
058B8EFB2994421200263FE9 /* SMCKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SMCKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
05AA4076251CF3D200106CEA /* Hot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hot.app; sourceTree = BUILT_PRODUCTS_DIR; };
05AA4079251CF3D200106CEA /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = "<group>"; };
05AA407E251CF3D600106CEA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -226,68 +200,17 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
058B8EFC2994421200263FE9 /* IOHIDKit.framework in Frameworks */,
052FBC34251ECA8600C4322E /* IOKit.framework in Frameworks */,
058B8EFE2994421200263FE9 /* SensorsUI.framework in Frameworks */,
057F8B65251D2D5F0048F1E1 /* GitHubUpdates.framework in Frameworks */,
058B8F002994421200263FE9 /* SMCKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
055669E92990F85200E7A5F1 /* SensorsWindow */ = {
isa = PBXGroup;
children = (
055669EA2990F85200E7A5F1 /* SensorIcon.swift */,
055669EB2990F85200E7A5F1 /* SensorsWindowController.swift */,
055669EC2990F85200E7A5F1 /* Images */,
055669F02990F85200E7A5F1 /* SensorValue.swift */,
055669F12990F85200E7A5F1 /* SensorHistoryData.swift */,
055669F22990F85200E7A5F1 /* ArrayIsNotEmpty.swift */,
055669F32990F85200E7A5F1 /* SensorItem.swift */,
055669F42990F85200E7A5F1 /* SensorItem.xib */,
055669F62990F85200E7A5F1 /* SensorsWindowController.xib */,
055669F82990F85200E7A5F1 /* ArrayIsEmpty.swift */,
055669F92990F85200E7A5F1 /* SensorGraphView.swift */,
055669FA2990F85200E7A5F1 /* NSImage.swift */,
055669FB2990F85200E7A5F1 /* Sensors.swift */,
055669FC2990F85200E7A5F1 /* Synchronizable.swift */,
055669FD2990F85200E7A5F1 /* Colors.swift */,
);
path = SensorsWindow;
sourceTree = "<group>";
};
055669EC2990F85200E7A5F1 /* Images */ = {
isa = PBXGroup;
children = (
055669ED2990F85200E7A5F1 /* VoltageTemplate.pdf */,
055669EE2990F85200E7A5F1 /* CurrentTemplate.pdf */,
055669EF2990F85200E7A5F1 /* ThermalTemplate.pdf */,
);
path = Images;
sourceTree = "<group>";
};
055669FE2990F85200E7A5F1 /* IOHID */ = {
isa = PBXGroup;
children = (
055669FF2990F85200E7A5F1 /* IOHID.h */,
05566A002990F85200E7A5F1 /* IOHID-Internal.h */,
05566A012990F85200E7A5F1 /* IOHIDData.swift */,
05566A022990F85200E7A5F1 /* IOHID.m */,
);
path = IOHID;
sourceTree = "<group>";
};
05566A032990F85200E7A5F1 /* SMC */ = {
isa = PBXGroup;
children = (
05566A042990F85200E7A5F1 /* SMC.m */,
05566A052990F85200E7A5F1 /* SMCData.swift */,
05566A062990F85200E7A5F1 /* SMC.h */,
05566A072990F85200E7A5F1 /* SMC-Internal.h */,
);
path = SMC;
sourceTree = "<group>";
};
057F8AFE251D22360048F1E1 /* Images */ = {
isa = PBXGroup;
children = (
@@ -436,16 +359,28 @@
057F8B64251D2D5F0048F1E1 /* Frameworks */ = {
isa = PBXGroup;
children = (
058B8EFA2994421200263FE9 /* IOHIDKit.framework */,
058B8EFB2994421200263FE9 /* SMCKit.framework */,
052FBC33251ECA8600C4322E /* IOKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
058B8EF2299441F500263FE9 /* Products */ = {
isa = PBXGroup;
children = (
058B8EF9299441F600263FE9 /* SensorsUI.framework */,
);
name = Products;
sourceTree = "<group>";
};
05AA406D251CF3D200106CEA = {
isa = PBXGroup;
children = (
057F8B1E251D2B900048F1E1 /* LICENSE */,
057F8B1F251D2B900048F1E1 /* README.md */,
058B8EEF299441CE00263FE9 /* CODE_OF_CONDUCT.md */,
058B8EF1299441F500263FE9 /* SensorsUI.xcodeproj */,
057F8B56251D2D510048F1E1 /* GitHubUpdates.xcodeproj */,
057F8B20251D2C840048F1E1 /* xcconfig */,
05AA4078251CF3D200106CEA /* Hot */,
@@ -476,9 +411,6 @@
05AA4088251CF3F400106CEA /* Classes */ = {
isa = PBXGroup;
children = (
055669FE2990F85200E7A5F1 /* IOHID */,
055669E92990F85200E7A5F1 /* SensorsWindow */,
05566A032990F85200E7A5F1 /* SMC */,
057F8B0B251D273E0048F1E1 /* AboutWindowController.swift */,
05AA4079251CF3D200106CEA /* ApplicationDelegate.swift */,
05221E87267009A8007246FF /* SensorViewController.swift */,
@@ -569,6 +501,10 @@
ProductGroup = 057F8B57251D2D510048F1E1 /* Products */;
ProjectRef = 057F8B56251D2D510048F1E1 /* GitHubUpdates.xcodeproj */;
},
{
ProductGroup = 058B8EF2299441F500263FE9 /* Products */;
ProjectRef = 058B8EF1299441F500263FE9 /* SensorsUI.xcodeproj */;
},
);
projectRoot = "";
targets = (
@@ -592,6 +528,13 @@
remoteRef = 057F8B5D251D2D510048F1E1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
058B8EF9299441F600263FE9 /* SensorsUI.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = SensorsUI.framework;
remoteRef = 058B8EF8299441F600263FE9 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
@@ -605,14 +548,11 @@
057F8B00251D22360048F1E1 /* StatusIconTemplate.pdf in Resources */,
057F8B1B251D2A970048F1E1 /* Icon.icns in Resources */,
052FBCD5251F842C00C4322E /* CPUTemplate.pdf in Resources */,
05566A0C2990F85200E7A5F1 /* ThermalTemplate.pdf in Resources */,
05221E8B26700A57007246FF /* SensorViewController.xib in Resources */,
05AD459229092CEB00A791C8 /* TCalTemplate.pdf in Resources */,
05AD458C2908505900A791C8 /* SelectSensorsWindowController.xib in Resources */,
055A9323252778D00070F771 /* InfoViewController.xib in Resources */,
05B0DFA526714A830068FF9B /* UnknownTemplate.pdf in Resources */,
05566A112990F85200E7A5F1 /* SensorItem.xib in Resources */,
05566A0B2990F85200E7A5F1 /* CurrentTemplate.pdf in Resources */,
05AD459029092B8400A791C8 /* BatteryTemplate.pdf in Resources */,
057F8B15251D27650048F1E1 /* AboutWindowController.xib in Resources */,
052FBCA7251EE46700C4322E /* PreferencesWindowController.xib in Resources */,
@@ -620,8 +560,6 @@
052FBCD7251F842C00C4322E /* SchedulerTemplate.pdf in Resources */,
05B0DFA626714A830068FF9B /* eAccTemplate.pdf in Resources */,
05566A782991963400E7A5F1 /* GraphWindowController.xib in Resources */,
05566A0A2990F85200E7A5F1 /* VoltageTemplate.pdf in Resources */,
05566A122990F85200E7A5F1 /* SensorsWindowController.xib in Resources */,
05B0DFAA267150F40068FF9B /* TCXCTemplate.pdf in Resources */,
05B0DFA426714A830068FF9B /* pAccTemplate.pdf in Resources */,
);
@@ -655,14 +593,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
05566A0E2990F85200E7A5F1 /* SensorHistoryData.swift in Sources */,
055A932525277E9E0070F771 /* IntegerToString.swift in Sources */,
05566A172990F85200E7A5F1 /* Synchronizable.swift in Sources */,
055A932725277F6E0070F771 /* TemperatureToString.swift in Sources */,
05566A0D2990F85200E7A5F1 /* SensorValue.swift in Sources */,
05566A1C2990F85200E7A5F1 /* SMCData.swift in Sources */,
05566A192990F85200E7A5F1 /* IOHIDData.swift in Sources */,
05566A152990F85200E7A5F1 /* NSImage.swift in Sources */,
05221E8626700772007246FF /* DictionaryIsEmpty.swift in Sources */,
052FBCA3251EE43B00C4322E /* PreferencesWindowController.swift in Sources */,
055A932B252780FD0070F771 /* GraphView.swift in Sources */,
@@ -670,22 +602,12 @@
057F8B11251D274C0048F1E1 /* NSApplication+LaunchServices.m in Sources */,
057F8B0C251D273E0048F1E1 /* AboutWindowController.swift in Sources */,
055A9320252778C10070F771 /* InfoViewController.swift in Sources */,
05566A162990F85200E7A5F1 /* Sensors.swift in Sources */,
05566A102990F85200E7A5F1 /* SensorItem.swift in Sources */,
05566A082990F85200E7A5F1 /* SensorIcon.swift in Sources */,
05566A182990F85200E7A5F1 /* Colors.swift in Sources */,
05566A092990F85200E7A5F1 /* SensorsWindowController.swift in Sources */,
05AD458829084FEF00A791C8 /* SelectSensorsWindowController.swift in Sources */,
05566A1A2990F85200E7A5F1 /* IOHID.m in Sources */,
05566A0F2990F85200E7A5F1 /* ArrayIsNotEmpty.swift in Sources */,
05566A75299195F400E7A5F1 /* GraphWindowController.swift in Sources */,
05AA408D251CFA0600106CEA /* ThermalLog.swift in Sources */,
055A932925277F990070F771 /* PercentToString.swift in Sources */,
05566A132990F85200E7A5F1 /* ArrayIsEmpty.swift in Sources */,
05AA407A251CF3D200106CEA /* ApplicationDelegate.swift in Sources */,
05BA0BAA26F342DA00AA7BFC /* PressureToString.swift in Sources */,
05566A1B2990F85200E7A5F1 /* SMC.m in Sources */,
05566A142990F85200E7A5F1 /* SensorGraphView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -716,22 +638,6 @@
name = PreferencesWindowController.xib;
sourceTree = "<group>";
};
055669F42990F85200E7A5F1 /* SensorItem.xib */ = {
isa = PBXVariantGroup;
children = (
055669F52990F85200E7A5F1 /* Base */,
);
name = SensorItem.xib;
sourceTree = "<group>";
};
055669F62990F85200E7A5F1 /* SensorsWindowController.xib */ = {
isa = PBXVariantGroup;
children = (
055669F72990F85200E7A5F1 /* Base */,
);
name = SensorsWindowController.xib;
sourceTree = "<group>";
};
055A9321252778D00070F771 /* InfoViewController.xib */ = {
isa = PBXVariantGroup;
children = (

View File

@@ -1,7 +1,7 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
* Copyright (c) 2023, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
@@ -24,6 +24,7 @@
import Cocoa
import GitHubUpdates
import SensorsUI
@NSApplicationMain
class ApplicationDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate

View File

@@ -23,5 +23,3 @@
******************************************************************************/
#import "NSApplication+LaunchServices.h"
#import "SMC.h"
#import "IOHID.h"

View File

@@ -1,135 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
@import IOKit;
@import CoreFoundation;
#import <IOKit/hidsystem/IOHIDEventSystemClient.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
#import <IOKit/hid/IOHIDKeys.h>
/* @see https://opensource.apple.com/source/IOHIDFamily/ */
typedef NS_ENUM( int64_t, IOHIDPage )
{
IOHIDPageAppleVendor = 0xFF00,
IOHIDPageAppleVendorKeyboard = 0xFF01,
IOHIDPageAppleVendorMouse = 0xFF02,
IOHIDPageAppleVendorAccelerometer = 0xFF03,
IOHIDPageAppleVendorAmbientLightSensor = 0xFF04,
IOHIDPageAppleVendorTemperatureSensor = 0xFF05,
IOHIDPageAppleVendorHeadset = 0xFF07,
IOHIDPageAppleVendorPowerSensor = 0xFF08,
IOHIDPageAppleVendorSmartCover = 0xFF09,
IOHIDPageAppleVendorPlatinum = 0xFF0A,
IOHIDPageAppleVendorLisa = 0xFF0B,
IOHIDPageAppleVendorMotion = 0xFF0C,
IOHIDPageAppleVendorBattery = 0xFF0D,
IOHIDPageAppleVendorIRRemote = 0xFF0E,
IOHIDPageAppleVendorDebug = 0xFF0F,
IOHIDPageAppleVendorFilteredEvent = 0xFF50,
IOHIDPageAppleVendorMultitouch = 0xFF60,
IOHIDPageAppleVendorDisplay = 0xFF92,
IOHIDPageAppleVendorTopCase = 0x00FF
};
typedef NS_ENUM( int64_t, IOHIDUsageAppleVendor )
{
IOHIDUsageAppleVendorTopCase = 0x01,
IOHIDUsageAppleVendorDisplay = 0x02,
IOHIDUsageAppleVendorAccelerometer = 0x03,
IOHIDUsageAppleVendorAmbientLightSensor = 0x04,
IOHIDUsageAppleVendorTemperatureSensor = 0x05,
IOHIDUsageAppleVendorKeyboard = 0x06,
IOHIDUsageAppleVendorHeadset = 0x07,
IOHIDUsageAppleVendorProximitySensor = 0x08,
IOHIDUsageAppleVendorGyro = 0x09,
IOHIDUsageAppleVendorCompass = 0x0A,
IOHIDUsageAppleVendorDeviceManagement = 0x0B,
IOHIDUsageAppleVendorTrackpad = 0x0C,
IOHIDUsageAppleVendorTopCaseReserved = 0x0D,
IOHIDUsageAppleVendorMotion = 0x0E,
IOHIDUsageAppleVendorKeyboardBacklight = 0x0F,
IOHIDUsageAppleVendorDeviceMotionLite = 0x10,
IOHIDUsageAppleVendorForce = 0x11,
IOHIDUsageAppleVendorBluetoothRadio = 0x12,
IOHIDUsageAppleVendorOrb = 0x13,
IOHIDUsageAppleVendorAccessoryBattery = 0x14
};
typedef NS_ENUM( int64_t, IOHIDUsageAppleVendorPowerSensor )
{
IOHIDUsageAppleVendorPowerSensorPower = 0x1,
IOHIDUsageAppleVendorPowerSensorCurrent = 0x2,
IOHIDUsageAppleVendorPowerSensorVoltage = 0x3
};
typedef NS_ENUM( int64_t, IOHIDEvent )
{
IOHIDEventTypeNULL = 0x00,
IOHIDEventTypeVendorDefined = 0x01,
IOHIDEventTypeButton = 0x02,
IOHIDEventTypeKeyboard = 0x03,
IOHIDEventTypeTranslation = 0x04,
IOHIDEventTypeRotation = 0x05,
IOHIDEventTypeScroll = 0x06,
IOHIDEventTypeScale = 0x07,
IOHIDEventTypeZoom = 0x08,
IOHIDEventTypeVelocity = 0x09,
IOHIDEventTypeOrientation = 0x0A,
IOHIDEventTypeDigitizer = 0x0B,
IOHIDEventTypeAmbientLightSensor = 0x0C,
IOHIDEventTypeAccelerometer = 0x0D,
IOHIDEventTypeProximity = 0x0E,
IOHIDEventTypeTemperature = 0x0F,
IOHIDEventTypeNavigationSwipe = 0x10,
IOHIDEventTypeSwipe = IOHIDEventTypeNavigationSwipe,
IOHIDEventTypeMouse = 0x11,
IOHIDEventTypeProgress = 0x12,
IOHIDEventTypeCount = 0x13,
IOHIDEventTypeGyro = 0x14,
IOHIDEventTypeCompass = 0x15,
IOHIDEventTypeZoomToggle = 0x16,
IOHIDEventTypeDockSwipe = 0x17,
IOHIDEventTypeSymbolicHotKey = 0x18,
IOHIDEventTypePower = 0x19,
IOHIDEventTypeBrightness = 0x1A,
IOHIDEventTypeFluidTouchGesture = 0x1B,
IOHIDEventTypeBoundaryScroll = 0x1C,
IOHIDEventTypeReset = 0x1D
};
#define IOHIDEventFieldBase( _type_ ) ( _type_ << 16 )
typedef NS_ENUM( int64_t, IOHIDEventField )
{
IOHIDEventFieldTemperatureLevel = IOHIDEventFieldBase( IOHIDEventTypeTemperature ),
IOHIDEventFieldPowerMeasurement = IOHIDEventFieldBase( IOHIDEventTypePower )
};
extern IOHIDEventSystemClientRef IOHIDEventSystemClientCreate( CFAllocatorRef );
extern void IOHIDEventSystemClientSetMatching( IOHIDEventSystemClientRef, CFDictionaryRef );
extern CFTypeRef IOHIDServiceClientCopyEvent( IOHIDServiceClientRef, IOHIDEvent, int64_t, int64_t );
extern CFDictionaryRef IOHIDServiceClientCopyProperties( IOHIDServiceClientRef, CFArrayRef );
extern double IOHIDEventGetFloatValue( CFTypeRef, int64_t );

View File

@@ -1,42 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
@import Foundation;
@class IOHIDData;
NS_ASSUME_NONNULL_BEGIN
@interface IOHID: NSObject
@property( class, nonatomic, readonly ) IOHID * shared;
- ( instancetype )init;
- ( NSArray< IOHIDData * > * )readTemperatureSensors;
- ( NSArray< IOHIDData * > * )readVoltageSensors;
- ( NSArray< IOHIDData * > * )readCurrentSensors;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,130 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#import "IOHID.h"
#import "IOHID-Internal.h"
#import "Hot-Swift.h"
#import <IOKit/hidsystem/IOHIDEventSystemClient.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
NS_ASSUME_NONNULL_BEGIN
@interface IOHID()
@property( nonatomic, readwrite, assign, nullable ) IOHIDEventSystemClientRef client;
- ( NSArray< IOHIDData * > * )read: ( long long )page usage: ( int64_t )usage eventType: ( int64_t )eventType eventField: ( int64_t )eventField;
@end
NS_ASSUME_NONNULL_END
@implementation IOHID
+ ( IOHID * )shared
{
static dispatch_once_t once;
static IOHID * instance;
dispatch_once
(
&once,
^( void )
{
instance = [ IOHID new ];
}
);
return instance;
}
- ( instancetype )init
{
if( ( self = [ super init ] ) )
{
self.client = IOHIDEventSystemClientCreate( kCFAllocatorDefault );
}
return self;
}
- ( oneway void )dealloc
{
CFRelease( self.client );
}
- ( NSArray< IOHIDData * > * )readTemperatureSensors
{
return [ self read: IOHIDPageAppleVendor usage: IOHIDUsageAppleVendorTemperatureSensor eventType: IOHIDEventTypeTemperature eventField: IOHIDEventFieldTemperatureLevel ];
}
- ( NSArray< IOHIDData * > * )readVoltageSensors
{
return [ self read: IOHIDPageAppleVendorPowerSensor usage: IOHIDUsageAppleVendorPowerSensorVoltage eventType: IOHIDEventTypePower eventField: IOHIDEventFieldPowerMeasurement ];
}
- ( NSArray< IOHIDData * > * )readCurrentSensors
{
return [ self read: IOHIDPageAppleVendorPowerSensor usage: IOHIDUsageAppleVendorPowerSensorCurrent eventType: IOHIDEventTypePower eventField: IOHIDEventFieldPowerMeasurement ];
}
- ( NSArray< IOHIDData * > * )read: ( long long )page usage: ( int64_t )usage eventType: ( int64_t )eventType eventField: ( int64_t )eventField
{
if( self.client == nil )
{
return @[];
}
NSDictionary * filter =
@{
@"PrimaryUsagePage" : [ NSNumber numberWithLongLong: page ],
@"PrimaryUsage" : [ NSNumber numberWithLongLong: usage ]
};
IOHIDEventSystemClientSetMatching( self.client, ( __bridge CFDictionaryRef )filter );
NSArray * services = CFBridgingRelease( IOHIDEventSystemClientCopyServices( ( IOHIDEventSystemClientRef )( self.client ) ) );
NSMutableDictionary< NSString *, IOHIDData * > * values = [ NSMutableDictionary new ];
for( id o in services )
{
IOHIDServiceClientRef service = ( __bridge IOHIDServiceClientRef )o;
NSString * name = CFBridgingRelease( IOHIDServiceClientCopyProperty( service, CFSTR( "Product" ) ) );
CFTypeRef event = IOHIDServiceClientCopyEvent( service, eventType, 0, 0 );
if( name != nil && event != nil )
{
values[ name ] = [ [ IOHIDData alloc ] initWithName: name value: IOHIDEventGetFloatValue( event, eventField ) ];
}
if( event != nil )
{
CFRelease( event );
}
}
return [ values allValues ];
}
@end

View File

@@ -1,39 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Foundation
@objc
public class IOHIDData: NSObject
{
@objc public dynamic var name: String
@objc public dynamic var value: Double
@objc
public init( name: String, value: Double )
{
self.name = name
self.value = value
}
}

View File

@@ -1,107 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
@import IOKit;
/*
* Reference:
* - https://github.com/apple-oss-distributions/IOKitUser
* - https://opensource.apple.com/source/IOKitUser/
* - https://opensource.apple.com/source/IOKitUser/IOKitUser-647.6/pwr_mgt.subproj/IOPMLibPrivate.c
*/
/* Do not modify - defined by AppleSMC.kext */
enum
{
kSMCKeyNotFound = 0x84
};
/* Do not modify - defined by AppleSMC.kext */
enum
{
kSMCSuccess = 0,
kSMCError = 1
};
/* Do not modify - defined by AppleSMC.kext */
enum
{
kSMCUserClientOpen = 0,
kSMCUserClientClose = 1,
kSMCHandleYPCEvent = 2,
kSMCReadKey = 5,
kSMCWriteKey = 6,
kSMCGetKeyCount = 7,
kSMCGetKeyFromIndex = 8,
kSMCGetKeyInfo = 9
};
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
unsigned char major;
unsigned char minor;
unsigned char build;
unsigned char reserved;
unsigned short release;
}
SMCVersion;
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
uint16_t version;
uint16_t length;
uint32_t cpuPLimit;
uint32_t gpuPLimit;
uint32_t memPLimit;
}
SMCPLimitData;
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
uint32_t dataSize;
uint32_t dataType;
uint8_t dataAttributes;
}
SMCKeyInfoData;
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
uint32_t key;
SMCVersion vers;
SMCPLimitData pLimitData;
SMCKeyInfoData keyInfo;
uint8_t result;
uint8_t status;
uint8_t data8;
uint32_t data32;
uint8_t bytes[ 32 ];
}
SMCParamStruct;
extern const uint32_t kSMCKeyNKEY;
extern const uint32_t kSMCKeyACID;

View File

@@ -1,40 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
@import Foundation;
@class SMCData;
NS_ASSUME_NONNULL_BEGIN
@interface SMC: NSObject
@property( class, nonatomic, readonly ) SMC * shared;
- ( instancetype )init;
- ( NSArray< SMCData * > * )readAllKeys: ( BOOL ( ^ _Nullable )( uint32_t ) )filter;
@end
NS_ASSUME_NONNULL_END

View File

@@ -1,410 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#import "SMC.h"
#import "SMC-Internal.h"
#import "Hot-Swift.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfour-char-constants"
const uint32_t kSMCKeyNKEY = '#KEY';
const uint32_t kSMCKeyACID = 'ACID';
#pragma clang diagnostic push
@import IOKit;
NS_ASSUME_NONNULL_BEGIN
@interface SMC()
@property( nonatomic, readwrite, assign ) io_connect_t connection;
@property( nonatomic, readwrite, strong ) NSMutableArray< NSNumber * > * keys;
@property( nonatomic, readwrite, strong ) NSMutableDictionary< NSNumber *, NSValue * > * keyInfoCache;
+ ( NSError * )errorWithTitle: ( NSString * )title message: ( NSString * )message code: ( NSInteger )code;
- ( BOOL )callSMCFunction: ( uint32_t )function input: ( const SMCParamStruct * )input output: ( SMCParamStruct * )output;
- ( BOOL )readSMCKeyInfo: ( SMCKeyInfoData * )info forKey: ( uint32_t )key;
- ( BOOL )readSMCKey: ( uint32_t * )key atIndex: ( uint32_t )index;
- ( BOOL )readSMCKey: ( uint32_t )key buffer: ( uint8_t * )buffer maxSize: ( uint32_t * )maxSize keyInfo: ( SMCKeyInfoData * _Nullable )keyInfo;
- ( uint32_t )readSMCKeyCount;
- ( uint32_t )readInteger: ( uint8_t * )data size: ( uint32_t )size;
@end
NS_ASSUME_NONNULL_END
@implementation SMC
+ ( SMC * )shared
{
static dispatch_once_t once;
static SMC * instance;
dispatch_once
(
&once,
^( void )
{
instance = [ SMC new ];
}
);
return instance;
}
+ ( NSError * )errorWithTitle: ( NSString * )title message: ( NSString * )message code: ( NSInteger )code
{
NSDictionary * info =
@{
NSLocalizedDescriptionKey: title,
NSLocalizedRecoverySuggestionErrorKey: message
};
return [ [ NSError alloc ] initWithDomain: NSCocoaErrorDomain code: code userInfo: info ];
}
- ( instancetype )init
{
if( ( self = [ super init ] ) )
{
self.keys = [ NSMutableArray new ];
self.keyInfoCache = [ NSMutableDictionary new ];
[ self open: nil ];
}
return self;
}
- ( oneway void )dealloc
{
[ self close ];
}
- ( NSArray< SMCData * > * )readAllKeys: ( BOOL ( ^ _Nullable )( uint32_t ) )filter
{
if( self.connection == IO_OBJECT_NULL )
{
return @[];
}
if( self.keys.count == 0 )
{
uint32_t count = [ self readSMCKeyCount ];
for( uint32_t i = 0; i < count; i++ )
{
uint32_t key = 0;
if( [ self readSMCKey: &key atIndex: i ] == NO )
{
continue;
}
if( key != 0 )
{
[ self.keys addObject: [ NSNumber numberWithUnsignedInt: key ] ];
}
}
}
NSMutableArray< SMCData * > * items = [ [ NSMutableArray alloc ] initWithCapacity: self.keys.count ];
for( NSNumber * key in self.keys )
{
if( filter != nil && filter( key.unsignedIntValue ) == NO )
{
continue;
}
SMCKeyInfoData info;
uint8_t data[ 32 ];
uint32_t size = sizeof( data );
if( [ self readSMCKey: key.unsignedIntValue buffer: data maxSize: &size keyInfo: &info ] == NO )
{
continue;
}
SMCData * item = [ [ SMCData alloc ] initWithKey: key.unsignedIntValue type: info.dataType data: [ NSData dataWithBytes: data length: size ] ];
[ items addObject: item ];
}
return items;
}
- ( BOOL )open: ( NSError * _Nullable __autoreleasing * )error
{
if( self.connection != IO_OBJECT_NULL )
{
return YES;
}
io_service_t smc = IOServiceGetMatchingService( kIOMasterPortDefault, IOServiceMatching( "AppleSMC" ) );
if( smc == IO_OBJECT_NULL )
{
if( error )
{
*( error ) = [ SMC errorWithTitle: @"Cannot Open SMC" message: @"Unable to retrieve the SMC service." code: -1 ];
}
return NO;
}
io_connect_t connection = IO_OBJECT_NULL;
kern_return_t result = IOServiceOpen( smc, mach_task_self(), 0, &connection );
if( result != kIOReturnSuccess || connection == IO_OBJECT_NULL )
{
if( error )
{
*( error ) = [ SMC errorWithTitle: @"Cannot Open SMC" message: @"Unable to open the SMC service." code: -1 ];
}
return NO;
}
self.connection = connection;
return YES;
}
- ( BOOL )close
{
if( self.connection == IO_OBJECT_NULL )
{
return YES;
}
if( IOServiceClose( self.connection ) != kIOReturnSuccess )
{
return false;
}
self.connection = IO_OBJECT_NULL;
return YES;
}
- ( BOOL )callSMCFunction: ( uint32_t )function input: ( const SMCParamStruct * )input output: ( SMCParamStruct * )output
{
size_t inputSize = sizeof( SMCParamStruct );
size_t outputSize = sizeof( SMCParamStruct );
kern_return_t result = IOConnectCallMethod( self.connection, kSMCUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL );
if( result != kIOReturnSuccess )
{
return NO;
}
result = IOConnectCallStructMethod( self.connection, function, input, inputSize, output, &outputSize );
IOConnectCallMethod( self.connection, kSMCUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL );
return result == kIOReturnSuccess;
}
- ( BOOL )readSMCKeyInfo: ( SMCKeyInfoData * )info forKey: ( uint32_t )key
{
if( info == NULL || key == 0 )
{
return NO;
}
{
NSValue * cached = self.keyInfoCache[ [ NSNumber numberWithUnsignedInt: key ] ];
if( cached != nil )
{
*( info ) = *( ( SMCKeyInfoData * )( cached.pointerValue ) );
return YES;
}
}
SMCParamStruct input;
SMCParamStruct output;
bzero( &input, sizeof( SMCParamStruct ) );
bzero( &output, sizeof( SMCParamStruct ) );
input.data8 = kSMCGetKeyInfo;
input.key = key;
if( [ self callSMCFunction: kSMCHandleYPCEvent input: &input output: &output ] == NO )
{
return NO;
}
if( output.result != kSMCSuccess )
{
return NO;
}
*( info ) = output.keyInfo;
{
SMCKeyInfoData * cached = calloc( sizeof( SMCKeyInfoData ), 1 );
if( cached != NULL )
{
*( cached ) = output.keyInfo;
self.keyInfoCache[ [ NSNumber numberWithUnsignedInt: key ] ] = [ NSValue valueWithPointer: cached ];
}
}
return YES;
}
- ( BOOL )readSMCKey: ( uint32_t * )key atIndex: ( uint32_t )index
{
if( key == NULL )
{
return NO;
}
SMCParamStruct input;
SMCParamStruct output;
bzero( &input, sizeof( SMCParamStruct ) );
bzero( &output, sizeof( SMCParamStruct ) );
input.data8 = kSMCGetKeyFromIndex;
input.data32 = index;
if( [ self callSMCFunction: kSMCHandleYPCEvent input: &input output: &output ] == NO )
{
return NO;
}
if( output.result != kSMCSuccess )
{
return NO;
}
*( key ) = output.key;
return YES;
}
- ( BOOL )readSMCKey: ( uint32_t )key buffer: ( uint8_t * )buffer maxSize: ( uint32_t * )maxSize keyInfo: ( SMCKeyInfoData * _Nullable )keyInfo
{
if( key == 0 || buffer == NULL || maxSize == NULL )
{
return NO;
}
SMCKeyInfoData info;
if( [ self readSMCKeyInfo: &info forKey: key ] == NO )
{
return NO;
}
SMCParamStruct input;
SMCParamStruct output;
bzero( &input, sizeof( SMCParamStruct ) );
bzero( &output, sizeof( SMCParamStruct ) );
input.key = key;
input.data8 = kSMCReadKey;
input.keyInfo.dataSize = info.dataSize;
if( [ self callSMCFunction: kSMCHandleYPCEvent input: &input output: &output ] == NO )
{
return NO;
}
if( output.result != kSMCSuccess )
{
return NO;
}
if( *( maxSize ) < info.dataSize )
{
return NO;
}
if( keyInfo != NULL )
{
*( keyInfo ) = info;
}
*( maxSize ) = info.dataSize;
bzero( buffer, *( maxSize ) );
for( uint32_t i = 0; i < info.dataSize; i++ )
{
if( key == kSMCKeyACID )
{
buffer[ i ] = output.bytes[ i ];
}
else
{
buffer[ i ] = output.bytes[ info.dataSize - ( i + 1 ) ];
}
}
return YES;
}
- ( uint32_t )readSMCKeyCount
{
uint8_t data[ 8 ];
uint32_t size = sizeof( data );
bzero( data, size );
if( [ self readSMCKey: kSMCKeyNKEY buffer: data maxSize: &size keyInfo: NULL ] == NO )
{
return 0;
}
return [ self readInteger: data size: size ];
}
- ( uint32_t )readInteger: ( uint8_t * )data size: ( uint32_t )size
{
uint32_t n = 0;
if( size > sizeof( uint32_t ) )
{
return 0;
}
for( uint32_t i = 0; i < size; i++ )
{
n |= ( uint32_t )( data[ i ] ) << ( i * 8 );
}
return n;
}
@end

View File

@@ -1,180 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Foundation
@objc
public class SMCData: NSObject
{
@objc public dynamic var key: UInt32
@objc public dynamic var type: UInt32
@objc public dynamic var data: Data
@objc public dynamic var value: Any?
@objc public var keyName: String
{
SMCData.fourCC( value: self.key )
}
@objc public var typeName: String
{
SMCData.fourCC( value: self.type )
}
@objc
public init( key: UInt32, type: UInt32, data: Data )
{
self.key = key
self.type = type
self.data = data
self.value = SMCData.value( for: data, type: type )
}
private class func fourCC( value: UInt32 ) -> String
{
let c1 = UInt8( ( value >> 24 ) & 0xFF )
let c2 = UInt8( ( value >> 16 ) & 0xFF )
let c3 = UInt8( ( value >> 8 ) & 0xFF )
let c4 = UInt8( ( value >> 0 ) & 0xFF )
return String( format: "%c%c%c%c", c1, c2, c3, c4 )
}
private class func value( for data: Data, type: UInt32 ) -> Any?
{
switch self.fourCC( value: type )
{
case "si8 ": return self.sint8( data: data ).byteSwapped
case "ui8 ": return self.uint8( data: data ).byteSwapped
case "si16": return self.sint16( data: data ).byteSwapped
case "ui16": return self.uint16( data: data ).byteSwapped
case "si32": return self.sint32( data: data ).byteSwapped
case "ui32": return self.uint32( data: data ).byteSwapped
case "si64": return self.sint64( data: data ).byteSwapped
case "ui64": return self.uint64( data: data ).byteSwapped
case "flt ": return self.float32( data: data )
case "ioft": return self.ioFloat( data: data )
case "sp78": return self.sp78( data: data )
case "flag": return data[ 0 ] == 1 ? "True" : "False"
case "ch8*": return String( data: Data( data.reversed() ), encoding: .utf8 )
default: return nil
}
}
private class func sint8( data: Data ) -> Int8
{
Int8( bitPattern: self.uint8( data: data ) )
}
private class func sint16( data: Data ) -> Int16
{
Int16( bitPattern: self.uint16( data: data ) )
}
private class func sint32( data: Data ) -> Int32
{
Int32( bitPattern: self.uint32( data: data ) )
}
private class func sint64( data: Data ) -> Int64
{
Int64( bitPattern: self.uint64( data: data ) )
}
private class func uint8( data: Data ) -> UInt8
{
UInt8( data[ 0 ] )
}
private class func uint16( data: Data ) -> UInt16
{
let u1 = UInt16( data[ 0 ] ) << 8
let u2 = UInt16( data[ 1 ] ) << 0
return u1 | u2
}
private class func uint32( data: Data ) -> UInt32
{
let u1 = UInt32( data[ 0 ] ) << 24
let u2 = UInt32( data[ 1 ] ) << 16
let u3 = UInt32( data[ 2 ] ) << 8
let u4 = UInt32( data[ 3 ] ) << 0
return u1 | u2 | u3 | u4
}
private class func uint64( data: Data ) -> UInt64
{
let u1 = UInt64( data[ 0 ] ) << 56
let u2 = UInt64( data[ 1 ] ) << 48
let u3 = UInt64( data[ 2 ] ) << 40
let u4 = UInt64( data[ 3 ] ) << 32
let u5 = UInt64( data[ 4 ] ) << 24
let u6 = UInt64( data[ 5 ] ) << 16
let u7 = UInt64( data[ 6 ] ) << 8
let u8 = UInt64( data[ 7 ] ) << 0
return u1 | u2 | u3 | u4 | u5 | u6 | u7 | u8
}
private class func float32( data: Data ) -> Float32
{
Float32( bitPattern: self.uint32( data: data ) )
}
private class func float64( data: Data ) -> Float64
{
Float64( bitPattern: self.uint64( data: data ) )
}
private class func ioFloat( data: Data ) -> Double
{
if data.count != 8
{
return 0
}
let u64 = self.uint64( data: data )
let integral = Double( u64 >> 16 )
let mask = pow( 2.0, 16.0 ) - 1
let fractional = Double( u64 & UInt64( mask ) ) / Double( 1 << 16 )
return integral + fractional
}
private class func sp78( data: Data ) -> Double
{
if data.count != 2
{
return 0
}
let b1 = Double( data[ 1 ] & 0x7F )
let b2 = Double( data[ 0 ] ) / Double( 1 << 8 )
return b1 + b2
}
}

View File

@@ -1,50 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
@objc( ArrayIsEmpty )
public class ArrayIsEmpty: ValueTransformer
{
public override class func transformedValueClass() -> AnyClass
{
NSNumber.self
}
public override class func allowsReverseTransformation() -> Bool
{
false
}
public override func transformedValue( _ value: Any? ) -> Any?
{
guard let array = value as? NSArray
else
{
return NSNumber( booleanLiteral: true )
}
return NSNumber( booleanLiteral: array.count == 0 )
}
}

View File

@@ -1,50 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
@objc( ArrayIsNotEmpty )
public class ArrayIsNotEmpty: ValueTransformer
{
public override class func transformedValueClass() -> AnyClass
{
NSNumber.self
}
public override class func allowsReverseTransformation() -> Bool
{
false
}
public override func transformedValue( _ value: Any? ) -> Any?
{
guard let array = value as? NSArray
else
{
return NSNumber( booleanLiteral: false )
}
return NSNumber( booleanLiteral: array.count > 0 )
}
}

View File

@@ -1,142 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner"/>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="c22-O7-iKe">
<rect key="frame" x="0.0" y="0.0" width="245" height="120"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Zhs-tE-zrk">
<rect key="frame" x="0.0" y="100" width="20" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="g2z-r1-gYP"/>
<constraint firstAttribute="width" constant="20" id="kP1-0x-y1M"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="NSApplicationIcon" id="YpG-g1-XTw"/>
<connections>
<binding destination="ek2-AR-oS5" name="value" keyPath="self.sensor" id="EbR-ou-eai">
<dictionary key="options">
<string key="NSValueTransformerName">SensorIcon</string>
</dictionary>
</binding>
</connections>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Vx7-2w-JY2">
<rect key="frame" x="26" y="105" width="28" height="11"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="truncatingTail" title="Label" id="4QE-tU-2iF">
<font key="font" metaFont="miniSystem"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="ek2-AR-oS5" name="toolTip" keyPath="self.sensor.name" id="sk7-rh-Bgb"/>
<binding destination="ek2-AR-oS5" name="value" keyPath="self.sensor.name" id="COB-ax-oMZ"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qyW-PJ-lOk">
<rect key="frame" x="219" y="105" width="28" height="11"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="truncatingTail" title="Label" id="05S-DK-Pm8">
<font key="font" metaFont="miniSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="ek2-AR-oS5" name="toolTip" keyPath="self.sensor.name" id="RUP-1u-HBl"/>
<binding destination="ek2-AR-oS5" name="value" keyPath="self.sensor.last" id="671-ZR-hc1">
<dictionary key="options">
<string key="NSValueTransformerName">SensorValue</string>
</dictionary>
</binding>
</connections>
</textField>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="XSC-DH-60t">
<rect key="frame" x="0.0" y="19" width="245" height="73"/>
</customView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KB3-h4-RKJ">
<rect key="frame" x="-2" y="0.0" width="23" height="11"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="Min:" id="P1F-RJ-VTt">
<font key="font" metaFont="miniSystem"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="WDq-1D-eKf">
<rect key="frame" x="25" y="0.0" width="28" height="11"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="Label" id="pVf-bC-aUU">
<font key="font" metaFont="miniSystem"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="ek2-AR-oS5" name="value" keyPath="self.sensor.min" id="Hz7-WE-4XS">
<dictionary key="options">
<string key="NSValueTransformerName">SensorValue</string>
</dictionary>
</binding>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="PeT-bn-qut">
<rect key="frame" x="190" y="0.0" width="25" height="11"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="Max:" id="piP-vw-2QX">
<font key="font" metaFont="miniSystem"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="zT4-AQ-MeS">
<rect key="frame" x="219" y="0.0" width="28" height="11"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="Label" id="0uv-Pe-gZH">
<font key="font" metaFont="miniSystem"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="ek2-AR-oS5" name="value" keyPath="self.sensor.max" id="q5h-49-6GI">
<dictionary key="options">
<string key="NSValueTransformerName">SensorValue</string>
</dictionary>
</binding>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="qyW-PJ-lOk" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="Vx7-2w-JY2" secondAttribute="trailing" constant="8" symbolic="YES" id="37w-zR-zSG"/>
<constraint firstAttribute="bottom" secondItem="zT4-AQ-MeS" secondAttribute="bottom" id="6Eb-Jb-ktv"/>
<constraint firstItem="zT4-AQ-MeS" firstAttribute="leading" secondItem="PeT-bn-qut" secondAttribute="trailing" constant="8" symbolic="YES" id="6Iv-Zk-l6p"/>
<constraint firstItem="Vx7-2w-JY2" firstAttribute="centerY" secondItem="Zhs-tE-zrk" secondAttribute="centerY" id="E6p-Sp-hhE"/>
<constraint firstItem="Zhs-tE-zrk" firstAttribute="top" secondItem="c22-O7-iKe" secondAttribute="top" id="F4w-Ta-FMp"/>
<constraint firstItem="zT4-AQ-MeS" firstAttribute="centerY" secondItem="PeT-bn-qut" secondAttribute="centerY" id="GLP-jq-o9j"/>
<constraint firstItem="Zhs-tE-zrk" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" id="H4R-eE-jNf"/>
<constraint firstItem="KB3-h4-RKJ" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" id="LlD-cK-jrf"/>
<constraint firstItem="XSC-DH-60t" firstAttribute="top" secondItem="Zhs-tE-zrk" secondAttribute="bottom" constant="8" symbolic="YES" id="RBs-v9-fzB"/>
<constraint firstItem="XSC-DH-60t" firstAttribute="leading" secondItem="c22-O7-iKe" secondAttribute="leading" id="Y8P-AG-Uex"/>
<constraint firstItem="qyW-PJ-lOk" firstAttribute="centerY" secondItem="Vx7-2w-JY2" secondAttribute="centerY" id="ZfP-Ip-Qp3"/>
<constraint firstItem="WDq-1D-eKf" firstAttribute="leading" secondItem="KB3-h4-RKJ" secondAttribute="trailing" constant="8" symbolic="YES" id="bnr-IM-2mn"/>
<constraint firstItem="PeT-bn-qut" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="WDq-1D-eKf" secondAttribute="trailing" constant="8" symbolic="YES" id="dRS-W2-HF3"/>
<constraint firstAttribute="bottom" secondItem="KB3-h4-RKJ" secondAttribute="bottom" id="gjk-x9-oBq"/>
<constraint firstAttribute="trailing" secondItem="zT4-AQ-MeS" secondAttribute="trailing" id="ivM-u5-F81"/>
<constraint firstItem="WDq-1D-eKf" firstAttribute="centerY" secondItem="KB3-h4-RKJ" secondAttribute="centerY" id="k8I-Sa-B0p"/>
<constraint firstAttribute="trailing" secondItem="XSC-DH-60t" secondAttribute="trailing" id="ma2-2p-gXZ"/>
<constraint firstItem="Vx7-2w-JY2" firstAttribute="leading" secondItem="Zhs-tE-zrk" secondAttribute="trailing" constant="8" symbolic="YES" id="pSn-l6-1WW"/>
<constraint firstItem="KB3-h4-RKJ" firstAttribute="top" secondItem="XSC-DH-60t" secondAttribute="bottom" constant="8" symbolic="YES" id="v2T-jr-FYT"/>
<constraint firstAttribute="trailing" secondItem="qyW-PJ-lOk" secondAttribute="trailing" id="zrr-cs-S3r"/>
</constraints>
<point key="canvasLocation" x="26.5" y="125"/>
</customView>
<collectionViewItem id="ek2-AR-oS5" customClass="SensorItem" customModule="Sensors" customModuleProvider="target">
<connections>
<outlet property="graphContainer" destination="XSC-DH-60t" id="FUo-iJ-Gkw"/>
<outlet property="view" destination="c22-O7-iKe" id="W6K-LU-Klf"/>
</connections>
</collectionViewItem>
</objects>
<resources>
<image name="NSApplicationIcon" width="32" height="32"/>
</resources>
</document>

View File

@@ -1,335 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="SensorsWindowController" customModule="Sensors" customModuleProvider="target">
<connections>
<outlet property="arrayController" destination="k4f-4o-be4" id="F6X-Lo-Fc0"/>
<outlet property="collectionView" destination="d8j-id-ziA" id="tbm-Yo-sK6"/>
<outlet property="window" destination="QvC-M9-y7g" id="3Jc-9C-AuF"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Sensors" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="MainWindow" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="800" height="515"/>
<rect key="screenRect" x="0.0" y="0.0" width="1710" height="1069"/>
<value key="minSize" type="size" width="800" height="515"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="515"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<visualEffectView blendingMode="behindWindow" material="underWindowBackground" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="uRj-rz-hcT">
<rect key="frame" x="0.0" y="0.0" width="800" height="515"/>
<subviews>
<scrollView wantsLayer="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aKe-JS-2Ui">
<rect key="frame" x="20" y="132" width="760" height="353"/>
<clipView key="contentView" drawsBackground="NO" id="zVN-hJ-YmX">
<rect key="frame" x="0.0" y="0.0" width="760" height="353"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<collectionView id="d8j-id-ziA">
<rect key="frame" x="0.0" y="0.0" width="760" height="353"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumInteritemSpacing="10" minimumLineSpacing="10" id="jv5-sj-5QH">
<size key="itemSize" width="245" height="120"/>
</collectionViewFlowLayout>
<color key="primaryBackgroundColor" white="1" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<binding destination="k4f-4o-be4" name="content" keyPath="arrangedObjects" id="WfZ-ms-k8f"/>
<binding destination="k4f-4o-be4" name="selectionIndexes" keyPath="selectionIndexes" previousBinding="WfZ-ms-k8f" id="JRi-HO-Ojp"/>
<outlet property="dataSource" destination="-2" id="BJq-MM-cYl"/>
</connections>
</collectionView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="pbH-A9-JB1">
<rect key="frame" x="-100" y="-100" width="233" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="F9Y-Pq-ygs">
<rect key="frame" x="744" y="0.0" width="16" height="303"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<connections>
<binding destination="-2" name="hidden" keyPath="self.sensors.data" id="CrI-nj-hKU">
<dictionary key="options">
<string key="NSValueTransformerName">ArrayIsEmpty</string>
</dictionary>
</binding>
</connections>
</scrollView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="X4f-ON-Yh7">
<rect key="frame" x="0.0" y="0.0" width="800" height="132"/>
<subviews>
<searchField wantsLayer="YES" verticalHuggingPriority="750" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0b0-bM-ppa">
<rect key="frame" x="20" y="90" width="760" height="22"/>
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="m6w-FG-kg5">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</searchFieldCell>
<connections>
<binding destination="-2" name="value" keyPath="self.searchText" id="n2O-a4-5b5">
<dictionary key="options">
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
</dictionary>
</binding>
</connections>
</searchField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CWx-dr-5aC">
<rect key="frame" x="18" y="51" width="103" height="18"/>
<buttonCell key="cell" type="check" title="Temperature" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="lZo-Np-2Ev">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showTemperature" id="IqV-HK-3FM"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YH9-KV-isM">
<rect key="frame" x="127" y="51" width="72" height="18"/>
<buttonCell key="cell" type="check" title="Voltage" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="7Kn-WX-eN1">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showVoltage" id="SEA-Tu-BOl"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="DL0-ry-nBa">
<rect key="frame" x="205" y="51" width="72" height="18"/>
<buttonCell key="cell" type="check" title="Current" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="WBA-tr-bDK">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showCurrent" id="McY-1z-eLE"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wh8-P7-8p4">
<rect key="frame" x="610" y="52" width="79" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Graph Style:" id="6Ty-8X-UI6">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="b2Z-bC-lIL">
<rect key="frame" x="692" y="46" width="92" height="25"/>
<popUpButtonCell key="cell" type="push" title="Gradient" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="UpT-Zz-emE" id="ToP-qb-kLc">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="bNn-yW-MVT">
<items>
<menuItem title="Gradient" state="on" id="UpT-Zz-emE"/>
<menuItem title="Line" tag="1" id="VP7-OH-4an"/>
<menuItem title="Fill" tag="2" id="Uix-Lw-WIT"/>
<menuItem title="Bars" tag="3" id="j4P-bQ-osF"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<binding destination="-2" name="selectedTag" keyPath="self.graphStyle" id="LYW-IL-Fda"/>
</connections>
</popUpButton>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AZ7-l5-9da">
<rect key="frame" x="18" y="21" width="62" height="18"/>
<buttonCell key="cell" type="check" title="IOHID" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="B30-xT-MxH">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showIOHID" id="BgH-kZ-wRG"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wQZ-5m-sLD">
<rect key="frame" x="86" y="21" width="55" height="18"/>
<buttonCell key="cell" type="check" title="SMC" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="lBw-Xe-W5E">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showSMC" id="vG2-nh-ynR"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AW4-o1-MSW">
<rect key="frame" x="637" y="22" width="52" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Sort by:" id="Zhd-oD-x9y">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton wantsLayer="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="YK3-dt-Gbg">
<rect key="frame" x="692" y="16" width="92" height="25"/>
<popUpButtonCell key="cell" type="push" title="Name" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="hmc-dx-TSW" id="zN2-s4-vqC">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="WXZ-C2-QB6">
<items>
<menuItem title="Name" state="on" id="hmc-dx-TSW"/>
<menuItem title="Value" id="Xek-ZI-v6u"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<binding destination="-2" name="selectedIndex" keyPath="self.sorting" id="x1p-2T-J5c"/>
</connections>
</popUpButton>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="YK3-dt-Gbg" secondAttribute="bottom" constant="20" symbolic="YES" id="5rr-n1-gE9"/>
<constraint firstItem="0b0-bM-ppa" firstAttribute="leading" secondItem="X4f-ON-Yh7" secondAttribute="leading" constant="20" symbolic="YES" id="7Hg-zM-lO0"/>
<constraint firstItem="YH9-KV-isM" firstAttribute="centerY" secondItem="CWx-dr-5aC" secondAttribute="centerY" id="DiY-62-WNM"/>
<constraint firstItem="AZ7-l5-9da" firstAttribute="leading" secondItem="X4f-ON-Yh7" secondAttribute="leading" constant="20" symbolic="YES" id="Kg6-oj-ya0"/>
<constraint firstItem="0b0-bM-ppa" firstAttribute="top" secondItem="X4f-ON-Yh7" secondAttribute="top" constant="20" symbolic="YES" id="MLt-9Q-NWw"/>
<constraint firstItem="wQZ-5m-sLD" firstAttribute="leading" secondItem="AZ7-l5-9da" secondAttribute="trailing" constant="8" symbolic="YES" id="TAj-3M-Ri4"/>
<constraint firstItem="wh8-P7-8p4" firstAttribute="centerY" secondItem="DL0-ry-nBa" secondAttribute="centerY" id="TS8-6H-T7P"/>
<constraint firstItem="DL0-ry-nBa" firstAttribute="centerY" secondItem="YH9-KV-isM" secondAttribute="centerY" id="UFB-Be-d69"/>
<constraint firstItem="b2Z-bC-lIL" firstAttribute="leading" secondItem="wh8-P7-8p4" secondAttribute="trailing" constant="8" symbolic="YES" id="V4o-Be-jIe"/>
<constraint firstItem="AW4-o1-MSW" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="wQZ-5m-sLD" secondAttribute="trailing" constant="8" symbolic="YES" id="YkP-QE-ySV"/>
<constraint firstItem="YK3-dt-Gbg" firstAttribute="leading" secondItem="AW4-o1-MSW" secondAttribute="trailing" constant="8" symbolic="YES" id="Yp3-Ns-Xe4"/>
<constraint firstItem="wQZ-5m-sLD" firstAttribute="centerY" secondItem="AW4-o1-MSW" secondAttribute="centerY" id="hsM-d4-60o"/>
<constraint firstItem="CWx-dr-5aC" firstAttribute="leading" secondItem="X4f-ON-Yh7" secondAttribute="leading" constant="20" symbolic="YES" id="kHN-fy-wU3"/>
<constraint firstItem="DL0-ry-nBa" firstAttribute="leading" secondItem="YH9-KV-isM" secondAttribute="trailing" constant="8" symbolic="YES" id="kXC-gz-rYd"/>
<constraint firstItem="YK3-dt-Gbg" firstAttribute="width" secondItem="b2Z-bC-lIL" secondAttribute="width" id="loy-q5-zWp"/>
<constraint firstAttribute="trailing" secondItem="YK3-dt-Gbg" secondAttribute="trailing" constant="20" symbolic="YES" id="m9H-b7-C5r"/>
<constraint firstItem="b2Z-bC-lIL" firstAttribute="top" secondItem="0b0-bM-ppa" secondAttribute="bottom" constant="20" symbolic="YES" id="nmc-VG-jfo"/>
<constraint firstItem="wh8-P7-8p4" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="DL0-ry-nBa" secondAttribute="trailing" constant="8" symbolic="YES" id="obO-Av-PNp"/>
<constraint firstItem="AW4-o1-MSW" firstAttribute="centerY" secondItem="YK3-dt-Gbg" secondAttribute="centerY" id="rQy-7z-w4x"/>
<constraint firstItem="YH9-KV-isM" firstAttribute="leading" secondItem="CWx-dr-5aC" secondAttribute="trailing" constant="8" symbolic="YES" id="sOb-Yn-u3A"/>
<constraint firstAttribute="trailing" secondItem="0b0-bM-ppa" secondAttribute="trailing" constant="20" symbolic="YES" id="vhy-3U-orM"/>
<constraint firstAttribute="trailing" secondItem="b2Z-bC-lIL" secondAttribute="trailing" constant="20" symbolic="YES" id="vmq-Sh-oFu"/>
<constraint firstItem="b2Z-bC-lIL" firstAttribute="centerY" secondItem="wh8-P7-8p4" secondAttribute="centerY" id="wRu-AK-pi5"/>
<constraint firstItem="YK3-dt-Gbg" firstAttribute="top" secondItem="b2Z-bC-lIL" secondAttribute="bottom" constant="10" symbolic="YES" id="ykj-lk-t0n"/>
<constraint firstItem="wQZ-5m-sLD" firstAttribute="centerY" secondItem="AZ7-l5-9da" secondAttribute="centerY" id="zw8-PQ-uUL"/>
</constraints>
<connections>
<binding destination="-2" name="hidden" keyPath="self.sensors.data" id="oYT-Hj-xEu">
<dictionary key="options">
<string key="NSValueTransformerName">ArrayIsEmpty</string>
</dictionary>
</binding>
</connections>
</customView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Asg-vC-Nsi">
<rect key="frame" x="252" y="69" width="296" height="378"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yFI-k2-eyH">
<rect key="frame" x="20" y="102" width="256" height="256"/>
<constraints>
<constraint firstAttribute="height" constant="256" id="3bQ-I0-4D7"/>
<constraint firstAttribute="width" constant="256" id="wmc-Wj-n9C"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="NSApplicationIcon" id="ccv-7E-1yf"/>
</imageView>
<stackView distribution="fill" orientation="vertical" alignment="centerX" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G4l-pP-k1k">
<rect key="frame" x="20" y="20" width="256" height="74"/>
<subviews>
<progressIndicator wantsLayer="YES" maxValue="100" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="Rc4-Fm-hWF">
<rect key="frame" x="112" y="42" width="32" height="32"/>
<connections>
<binding destination="-2" name="animate" keyPath="self.sensors.loading" id="dyi-wq-mTf"/>
<binding destination="-2" name="hidden" keyPath="self.sensors.loading" id="OKR-as-1bb">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
</progressIndicator>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="caY-ih-a0p">
<rect key="frame" x="44" y="21" width="168" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="No sensor data available..." id="dA5-eI-Kva">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="hidden" keyPath="self.sensors.loading" id="RA3-Mq-TR1"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="b8F-vc-SdM">
<rect key="frame" x="68" y="0.0" width="120" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Reading sensors..." id="ieL-sj-MN9">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="-2" name="hidden" keyPath="self.sensors.loading" id="R2q-Da-hsc">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
</textField>
</subviews>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<constraints>
<constraint firstItem="yFI-k2-eyH" firstAttribute="leading" secondItem="Asg-vC-Nsi" secondAttribute="leading" constant="20" symbolic="YES" id="6hv-WO-Mp2"/>
<constraint firstAttribute="trailing" secondItem="G4l-pP-k1k" secondAttribute="trailing" constant="20" symbolic="YES" id="Ff2-Ea-C3q"/>
<constraint firstItem="G4l-pP-k1k" firstAttribute="top" secondItem="yFI-k2-eyH" secondAttribute="bottom" constant="8" symbolic="YES" id="HJL-Tq-Tud"/>
<constraint firstItem="G4l-pP-k1k" firstAttribute="leading" secondItem="Asg-vC-Nsi" secondAttribute="leading" constant="20" symbolic="YES" id="afE-6R-eXF"/>
<constraint firstAttribute="bottom" secondItem="G4l-pP-k1k" secondAttribute="bottom" constant="20" symbolic="YES" id="dJQ-em-oKz"/>
<constraint firstAttribute="trailing" secondItem="yFI-k2-eyH" secondAttribute="trailing" constant="20" symbolic="YES" id="isW-X4-uYe"/>
<constraint firstItem="yFI-k2-eyH" firstAttribute="top" secondItem="Asg-vC-Nsi" secondAttribute="top" constant="20" symbolic="YES" id="woG-6u-Efg"/>
</constraints>
<connections>
<binding destination="-2" name="hidden" keyPath="self.sensors.data" id="nDO-gY-oWD">
<dictionary key="options">
<string key="NSValueTransformerName">ArrayIsNotEmpty</string>
</dictionary>
</binding>
</connections>
</customView>
</subviews>
<constraints>
<constraint firstItem="X4f-ON-Yh7" firstAttribute="top" secondItem="aKe-JS-2Ui" secondAttribute="bottom" id="5IN-cs-jqm"/>
<constraint firstItem="Asg-vC-Nsi" firstAttribute="centerX" secondItem="uRj-rz-hcT" secondAttribute="centerX" id="961-zO-gq7"/>
<constraint firstItem="aKe-JS-2Ui" firstAttribute="leading" secondItem="uRj-rz-hcT" secondAttribute="leading" constant="20" symbolic="YES" id="K0o-wa-efC"/>
<constraint firstAttribute="bottom" secondItem="X4f-ON-Yh7" secondAttribute="bottom" id="L6P-Pp-IP7"/>
<constraint firstAttribute="trailing" secondItem="X4f-ON-Yh7" secondAttribute="trailing" id="Lxr-7P-w7M"/>
<constraint firstAttribute="trailing" secondItem="aKe-JS-2Ui" secondAttribute="trailing" constant="20" symbolic="YES" id="RZP-rx-Xju"/>
<constraint firstItem="aKe-JS-2Ui" firstAttribute="top" secondItem="uRj-rz-hcT" secondAttribute="top" constant="30" id="b5q-1K-Vb2"/>
<constraint firstItem="X4f-ON-Yh7" firstAttribute="leading" secondItem="uRj-rz-hcT" secondAttribute="leading" id="ffA-eK-qjQ"/>
<constraint firstItem="Asg-vC-Nsi" firstAttribute="centerY" secondItem="uRj-rz-hcT" secondAttribute="centerY" id="hRR-yE-RmG"/>
</constraints>
</visualEffectView>
</subviews>
<constraints>
<constraint firstItem="uRj-rz-hcT" firstAttribute="top" secondItem="EiT-Mj-1SZ" secondAttribute="top" id="WwN-si-Yl6"/>
<constraint firstAttribute="trailing" secondItem="uRj-rz-hcT" secondAttribute="trailing" id="eKa-0b-qZ9"/>
<constraint firstItem="uRj-rz-hcT" firstAttribute="leading" secondItem="EiT-Mj-1SZ" secondAttribute="leading" id="f7k-yq-eVb"/>
<constraint firstAttribute="bottom" secondItem="uRj-rz-hcT" secondAttribute="bottom" id="v4a-ky-3o2"/>
</constraints>
</view>
<point key="canvasLocation" x="-110" y="144"/>
</window>
<arrayController selectsInsertedObjects="NO" avoidsEmptySelection="NO" clearsFilterPredicateOnInsertion="NO" automaticallyRearrangesObjects="YES" id="k4f-4o-be4">
<connections>
<binding destination="-2" name="contentArray" keyPath="self.sensors.data" id="V1H-EA-tCm"/>
</connections>
</arrayController>
</objects>
<resources>
<image name="NSApplicationIcon" width="32" height="32"/>
</resources>
</document>

View File

@@ -1,41 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
public class Colors
{
public class func color( for kind: SensorHistoryData.Kind ) -> NSColor
{
switch kind
{
case .thermal: return NSColor.systemOrange
case .voltage: return NSColor.systemPurple
case .current: return NSColor.systemTeal
}
}
private init()
{}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,47 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
public extension NSImage
{
func tinted( with color: NSColor ) -> NSImage
{
guard let copy = self.copy() as? NSImage
else
{
return self
}
copy.isTemplate = false
let rect = NSRect( origin: NSZeroPoint, size: copy.size )
copy.lockFocus()
color.set()
rect.fill( using: .sourceAtop )
copy.unlockFocus()
return copy
}
}

View File

@@ -1,241 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
public class SensorGraphView: NSView
{
@objc
public enum GraphStyle: Int
{
case gradient
case line
case fill
case bars
}
@objc public dynamic var sensor: SensorHistoryData?
private var defaultsObserver: Any?
public override init( frame: NSRect )
{
super.init( frame: frame )
self.defaultsObserver = NotificationCenter.default.addObserver( forName: UserDefaults.didChangeNotification, object: nil, queue: nil )
{
[ weak self ] _ in self?.needsDisplay = true
}
}
required init?( coder: NSCoder )
{
super.init( coder: coder )
self.defaultsObserver = NotificationCenter.default.addObserver( forName: UserDefaults.didChangeNotification, object: nil, queue: nil )
{
[ weak self ] _ in self?.needsDisplay = true
}
}
public override func draw( _ rect: NSRect )
{
let style = GraphStyle( rawValue: UserDefaults.standard.integer( forKey: "sensorsWindowGraphStyle" ) ) ?? .bars
self.drawBorder( in: rect, style: style )
self.drawBackground( in: rect, style: style )
guard let sensor = self.sensor, sensor.values.count >= 2
else
{
return
}
let values = sensor.values.map { CGFloat( $0.doubleValue ) }
var min: CGFloat = values.min() ?? 0
var max: CGFloat = values.max() ?? 0
if sensor.kind == .thermal, min >= 0, max <= 100
{
min = 0
max = 100
}
if style == .bars
{
self.drawBars(
in: rect,
kind: sensor.kind,
values: values,
min: min,
max: max,
color: Colors.color( for: sensor.kind )
)
}
else
{
self.drawGraph(
in: rect.insetBy( dx: 10, dy: 10 ),
kind: sensor.kind,
values: values,
min: min,
max: max,
color: Colors.color( for: sensor.kind ),
style: style
)
}
}
private func drawBorder( in rect: NSRect, style: GraphStyle )
{
if style == .bars
{
return
}
let border = NSBezierPath( roundedRect: rect.insetBy( dx: 1, dy: 1 ), xRadius: 10, yRadius: 10 )
border.lineWidth = 1
NSColor.gray.setStroke()
border.stroke()
}
private func drawBackground( in rect: NSRect, style: GraphStyle )
{
if style == .bars
{
let c = 15
let h = rect.size.height / CGFloat( c )
let n = rect.size.width / h
for i in 0 ..< Int( n )
{
for j in 0 ..< c
{
let square = NSRect( x: rect.origin.x + h * CGFloat( i ), y: rect.origin.y + h * CGFloat( j ), width: h, height: h ).insetBy( dx: 1, dy: 1 )
NSColor.gray.withAlphaComponent( 0.2 ).setFill()
square.fill()
}
}
}
else
{
let border = NSBezierPath( roundedRect: rect.insetBy( dx: 1, dy: 1 ), xRadius: 10, yRadius: 10 )
NSColor.gray.withAlphaComponent( 0.2 ).setFill()
border.fill()
}
}
private func drawGraph( in rect: NSRect, kind: SensorHistoryData.Kind, values: [ CGFloat ], min: CGFloat, max: CGFloat, color: NSColor, style: GraphStyle )
{
let p1 = NSBezierPath()
let p2 = NSBezierPath()
p1.lineWidth = 1
p2.lineWidth = 0
if min == max, kind != .thermal
{
p1.move( to: NSPoint( x: rect.origin.x, y: rect.origin.y + rect.size.height / 2 ) )
p1.line( to: NSPoint( x: rect.origin.x + rect.size.width, y: rect.origin.y + rect.size.height / 2 ) )
p2.move( to: NSPoint( x: rect.origin.x, y: rect.origin.y + rect.size.height / 2 ) )
p2.line( to: NSPoint( x: rect.origin.x + rect.size.width, y: rect.origin.y + rect.size.height / 2 ) )
}
else
{
for i in 0 ..< values.count
{
let value = values[ i ]
let dx = rect.size.width / CGFloat( values.count - 1 )
let x = rect.origin.x + CGFloat( i ) * dx
let v = ( value - min ) / ( max - min )
let y = rect.origin.y + v * rect.size.height
if i == 0
{
p1.move( to: NSPoint( x: x, y: y ) )
p2.move( to: NSPoint( x: x, y: y ) )
}
else
{
p1.line( to: NSPoint( x: x, y: y ) )
p2.line( to: NSPoint( x: x, y: y ) )
}
}
}
p2.line( to: NSPoint( x: rect.origin.x + rect.size.width, y: rect.origin.y - 3 ) )
p2.line( to: NSPoint( x: rect.origin.x, y: rect.origin.y - 3 ) )
p2.close()
if style == .gradient
{
let gradient = NSGradient( colors: [ color.withAlphaComponent( 0.25 ), color.withAlphaComponent( 0 ) ] )
gradient?.draw( in: p2, angle: -90 )
}
else if style == .fill
{
color.setFill()
p2.fill()
}
color.setStroke()
p1.stroke()
}
private func drawBars( in rect: NSRect, kind: SensorHistoryData.Kind, values: [ CGFloat ], min: CGFloat, max: CGFloat, color: NSColor )
{
let c = 15
let h = rect.size.height / CGFloat( c )
let n = rect.size.width / h
let values = Array( values.suffix( Int( n ) ) )
for i in 0 ..< Int( n )
{
if i >= values.count
{
return
}
let v = values[ i ]
let p = ( v - min ) / ( max - min )
for j in 0 ..< c
{
if CGFloat( j ) / CGFloat( c ) > p
{
break
}
let square = NSRect( x: rect.origin.x + h * CGFloat( i ), y: rect.origin.y + h * CGFloat( j ), width: h, height: h ).insetBy( dx: 1, dy: 1 )
color.setFill()
square.fill()
}
}
}
}

View File

@@ -1,161 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Foundation
@objc
public class SensorHistoryData: NSObject, Synchronizable
{
@objc( SensorHistoryDataKind )
public enum Kind: Int, CustomStringConvertible
{
case thermal
case voltage
case current
public var description: String
{
switch self
{
case .thermal: return "thermal"
case .voltage: return "voltage"
case .current: return "current"
}
}
}
@objc( SensorHistoryDataSource )
public enum Source: Int, CustomStringConvertible
{
case hid
case smc
public var description: String
{
switch self
{
case .hid: return "IOHID"
case .smc: return "SMC"
}
}
}
@objc public private( set ) dynamic var source: Source
@objc public private( set ) dynamic var kind: Kind
@objc public private( set ) dynamic var name: String
private var data: [ Double ] = []
@objc public dynamic var values: [ NSNumber ]
{
return self.synchronized
{
return self.data.map { NSNumber( floatLiteral: $0 ) }
}
}
@objc public dynamic var min: NSNumber?
{
return self.synchronized
{
guard let max = self.data.min()
else
{
return nil
}
return NSNumber( floatLiteral: max )
}
}
@objc public dynamic var max: NSNumber?
{
return self.synchronized
{
guard let min = self.data.max()
else
{
return nil
}
return NSNumber( floatLiteral: min )
}
}
@objc public dynamic var last: NSNumber?
{
return self.synchronized
{
guard let last = self.data.last
else
{
return nil
}
return NSNumber( floatLiteral: last )
}
}
@objc
public init( source: Source, kind: Kind, name: String )
{
self.source = source
self.kind = kind
self.name = name
}
@objc( addValue: )
public func add( value: Double )
{
self.synchronized
{
var data = self.data
data.append( value )
self.data = data.suffix( 50 )
DispatchQueue.main.async
{
self.willChangeValue( for: \.values )
self.willChangeValue( for: \.min )
self.willChangeValue( for: \.max )
self.willChangeValue( for: \.last )
self.didChangeValue( for: \.values )
self.didChangeValue( for: \.min )
self.didChangeValue( for: \.max )
self.didChangeValue( for: \.last )
}
}
}
public override var description: String
{
let min = String( format: "%.2f", self.min?.doubleValue ?? 0 )
let max = String( format: "%.2f", self.max?.doubleValue ?? 0 )
return "\( super.description ): \( self.name ) (\( self.kind ), min: \( min ), max: \( max ))"
}
}

View File

@@ -1,55 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
@objc( SensorIcon )
public class SensorIcon: ValueTransformer
{
public override class func transformedValueClass() -> AnyClass
{
NSImage.self
}
public override class func allowsReverseTransformation() -> Bool
{
false
}
public override func transformedValue( _ value: Any? ) -> Any?
{
guard let data = value as? SensorHistoryData
else
{
return nil
}
switch data.kind
{
case .thermal: return NSImage( named: "ThermalTemplate" )?.tinted( with: Colors.color( for: data.kind ) )
case .voltage: return NSImage( named: "VoltageTemplate" )?.tinted( with: Colors.color( for: data.kind ) )
case .current: return NSImage( named: "CurrentTemplate" )?.tinted( with: Colors.color( for: data.kind ) )
}
}
}

View File

@@ -1,54 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
public class SensorItem: NSCollectionViewItem
{
@objc public dynamic var sensor: SensorHistoryData?
{
didSet
{
self.graph.sensor = self.sensor
}
}
private var graph = SensorGraphView()
@IBOutlet private var graphContainer: NSView!
public override func viewDidLoad()
{
super.viewDidLoad()
self.graph.translatesAutoresizingMaskIntoConstraints = false
self.graph.frame = self.graphContainer.bounds
self.graphContainer.addSubview( self.graph )
self.graphContainer.addConstraint( NSLayoutConstraint( item: self.graph, attribute: .width, relatedBy: .equal, toItem: self.graphContainer, attribute: .width, multiplier: 1, constant: 0 ) )
self.graphContainer.addConstraint( NSLayoutConstraint( item: self.graph, attribute: .height, relatedBy: .equal, toItem: self.graphContainer, attribute: .height, multiplier: 1, constant: 0 ) )
self.graphContainer.addConstraint( NSLayoutConstraint( item: self.graph, attribute: .centerX, relatedBy: .equal, toItem: self.graphContainer, attribute: .centerX, multiplier: 1, constant: 0 ) )
self.graphContainer.addConstraint( NSLayoutConstraint( item: self.graph, attribute: .centerY, relatedBy: .equal, toItem: self.graphContainer, attribute: .centerY, multiplier: 1, constant: 0 ) )
}
}

View File

@@ -1,50 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
@objc( SensorValue )
public class SensorValue: ValueTransformer
{
public override class func transformedValueClass() -> AnyClass
{
NSString.self
}
public override class func allowsReverseTransformation() -> Bool
{
false
}
public override func transformedValue( _ value: Any? ) -> Any?
{
guard let n = value as? NSNumber
else
{
return "--"
}
return String( format: "%.02f", n.doubleValue )
}
}

View File

@@ -1,150 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
@objc
public class Sensors: NSObject
{
@objc public private( set ) dynamic var loading = true
@objc public private( set ) dynamic var data = [ SensorHistoryData ]()
@objc private dynamic var sensors = [ String: SensorHistoryData ]()
private var shouldRun = true
private var completion: ( () -> Void )?
public override init()
{
super.init()
DispatchQueue.global( qos: .background ).async
{
self.run()
}
}
public func stop( completion: ( () -> Void )? )
{
if self.shouldRun == false
{
return
}
self.completion = completion
self.shouldRun = false
}
private func run()
{
let timer = Timer.scheduledTimer( withTimeInterval: 1, repeats: true )
{
_ in self.readSensors()
}
self.readSensors()
RunLoop.current.add( timer, forMode: .default )
while self.shouldRun
{
RunLoop.current.run( until: Date( timeIntervalSinceNow: 5 ) )
}
timer.invalidate()
let completion = self.completion
self.completion = nil
self.data = []
completion?()
}
private func readSensors()
{
self.readIOHIDSensors()
self.readSMCSensors()
let sensors = self.sensors
DispatchQueue.main.async
{
self.data = [ SensorHistoryData ]( sensors.values )
self.loading = false
}
}
private func readIOHIDSensors()
{
IOHID.shared.readTemperatureSensors().forEach { self.addSensorHistoryData( data: $0, kind: .thermal ) }
IOHID.shared.readVoltageSensors().forEach { self.addSensorHistoryData( data: $0, kind: .voltage ) }
IOHID.shared.readCurrentSensors().forEach { self.addSensorHistoryData( data: $0, kind: .current ) }
}
private func readSMCSensors()
{
let all = SMC.shared.readAllKeys()
all.filter { $0.keyName.hasPrefix( "T" ) }.forEach { self.addSensorHistoryData( data: $0, kind: .thermal ) }
all.filter { $0.keyName.hasPrefix( "V" ) }.forEach { self.addSensorHistoryData( data: $0, kind: .voltage ) }
all.filter { $0.keyName.hasPrefix( "I" ) }.forEach { self.addSensorHistoryData( data: $0, kind: .current ) }
}
private func addSensorHistoryData( data: IOHIDData, kind: SensorHistoryData.Kind )
{
let key = String( format: "IOHID.%llu.%@", kind.rawValue, data.name )
if self.sensors[ key ] == nil
{
self.sensors[ key ] = SensorHistoryData( source: .hid, kind: kind, name: data.name )
}
self.sensors[ key ]?.add( value: data.value )
}
private func addSensorHistoryData( data: SMCData, kind: SensorHistoryData.Kind )
{
let value: Double
if let f = data.value as? Double
{
value = f
}
else if let f = data.value as? Float32
{
value = Double( f )
}
else
{
return
}
let key = String( format: "SMC.%llu.%@", kind.rawValue, data.keyName )
if self.sensors[ key ] == nil
{
self.sensors[ key ] = SensorHistoryData( source: .smc, kind: kind, name: data.keyName )
}
self.sensors[ key ]?.add( value: value )
}
}

View File

@@ -1,199 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
public class SensorsWindowController: NSWindowController
{
@objc private dynamic var sensors = Sensors()
@objc private dynamic var showTemperature = UserDefaults.standard.object( forKey: "sensorsWindowShowTemperature" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showTemperature, forKey: "sensorsWindowShowTemperature" )
}
}
@objc private dynamic var showVoltage = UserDefaults.standard.object( forKey: "sensorsWindowShowVoltage" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showVoltage, forKey: "sensorsWindowShowVoltage" )
}
}
@objc private dynamic var showCurrent = UserDefaults.standard.object( forKey: "sensorsWindowShowCurrent" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showCurrent, forKey: "sensorsWindowShowCurrent" )
}
}
@objc private dynamic var showIOHID = UserDefaults.standard.object( forKey: "sensorsWindowShowIOHID" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showIOHID, forKey: "sensorsWindowShowIOHID" )
}
}
@objc private dynamic var showSMC = UserDefaults.standard.object( forKey: "sensorsWindowShowSMC" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showSMC, forKey: "sensorsWindowShowSMC" )
}
}
@objc private dynamic var sorting = UserDefaults.standard.integer( forKey: "sensorsWindowSorting" )
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.sorting, forKey: "sensorsWindowSorting" )
}
}
@objc private dynamic var searchText: String?
{
didSet { self.updateFilters() }
}
@objc private dynamic var graphStyle = UserDefaults.standard.integer( forKey: "sensorsWindowGraphStyle" )
{
didSet
{
UserDefaults.standard.set( self.graphStyle, forKey: "sensorsWindowGraphStyle" )
}
}
@IBOutlet private var collectionView: NSCollectionView!
@IBOutlet private var arrayController: NSArrayController!
public override var windowNibName: NSNib.Name?
{
"SensorsWindowController"
}
public override func windowDidLoad()
{
super.windowDidLoad()
self.arrayController.sortDescriptors = [ NSSortDescriptor( key: "name", ascending: true, selector: #selector( NSString.localizedCaseInsensitiveCompare( _: ) ) ) ]
self.updateFilters()
}
public func stop( completion: ( () -> Void )? )
{
self.sensors.stop( completion: completion )
}
private func updateFilters()
{
var predicates = [ NSPredicate ]()
if self.showTemperature == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.kind != .thermal } )
}
if self.showVoltage == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.kind != .voltage } )
}
if self.showCurrent == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.kind != .current } )
}
if self.showIOHID == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.source != .hid } )
}
if self.showSMC == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.source != .smc } )
}
if let search = self.searchText, search.count > 0
{
predicates.append( NSPredicate( format: "name contains[c] %@", search ) )
}
let descriptors =
[
NSSortDescriptor( key: "name", ascending: true, selector: #selector( NSString.localizedCaseInsensitiveCompare( _: ) ) ),
NSSortDescriptor( key: "last", ascending: false ),
]
self.arrayController.sortDescriptors = self.sorting == 1 ? descriptors.reversed() : descriptors
if predicates.count > 0
{
self.arrayController.filterPredicate = NSCompoundPredicate( andPredicateWithSubpredicates: predicates )
}
else
{
self.arrayController.filterPredicate = nil
}
}
}
extension SensorsWindowController: NSCollectionViewDataSource
{
public func numberOfSections( in collectionView: NSCollectionView ) -> Int
{
1
}
public func collectionView( _ collectionView: NSCollectionView, numberOfItemsInSection section: Int ) -> Int
{
( self.arrayController.arrangedObjects as? [ SensorHistoryData ] )?.count ?? 0
}
public func collectionView( _ itemForRepresentedObjectAtcollectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath ) -> NSCollectionViewItem
{
let item = self.collectionView.makeItem( withIdentifier: NSUserInterfaceItemIdentifier( rawValue: "SensorItem" ), for: indexPath )
if let item = item as? SensorItem, let sensors = self.arrayController.arrangedObjects as? [ SensorHistoryData ]
{
if sensors.count > indexPath.item
{
item.sensor = sensors[ indexPath.item ]
}
}
return item
}
}

View File

@@ -1,57 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Foundation
public protocol Synchronizable
{
static func synchronized< T >( closure: () -> T ) -> T
func synchronized< T >( closure: () -> T ) -> T
}
public extension Synchronizable
{
static func synchronized< T >( closure: () -> T ) -> T
{
objc_sync_enter( self )
let r = closure()
objc_sync_exit( self )
return r
}
func synchronized< T >( closure: () -> T ) -> T
{
objc_sync_enter( self )
let r = closure()
objc_sync_exit( self )
return r
}
}

View File

@@ -1,7 +1,7 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
* Copyright (c) 2023, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
@@ -23,6 +23,8 @@
******************************************************************************/
import Foundation
import IOHIDKit
import SMCKit
public class ThermalLog: NSObject
{