Sechs neue Widgets (CPU, GPU, Speicher, Akku, Sensoren, Netzwerk) und dieselben sechs als einzeln aktivierbare Menüleisten-Module mit fünf Darstellungsarten. Panel-Widget und Menüleisten-Modul derselben Größe teilen sich die Messschleife über Referenzzählung. Ohne das liefe für jede Anzeige ein eigener Timer mit denselben IOKit- und SMC-Abfragen — bei sechs Modulen und ebenso vielen Widgets ein Vielfaches der nötigen Arbeit. Meldet sich der letzte Konsument ab, hört die Schleife auf; im Ruhezustand misst Onyx nichts. Die Differenzrechnung ist testgetrieben, und die Tests haben zwei echte Fehler gefunden. Erstens: mein Überlaufschutz beim Durchsatz hielt einen zurückgesetzten Zähler (Interface-Wechsel) für einen Überlauf und zeigte 4,3 GB/s. Da if_data64 64-Bit-Zähler liefert, die bei 10 Gbit/s erst nach 470 Jahren umlaufen, ist ein kleinerer Wert immer ein Zurücksetzen — die Unterscheidung produzierte nur den Ausreißer, den sie verhindern sollte. Zweitens: ByteCountFormatter schrieb bei null „Zero KB/s" statt „0 KB/s". Bei den CPU-Zählern bleibt der Überlaufschutz nötig: die sind 32 Bit breit und laufen nach gut 400 Tagen wirklich um, deshalb `&-` statt `-`. Sensoren kommen über den SMC-Leser aus Spike A statt über die private IOHID-Schnittstelle — auf dieser Maschine nachweislich verifiziert, und die dort gefundene Little-Endian-Eigenheit ist berücksichtigt. Nur eine kurze Liste benannter Fühler statt aller 3486 Keys: eine Wand aus Kürzeln ist keine Information. Gegengemessen statt vermutet: 15 Kerne, 39,8 W, GPU 50 %, 16,6/24 GB mit kritischem Druck, Akku 68 Zyklen bei 100 % Gesundheit, fünf Sensoren, zwei Lüfter, en0 mit 661 KB/s. Menüleisten-Module zeichnen in labelColor statt in den Onyx-Farben — nur die Systemfarbe passt sich heller wie dunkler Leiste an. Feste Breite je Darstellungsart, sonst schiebt jeder Messwert die halbe Leiste hin und her. Standardmäßig ist kein Modul aktiv: sechs neue Symbole beim ersten Start wären eine Zumutung. 145 Tests grün.
61 lines
3.1 KiB
Swift
61 lines
3.1 KiB
Swift
// swift-tools-version: 6.2
|
|
import PackageDescription
|
|
|
|
let package = Package(
|
|
name: "OnyxKit",
|
|
// Quellsprache ist Englisch, damit die Schlüssel im Code lesbar bleiben.
|
|
// Deutsch kommt als Übersetzung dazu; die Systemsprache entscheidet.
|
|
defaultLocalization: "en",
|
|
platforms: [.macOS(.v26)],
|
|
products: [
|
|
.library(name: "OnyxCore", targets: ["OnyxCore"]),
|
|
.library(name: "OnyxDesign", targets: ["OnyxDesign"]),
|
|
.library(name: "OnyxNotch", targets: ["OnyxNotch"]),
|
|
.library(name: "OnyxWidgetKit", targets: ["OnyxWidgetKit"]),
|
|
.library(name: "OnyxMenuBar", targets: ["OnyxMenuBar"]),
|
|
.library(name: "CalendarProvider", targets: ["CalendarProvider"]),
|
|
.library(name: "WeatherProvider", targets: ["WeatherProvider"]),
|
|
.library(name: "MediaProvider", targets: ["MediaProvider"]),
|
|
.library(name: "MetricsProvider", targets: ["MetricsProvider"]),
|
|
.library(name: "NetworkProvider", targets: ["NetworkProvider"]),
|
|
],
|
|
targets: [
|
|
// Der String-Katalog muss ausdrücklich als Ressource stehen — sonst gibt
|
|
// es kein `Bundle.module`, und die Übersetzungen wären zur Laufzeit
|
|
// unauffindbar.
|
|
.target(name: "OnyxCore", resources: [.process("Localizable.xcstrings")]),
|
|
.testTarget(name: "OnyxCoreTests", dependencies: ["OnyxCore"]),
|
|
|
|
.target(name: "OnyxDesign"),
|
|
|
|
.target(name: "OnyxNotch", dependencies: ["OnyxDesign"]),
|
|
.testTarget(name: "OnyxNotchTests", dependencies: ["OnyxNotch"]),
|
|
|
|
.target(name: "OnyxWidgetKit", dependencies: ["OnyxDesign"]),
|
|
.testTarget(name: "OnyxWidgetKitTests", dependencies: ["OnyxWidgetKit"]),
|
|
|
|
.target(name: "OnyxMenuBar", dependencies: ["OnyxDesign", "OnyxWidgetKit"]),
|
|
.testTarget(name: "OnyxMenuBarTests", dependencies: ["OnyxMenuBar"]),
|
|
|
|
.target(name: "CalendarProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit"],
|
|
resources: [.process("Localizable.xcstrings")]),
|
|
.testTarget(name: "CalendarProviderTests", dependencies: ["CalendarProvider"]),
|
|
|
|
.target(name: "WeatherProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit"],
|
|
resources: [.process("Localizable.xcstrings")]),
|
|
.testTarget(name: "WeatherProviderTests", dependencies: ["WeatherProvider"]),
|
|
|
|
.target(name: "MediaProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit"],
|
|
resources: [.process("Localizable.xcstrings")]),
|
|
.testTarget(name: "MediaProviderTests", dependencies: ["MediaProvider"]),
|
|
|
|
.target(name: "MetricsProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit", "OnyxMenuBar"],
|
|
resources: [.process("Localizable.xcstrings")]),
|
|
.testTarget(name: "MetricsProviderTests", dependencies: ["MetricsProvider"]),
|
|
|
|
.target(name: "NetworkProvider", dependencies: ["OnyxDesign", "OnyxWidgetKit", "OnyxMenuBar", "MetricsProvider"],
|
|
resources: [.process("Localizable.xcstrings")]),
|
|
.testTarget(name: "NetworkProviderTests", dependencies: ["NetworkProvider"]),
|
|
]
|
|
)
|