Commit Graph

5 Commits

Author SHA1 Message Date
Scarriffle
667fb61c96 Absturz beim XPC-Rückruf, Menü zurück, Fenster weg von der Notch
Der Absturzbericht war eindeutig:

  Thread 8: com.apple.NSXPCConnection.m-user…onyx.helper
    swift_task_isCurrentExecutorWithFlags
    closure #3 in FanControl.proxy()
    EXC_BREAKPOINT

Die Rückrufe der XPC-Verbindung erben die MainActor-Isolation der Methode,
in der sie stehen. XPC ruft sie aber auf seiner eigenen Warteschlange auf,
Swift 6 prüft das zur Laufzeit und beendet den Prozess. Das
`Task { @MainActor in … }` im Rumpf half nicht: die Prüfung geschieht beim
Betreten des Abschlusses, nicht beim Zugriff.

Alle sieben Rückrufe sind jetzt `@Sendable`. Und weil das eine Fehlerklasse
ist und kein Einzelfall, dieselbe Behandlung für die übrigen Stellen, an
denen ein MainActor-Typ einen Abschluss an eine Systemschnittstelle gibt:
Papierkorb, Vorschaubilder, Adapter-Ende, Darwin-Nachricht.

Dazu drei Dinge aus dem Bericht von eben:

Der Linksklick aufs Menüleistensymbol fuhr das Panel aus — und ging dabei
als Fixieren durch. Danach stand das Panel offen und reagierte auf nichts
mehr. Das war schlechter als das Problem, das es lösen sollte. Ein
Statuselement zeigt bei einem Klick sein Menü; alles andere überrascht.
„Panel öffnen" bleibt draußen.

Ein Klick daneben schließt jetzt auch ein fixiertes Panel. „Klick fixiert"
ist eine gute Regel, aber wer sie nicht kennt, sitzt sonst vor etwas, das
offen steht und nicht reagiert — und sucht den Fehler in der App.

Einstellungs- und Einrichtungsfenster gehen nicht mehr direkt unter der
Notch auf. `center()` setzt oberhalb der Mitte; der Schließknopf landete
damit so weit oben, dass man auf dem Weg dorthin die Notch auslöste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 12:54:32 +02:00
Scarriffle
a54b332723 Notch: Toleranz für zitternde Hände, „Panel öffnen" fliegt raus
Warum meine Proben grün waren und deine Hand nicht: jedes einzelne
Abtastbild außerhalb der Auslösefläche hat das Aufziehen sofort
abgebrochen. Ein Zeiger, den eine Hand an den oberen Rand führt, steht
dort aber nicht still — er wandert um ein paar Punkte. Damit fing die
Entprellzeit von 220 ms dauernd von vorn an und kam nie ans Ziel.
`CGWarpMouseCursorPosition` setzt den Zeiger auf einen Punkt und hält ihn
absolut still; deshalb war jede automatisierte Probe 19 von 19 grün.

Kurzes Herausrutschen bricht jetzt nicht mehr ab: die Entprellzeit läuft
weiter, parallel läuft die Abbruchfrist von 300 ms. Kommt der Zeiger
zurück, wird die Frist gestoppt — die Entprellzeit setzt bewusst nicht neu
an, sonst dauerte es bei jedem Grenzübertritt wieder von vorn.

Das allein hätte einen neuen Fehler gebracht, und ein vorhandener Test hat
ihn gefunden: beim beiläufigen Streifen der Notch wäre die Entprellzeit
abgelaufen, während der Zeiger längst weg war — das Panel wäre für ein
Zehntel aufgeblitzt. Die Maschine merkt sich deshalb, wo der Zeiger steht,
und öffnet nur, wenn er da ist. Ist die Entprellzeit abgelaufen, während er
draußen war, geht es beim Zurückkommen ohne weiteres Warten auf.

Die Auslösefläche reicht außerdem 14 statt 4 Punkte unter die Notch. Vier
Punkte sind keine Fläche, die eine Hand trifft.

„Panel öffnen" ist aus dem Menü verschwunden. Ein Menüeintrag für etwas,
das beim Berühren der Notch von selbst passiert, beschreibt einen Umweg um
die eigentliche Bedienung herum. Als Notausgang bleibt es erreichbar, nur
ohne eigene Zeile: Linksklick auf das Symbol fährt das Panel aus,
Rechtsklick zeigt Einstellungen und Beenden.

Dazu Protokollierung jedes Zustandswechsels und jeder Unterdrückung. Ohne
diese Spur ist ein Panel, das sich „manchmal nicht öffnet", nicht zu
untersuchen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 12:12:31 +02:00
Scarriffle
453353de58 Notch öffnet zuverlässig, Einstellungen beenden Onyx nicht mehr
Das Öffnen hing allein an Mausereignissen. Der Auslösebereich liegt aber in
der Menüleiste, und dorthin stellt macOS Bewegungen nicht verlässlich an
fremde Programme zu — mal kommen sie an, mal nicht, je nachdem, was gerade
den Zeiger führt. Ein Verfahren, das eine Zustellung voraussetzt, die es
nicht gibt, kann nicht zuverlässig sein.

