From 9ce07ae5d0c3ea58ccf2432663a1f7aff253979b Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:20:02 +0100 Subject: [PATCH] feat(autofill): la barrette revient la ou on l'avait posee Pref DPAPI lazyPos, ecrite sur WM_EXITSIZEMOVE - une ecriture par deplacement, pas une par pixel parcouru. La position n'est reprise que si MonitorFromRect la trouve encore sur un ecran. La barrette n'a pas d'entree dans la barre des taches : une position heritee d'un ecran debranche, ou d'une resolution changee, la laisserait hors du bureau et definitivement irrecuperable. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 8 +++++- delphi-backend/Source/PM.Bridge.pas | 39 ++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2868266..42e7862 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -186,7 +186,13 @@ Détails : (elle finit par se poser sur le champ qu'elle remplit, il faut pouvoir la pousser). `WM_ERASEBKGND` peint le fond — la classe `TPUtilWindow` d'`AllocateHWnd` n'a **pas** de brosse de fond. -- Position : coin bas-droit de la *work area* au démarrage, **pas persistée**. +- Position : coin bas-droit de la *work area* au premier lancement, puis + **retenue** en pref DPAPI (`lazyPos`, `'x,y'`), écrite sur `WM_EXITSIZEMOVE` + (une écriture par déplacement, pas une par pixel parcouru). Elle n'est reprise + que si `MonitorFromRect(…, MONITOR_DEFAULTTONULL)` la trouve encore sur un + écran : la barrette n'a **pas d'entrée dans la barre des tâches**, donc une + position héritée d'un écran débranché la rendrait définitivement + irrécupérable. - Le `X` **poste** `WM_LAZY_CLOSE` à la fenêtre message-only au lieu de détruire sur place : libérer une fenêtre depuis son propre gestionnaire libérerait, en plein envoi, l'instance qui lui sert de window proc. diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 28259a9..bb77be0 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -31,7 +31,7 @@ interface uses System.SysUtils, System.Classes, System.Math, System.Types, FMX.Types, FMX.Forms, - Winapi.Windows, Winapi.ShellAPI, Winapi.Messages, + Winapi.Windows, Winapi.ShellAPI, Winapi.Messages, Winapi.MultiMon, PM.SingleInstance, PM.UserPrefs; type @@ -414,6 +414,9 @@ const // derriere sans faire disparaitre la barrette du regard. LAZY_ALPHA_KEY = 'lazyAlphaPct'; LAZY_ALPHA_DEFAULT = 60; + // Coin haut-gauche retenu, 'x,y'. Meme raison que l'opacite d'etre une pref + // DPAPI : la barrette s'allume parfois coffre ferme. + LAZY_POS_KEY = 'lazyPos'; LAZY_W = 236; LAZY_H = 40; @@ -1173,6 +1176,14 @@ begin end; Exit; end; + // Fin du glissement (la boucle modale ouverte par HTCAPTION), donc une + // ecriture par deplacement et non une par pixel parcouru. + WM_EXITSIZEMOVE: + begin + GetWindowRect(FLazyWnd, LRect); + SetPref(LAZY_POS_KEY, Format('%d,%d', [LRect.Left, LRect.Top])); + Exit; + end; // Deux portes pour un seul menu : le fond de la barrette est declare // non-client (HTCAPTION, pour pouvoir la trainer) et rend donc un clic droit // NC, tandis qu'un clic droit sur un bouton remonte en WM_CONTEXTMENU. @@ -1247,7 +1258,9 @@ procedure TPMBridge.SetLazyBar(AOn: Boolean); end; var - LWork: TRect; + LWork, LRect: TRect; + LSaved: TArray; + LX, LY, LPosX, LPosY: Integer; begin if AOn = LazyBarVisible then Exit; @@ -1280,8 +1293,26 @@ begin if not SystemParametersInfo(SPI_GETWORKAREA, 0, @LWork, 0) then LWork := Rect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); - SetWindowPos(FLazyWnd, HWND_TOPMOST, - LWork.Right - LAZY_W - 24, LWork.Bottom - LAZY_H - 24, LAZY_W, LAZY_H, + LX := LWork.Right - LAZY_W - 24; + LY := LWork.Bottom - LAZY_H - 24; + + // LA POSITION RETENUE, SI ELLE TOMBE ENCORE SUR UN ECRAN. Un ecran debranche + // depuis, ou une resolution changee, laisserait sinon la barrette hors du + // bureau - et elle est sans entree dans la barre des taches, donc perdue pour + // de bon : ni a cliquer, ni a ramener. MonitorFromRect le dit d'un mot. + LSaved := GetPref(LAZY_POS_KEY).Split([',']); + if (Length(LSaved) = 2) and TryStrToInt(LSaved[0], LPosX) + and TryStrToInt(LSaved[1], LPosY) then + begin + LRect := Rect(LPosX, LPosY, LPosX + LAZY_W, LPosY + LAZY_H); + if MonitorFromRect(@LRect, MONITOR_DEFAULTTONULL) <> 0 then + begin + LX := LPosX; + LY := LPosY; + end; + end; + + SetWindowPos(FLazyWnd, HWND_TOPMOST, LX, LY, LAZY_W, LAZY_H, SWP_NOACTIVATE or SWP_SHOWWINDOW); // La souris est ailleurs a la seconde ou la barrette parait : elle nait donc