fix(winstate): park the restored-size rect so the FMX restore has nothing to grow

FMX drops the maximised state when Windows minimises the form externally —
reproducible in an empty FMX app. Windows then picks rcNormalPosition as the
restore target before it animates, so every reactive correction measured (queued,
inline in MINIMIZEEND, inside the restore's own WM_SIZE) landed after the frame
was already growing: the state ended correct and the flash remained.

Widen rcNormalPosition to the monitor work area while the window is down instead.
FMX still restores to normal, except normal is now full-screen, so nothing grows;
ReleaseNormalRect writes the real rectangle back once the window is maximised
again, keeping the user's own restored size intact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-27 20:13:52 +01:00
parent b52cdc2d0b
commit 17e817f8ab
2 changed files with 99 additions and 18 deletions
+3 -1
View File
@@ -339,7 +339,9 @@ L'app démarre maximisée (`WindowState = wsMaximized` dans la `.fmx`).
- **ACTION** : fenêtre **maximisée** → `Win+D` (ou *Show desktop*) → revenir à l'app (barre des tâches, tray ou Alt+Tab).
- **ATTENDU** : elle revient **maximisée**, **sans passer par une frame en taille normale**.
- **Historique** : FMX oublie l'état maximisé quand Windows minimise la fenêtre de l'extérieur, et aucun de nos chemins de restore ne tourne pour un clic sur la barre des tâches.
- **Historique (flash)** : une fois l'état correct, il restait un scintillement — la fenêtre revenait normale puis se maximisait. La correction était postée via `ForceQueue` ; le log a montré que l'état ne changeait **pas** entre le hook et le tour de boucle suivant, donc la file ne protégeait d'aucune course et n'ajoutait que la frame visible. Elle s'exécute maintenant **en ligne** dans `MINIMIZEEND` (`ApplyWantedWindowState`), la passe différée restant en filet idempotent. Piste écartée au passage : poser `WPF_RESTORETOMAXIMIZED` — `GetWindowPlacement` rapporte déjà ce flag sur toute fenêtre maximisée, donc le stamp est un no-op.
- **Historique (flash)** : une fois l'état final correct, il restait un scintillement — le cadre apparaissait en taille normale puis grandissait. **C'est un bug FMX**, reproduit sur une application FMX vide : FMX perd le maximisé quand Windows minimise le formulaire de l'extérieur. Windows choisit alors `rcNormalPosition` comme cible **avant** d'animer, donc aucune correction réactive ne peut arriver à temps — trois ont été essayées et rejetées par la mesure : `ForceQueue` (un tour de boucle trop tard), appel inline dans `MINIMIZEEND` (le hook est délivré après le `WM_SIZE`), correction dans le `WM_SIZE` lui-même (l'état devient parfait, le flash reste — preuve que le problème n'était plus l'état). Écarté aussi : poser `WPF_RESTORETOMAXIMIZED`, que `GetWindowPlacement` rapporte déjà à 2 sur une fenêtre maximisée (no-op).
**Solution** : ne pas combattre la restauration, rendre sa cible inoffensive. `WinStateMinimizeStart` gare le vrai `rcNormalPosition` et le remplace par `rcWork` du moniteur ; FMX restaure toujours « en normal », mais normal vaut désormais plein écran, donc rien ne grandit. `ReleaseNormalRect` rend le rectangle réel une fois la fenêtre re-maximisée (invisible : elle est maximisée à ce moment).
- **Non-régression obligatoire** : après le retour, **dé-maximiser** doit rendre la taille d'origine de l'utilisateur, pas la zone de travail — sinon `ReleaseNormalRect` n'a pas tourné et le rectangle est resté garé.
### I2 · normal survit aussi ✅
- **ACTION** : dé-maximiser la fenêtre → `Win+D` → revenir.