Die Zeigerposition wird deshalb jetzt immer abgefragt, im Ruhezustand
zehnmal je Sekunde, bei offenem Panel sechzigmal. Die Monitore sind nur noch
Beschleunigung. Kosten: 0,1 % CPU im Leerlauf, gemessen. Nachgeprüft mit
fünf Anläufen aus verschiedenen Richtungen — fünfmal offen.

Die Unterdrückung war zu grob: jedes Vollbildfenster galt als Grund, das
Panel wegzuhalten. Damit war die Notch tot, sobald Xcode im Vollbild lief.
Gemeint war immer nur der Film über den ganzen Bildschirm, und den erkennt
man daran, dass etwas den Bildschirm wachhält — ein Textfenster tut das
nicht. Beide Bedingungen zusammen, nicht eine davon.

Dazu ein Loch, das dabei auffiel: fiel die Unterdrückung weg, während der
Zeiger schon in der Notch stand, wartete die Maschine auf ein Ereignis, das
erst bei der nächsten Bewegung kam.

Der rote Knopf blendet Fenster jetzt aus, statt sie zu schließen. Onyx hat
kein Hauptfenster; „Fenster zu" heißt hier nie „fertig". Manche
Hilfsprogramme erzwingen aber genau diese Gleichung und beenden eine App,
sobald ihr letztes Fenster verschwindet — dann war Onyx nach einem Blick in
die Einstellungen weg, samt Menüleiste und Notch. Ein Fenster, das nie
wirklich schließt, gibt dafür keinen Anlass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:21:00 +02:00
Guido Schmit
65f9fbfa4e Inhalt beginnt unterhalb der Notch statt dahinter
Das Panel reichte oben bündig an die Bildschirmkante, damit seine Fläche mit
der schwarzen Notch-Hardware zu einem Körper verschmilzt. Die Notch ist aber
undurchsichtig — die obersten 38 pt Inhalt waren schlicht nicht zu sehen. Links
und rechts daneben liegt in diesem Streifen zusätzlich die Menüleiste, der ganze
Streifen ist also unbrauchbar.

Die Fläche bleibt deshalb, wo sie war; nur der Inhalt rückt nach unten. Das
Fenster wächst entsprechend mit (446x340 → 446x378), damit unten nichts
abgeschnitten wird.

Der Controller nimmt jetzt die Inhaltsgröße entgegen und schlägt den Freiraum
selbst auf. Keine Aufrufstelle muss daran denken, und beim Wechsel zwischen
eingebautem Display (38 pt) und externem (virtueller Balken) wandert der
Freiraum automatisch mit.

Gegengemessen statt geschätzt: die Zentrierung war korrekt (Panel-midX 900 =
Notch-midX 900), der Fehler lag allein in der Höhe. Vier Tests halten den
Inhaltsbereich jetzt außerhalb der Notch fest, auch für den virtuellen Balken.

70 Tests grün.
2026-08-10 17:43:30 +02:00
Guido Schmit
fbe13fd1cb Phase 1: Notch-Shell, Design-System, Menüleisten-Infrastruktur
Zustandsmaschine und Geometrie sind testgetrieben entstanden und tragen 40
Tests — sie sind frei von AppKit, damit jeder Übergang ohne Fenster und ohne
Warten prüfbar ist. Zeit kommt nur als Ereignis herein.

Zwei Entscheidungen, die im Code begründet sind:

Der Zeiger wird über einen globalen Ereignismonitor verfolgt, nicht über ein
unsichtbares Fenster auf der Notch. Ein solches Fenster müsste Mausereignisse
annehmen, um sie zu bemerken, und würde damit Menüleiste und Fensterknöpfe
darunter unbenutzbar machen.

"Nur internes Display" fällt auf ein externes zurück, wenn kein eingebautes da
ist. Am Dock mit geschlossenem Deckel hieße die Einstellung wörtlich genommen,
dass Onyx unerreichbar wird.

Design: NSVisualEffectView mit eigenem Tint statt Liquid Glass — Onyx ist Stein,
kein Glas. Alle Farben und Maße liegen als Tokens in OnyxDesign.

Menüleiste: jedes Modul bekommt ein eigenes NSStatusItem. Elemente, denen macOS
mangels Platz keine Breite gibt, werden erkannt und gemeldet, statt still zu
verschwinden.

App-Target über XcodeGen, damit die Projektdefinition im Diff lesbar bleibt.
Nicht sandboxed, mit App-Group-Entitlement — baut, startet, signiert mit
PP34X97WS3.
2026-08-10 17:17:16 +02:00