Skip to content

Zwei Fensterprüfstände: auf Ruhe warten, Grundlage frisch erzwingen - #451

Merged
oe5sos merged 3 commits into
mainfrom
fix/seitenbereich-rastfrist
Nov 14, 2026
Merged

oe5sos merged 3 commits into
mainfrom
fix/seitenbereich-rastfrist

Conversation

@oe5sos

@oe5sos oe5sos commented Nov 13, 2026

Copy link
Copy Markdown
Owner

Warum

collapsingWidensTheAdjacentPanadapter fiel am 2026-11-03 und wieder am 2026-11-13 auf dem Linux-Läufer — beide Male mit derselben Zahl: 429 statt 420. Am 13.11. hat das einen fertigen PR (#442) blockiert, der den Seitenbereich gar nicht anfasst.

Der Kommentar im Prüfstand nennt die Ursache schon selbst: snapToGridAfterSettle (WindowPlacement.h) rastet den Rahmen erst 180 ms nach dem Loslassen ein. Wer vorher misst, vergleicht die Breite vor dem Rasten mit der danach.

Die bisherige Antwort darauf war eine längere Wartezeit (kRastFristMs = 400). Das hält nur, solange der Taktgeber pünktlich drankommt — auf einem ausgelasteten Läufer tut er das nicht, und eine feste Frist lässt sich nicht so weit hochdrehen, dass sie immer reicht, ohne jeden Lauf zu bremsen.

Was sich ändert

An den drei Stellen, die eine Breite ablesen oder vergleichen, wird nicht mehr auf die Uhr gewartet, sondern auf Ruhe:

warteBisDerRahmenSteht() wartet erst die Frist ab — vorher hat das Rasten gar nicht begonnen, und „ruhig" wäre eine Lüge — und dann, bis sich frameGeometry() drei Messungen lang nicht mehr ändert. Kommt der Rahmen bis zur Obergrenze (4 s) nicht zur Ruhe, fällt der Fall mit Begründung, statt stillschweigend weiterzulaufen: ein übergangener Fall sieht aus wie ein Erfolg.

Kein Produktivcode berührt, nur der Prüfstand.

Gegenprobe

Mit einer Ruheprüfung, die nie zutrifft (if (false && jetzt == vorher)), fällt der Fall mit

FAIL!  : collapsingWidensTheAdjacentPanadapter()
         'warteBisDerRahmenSteht(win, kRastFristMs)' returned FALSE.
         (der Rahmen kam nach dem Setzen nicht zur Ruhe)

Der Helfer winkt also nicht bloß durch. Zurückgestellt: 2/2 grün.

🤖 Generated with Claude Code

oe5sos and others added 2 commits November 13, 2026 21:02
`collapsingWidensTheAdjacentPanadapter` fiel am 2026-11-03 und wieder
am 2026-11-13 auf dem Linux-Laeufer, beide Male mit DERSELBEN Zahl:
429 statt 420. Der Kommentar im Pruefstand nennt die Ursache schon
selbst -- `snapToGridAfterSettle` (WindowPlacement.h) rastet den
Rahmen erst 180 ms nach dem Loslassen ein, und wer vorher misst,
vergleicht die Breite VOR dem Rasten mit der danach.

Die Antwort darauf war bisher eine laengere Wartezeit
(kRastFristMs = 400). Das haelt nur, solange der Taktgeber puenktlich
drankommt; auf einem ausgelasteten Laeufer tut er das nicht, und eine
feste Frist laesst sich nicht so weit hochdrehen, dass sie immer
reicht, ohne den Lauf zu bremsen.

Jetzt wird an den drei Stellen, die eine Breite ablesen oder
vergleichen, nicht mehr auf die Uhr gewartet, sondern auf RUHE:
`warteBisDerRahmenSteht` wartet erst die Frist ab (vorher hat das
Rasten gar nicht begonnen, und "ruhig" waere eine Luege) und dann,
bis sich frameGeometry() drei Messungen lang nicht mehr aendert.
Kommt er bis zur Obergrenze nicht zur Ruhe, faellt der Fall mit
Begruendung, statt stillschweigend weiterzulaufen.

Gegenprobe gefahren: mit einer Ruhepruefung, die nie zutrifft, faellt
der Fall mit "der Rahmen kam nach dem Setzen nicht zur Ruhe" -- der
Helfer winkt also nicht bloss durch. 2/2 gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kleinUndWiederGrossGibtDieAlteLage() stellte seine Lage nie her. Der
Fall setzt dem schwebenden Fenster eine Untergrenze und erwartet, dass
es beim Verkleinern des Hauptfensters an ihr haengenbleibt. Dafuer
muessen die ANTEILE, aus denen MainWindow::schwebendeUmrechnen die neue
Groesse rechnet, von JETZT stammen. schwebendeMitziehenForTest() setzt
aber nur den Hauptrahmen als Basis; die Anteile je Fenster bleiben
stehen, solange das Fenster dort steht, wo das Mitziehen es hingesetzt
hat -- so ist es gewollt.

Steht das Fenster schmaler, als seine Grundlage will (auf macOS: 260
statt 269, weil es im Fall davor an seiner natuerlichen Mindestbreite
hing), rechnet der Fall mit 269 weiter und vergleicht gegen 260. Erst
auf Linux (drei Faelle), dann auf macOS (Lauf 43497937016, Shard 2/2,
ein Fall) -- beide Male dieselbe Ursache.

Jetzt zieht der Fall das Fenster vorher um 32 Punkte von Hand: mehr als
eine Rasterweite, damit gelten die Anteile als veraltet und werden beim
naechsten Umrechnen frisch gemessen. Dazu eine qInfo-Zeile VOR dem
Vergleich (ein Fehlschlag in der CI soll die Zahlen zeigen) und eine
Vorbedingung, dass das Hauptfenster wirklich schmaler wurde -- es
stoesst bei dieser Groesse an seine eigene Mindestbreite.

Gegenprobe gefahren: die macOS-Lage lokal hergestellt (Hoechstbreite
200 setzen, Hauptfenster verkleinern, Hoechstbreite loesen) -- ohne die
Behebung faellt der Fall mit genau denselben Zahlen wie in der CI
(Actual 269, Expected 260), mit ihr ist er gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@oe5sos oe5sos changed the title Seitenbereich-Prüfstand: auf Ruhe warten statt auf die Uhr Zwei Fensterprüfstände: auf Ruhe warten, Grundlage frisch erzwingen Nov 13, 2026
@oe5sos

oe5sos commented Nov 13, 2026

Copy link
Copy Markdown
Owner Author

Zweiter Prüfstand dazu: tst_schwebende_folgen_dem_hauptfenster::kleinUndWiederGrossGibtDieAlteLage fiel erst auf Linux (drei Fälle), dann auf macOS (ein Fall, Actual 269 / Expected 260).

Ursache ist nicht Flattern, sondern dass der Fall seine Lage nie herstellte: schwebendeMitziehenForTest() setzt nur den Hauptrahmen als Basis, nicht die Anteile je Fenster. Steht das Fenster schmaler, als seine stehengebliebene Grundlage will (auf macOS 260 statt 269, weil es im Fall davor an seiner Mindestbreite hing), rechnet die Umrechnung mit 269 weiter.

Gegenprobe gefahren: die macOS-Lage lokal hergestellt (Höchstbreite 200 setzen, Hauptfenster verkleinern, Höchstbreite lösen) — ohne die Behebung fällt der Fall mit genau denselben Zahlen wie in der CI, mit ihr ist er grün (10/10, 13,8 s).

Drei Faelle stellten das Fenster "300 rechts, 520 unter der Oberkante"
des Hauptfensters -- eine feste Zahl, die nur hier traegt. Auf macOS
wird dasselbe Fenster doppelt so hoch (301 gegen 157 Punkte) und die
Bedienleisten fressen 150 Punkte statt weniger: dort ragte es nach dem
Verkleinern in die Statusleiste, der Schutzrahmen schob es waehrend der
Messung heraus -- und der Pruefstand zaehlte das als "zog mit".

Im Protokoll stand es wortwoertlich vor jedem der beiden Fehlschlaege:
"Schutzrahmen: 1 schwebende Fenster lagen auf einer Bedienleiste und
wurden heruntergeschoben" (Lauf 43523526068, macOS 2/2).

Jetzt rechnet tiefAberSicherStellen() die Lage aus der Arbeitsflaeche,
der gemessenen Fensterhoehe und dem Platz, den der Fall selbst noch
verliert (58 Punkte Hoehe beim Startsprung, 41 beim Zug nach oben, 100
beim Verkleinern) -- und meldet es als fehlenden Platz, wenn der Fall
nicht herstellbar ist, statt stumm Falsches zu messen. eigeneBewegung-
ZiehtNicht() haengt damit nicht mehr an der Lage seines Vorgaengers.

Gegenprobe gefahren: mit erzwungener macOS-Hoehe (setMinimumHeight(310)
in initTestCase) fallen mit den alten festen Stellen genau dieselben
zwei Faelle, mit denselben Zahlen wie in der CI (Expected QPoint(528,688),
"zog mit (0,-224)") und derselben Schutzrahmen-Meldung davor; mit dem
Helfer sind alle zehn gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@oe5sos
oe5sos merged commit d6bad41 into main Nov 14, 2026
12 of 13 checks passed
@oe5sos
oe5sos deleted the fix/seitenbereich-rastfrist branch November 14, 2026 01:18
oe5sos added a commit that referenced this pull request Nov 14, 2026
…ssen (#453)

`beimZiehenWirdDerRahmenSICHTBAR` war auf main rot (Linux-Shard 3/4, 1
von 304 -- derselbe Fall und derselbe Shard wie am 2026-10-20). Das
Programm hat dabei vollkommen richtig gearbeitet.

Die Ursache stand im VOLLEN Protokoll, eine Zeile vor dem Fehlschlag,
und nicht in den FAIL-Zeilen:

    Schutzrahmen: 1 schwebende Fenster lagen auf einer Bedienleiste
    und wurden heruntergeschoben

Nach dem Aufbau setzt MainWindow zwei Nachlaeufe an (MainWindow.cpp,
"Zwei Nachlaeufe"): `singleShot(0)` und `singleShot(500)`, beide rufen
`schwebendeAusDemSchutzrahmenHolen()`. Auf dem lastigen Laeufer kam der
zweite erst mitten in der Messung -- er holte den eben platzierten
Schweber von der Sperrzone weg. Danach beruehrte nichts mehr etwas,
also schwieg `meldeZug()` zu Recht, und der Lauf meldete das als „der
Rahmen bleibt beim Ziehen unsichtbar".

Drei Aenderungen, alle im Pruefstand:

* `warteBisDasHauptfensterSteht()` nach dem Muster von
  `warteBisDerRahmenSteht()` aus tst_side_area_integration.cpp (#451):
  Mindestfrist ueber die 500 ms des zweiten Nachlaufs, danach auf Ruhe
  warten -- drei gleiche Messungen der Fenstergeometrie, nicht eine.
  Auf den ZUSTAND warten, nicht auf die Uhr.
* Das `processEvents()` zwischen `move()` und `meldeZug()` ist weg.
  Genau in dieser Luecke lief der Nachlauf. `meldeZug()` liest
  `frameGeometry()` direkt und braucht keine Ereignisrunde.
* Sprechende Meldungen: faellt der Fall doch, sagt er jetzt, WO das
  Fenster liegt und dass ein Nachlauf es geholt haben kann. Die alte
  Meldung („der Rahmen bleibt beim Ziehen unsichtbar") hat mich zuerst
  auf die falsche Spur gefuehrt.

Dazu ein neuer Prueffall, `einePlatzierungLoestDenHinweisNICHTAus`: die
Wache `if (s_eigeneBewegungen > 0) { return; }` in `meldeZug()` war
NIRGENDS festgenagelt -- in keinem der vier Prueffaelle, die
`EigeneBewegung` ueberhaupt nennen. Darum konnte ich sie zuerst fuer
die Ursache halten; nichts schloss sie aus. Jetzt tut es etwas, und
zwar in beide Richtungen: eine Platzierung loest den Hinweis nicht
aus, ein echter Zug danach aber doch.

ZWEI GEGENPROBEN gefahren, weil ein lokal gruener Lauf hier nichts
beweist:

1. Nachlauf absichtlich mitten in die Messung
   (`mw.schwebendeAusDemSchutzrahmenHolen()` zwischen `move()` und der
   Pruefung): rot, mit derselben Protokollzeile wie in der CI und der
   neuen Meldung „die Lage kam nicht an: 42,100 304x124 trifft die
   Sperrzone nicht". Damit ist der Fehlschlag des Laeufers gezielt
   hergestellt, nicht nur vermutet.
2. Die Wache aus `meldeZug()` entfernt: `einePlatzierungLoestDen
   HinweisNICHTAus` wird rot („der Hinweis blinkt beim PLATZIEREN").

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant