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