mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 09:53:51 +02:00
win32: use a WindowPosChanging hack in SetBounds to prevent Windows to change the LCL position (replaces c5c2329f
). Issue #39479
This commit is contained in:
parent
89cd2a1045
commit
20009b685b
lcl/interfaces/win32
@ -134,6 +134,11 @@ procedure WindowCreateInitBuddy(const AWinControl: TWinControl;
|
||||
// Must be in win32proc but TCreateWindowExParams declared here
|
||||
procedure SetStdBiDiModeParams(const AWinControl: TWinControl; var Params:TCreateWindowExParams);
|
||||
|
||||
var
|
||||
// WindowPosChanging hack - see comment in TWin32WSWinControl.SetBounds
|
||||
LockWindowPosChanging: Boolean = False;
|
||||
LockWindowPosChangingXY: TPoint;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -441,6 +446,8 @@ var
|
||||
suppressMove: boolean;
|
||||
Handle: HWND;
|
||||
WindowPlacement: TWINDOWPLACEMENT;
|
||||
Mon: HMONITOR;
|
||||
MonInfo: TMonitorInfo;
|
||||
begin
|
||||
IntfLeft := ALeft;
|
||||
IntfTop := ATop;
|
||||
@ -459,24 +466,35 @@ begin
|
||||
begin
|
||||
Handle := AWinControl.Handle;
|
||||
WindowPlacement.length := SizeOf(WindowPlacement);
|
||||
|
||||
// Windows (at least Win 10) has the feature that SetWindowPos() forces dialogs with parent windows on the same screen
|
||||
// with the parent window - the position set with Windows.SetWindowPos() is ignored and instead the dialog
|
||||
// is centered with its parent window.
|
||||
// To prevent Windows from changing the position defined by the LCL, SetWindowPos() must not be used and
|
||||
// SetWindowPlacement() must be used instead.
|
||||
// It looks like GetWindowPlacement/SetWindowPlacement has no negative impact on non-form controls, so it is used directly
|
||||
// In case of problems with "normal" wincontrols, the GetWindowPlacement/SetWindowPlacement code can be executed only
|
||||
// for TCustomForm descendands
|
||||
// To prevent Windows from changing the position defined by the LCL, the LM_WINDOWPOSCHANGING is handled and the
|
||||
// new coordinates are re-assigned within the message handler with LockWindowPosChanging&LockWindowPosChangingXY
|
||||
// See issue #39479 for more description and demo application.
|
||||
if GetWindowPlacement(Handle, @WindowPlacement) then
|
||||
begin
|
||||
WindowPlacement.rcNormalPosition := Bounds(IntfLeft, IntfTop, IntfWidth, IntfHeight);
|
||||
if not IsIconic(Handle) and not Windows.IsWindowVisible(Handle) then // do not show hidden windows prematurely
|
||||
WindowPlacement.showCmd := SW_HIDE;
|
||||
SetWindowPlacement(Handle, @WindowPlacement);
|
||||
end
|
||||
else
|
||||
Windows.SetWindowPos(Handle, 0, IntfLeft, IntfTop, IntfWidth, IntfHeight, SWP_NOZORDER or SWP_NOACTIVATE);
|
||||
LockWindowPosChanging := True;
|
||||
try
|
||||
LockWindowPosChangingXY := Point(IntfLeft, IntfTop);
|
||||
if IsIconic(Handle) and GetWindowPlacement(Handle, @WindowPlacement) then
|
||||
begin
|
||||
WindowPlacement.rcNormalPosition := Bounds(IntfLeft, IntfTop, IntfWidth, IntfHeight);
|
||||
// workarea coordinates must be used for top-level windows without WS_EX_TOOLWINDOW window style
|
||||
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOOLWINDOW)=0 then
|
||||
begin
|
||||
Mon := MonitorFromRect(@WindowPlacement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY);
|
||||
MonInfo := Default(TMonitorInfo);
|
||||
MonInfo.cbSize := SizeOf(TMonitorInfo);
|
||||
if (Mon<>0) and GetMonitorInfo(Mon, @MonInfo) then
|
||||
WindowPlacement.rcNormalPosition.Offset(MonInfo.rcMonitor.Left-MonInfo.rcWork.Left, MonInfo.rcMonitor.Top-MonInfo.rcWork.Top);
|
||||
end;
|
||||
SetWindowPlacement(Handle, @WindowPlacement);
|
||||
end
|
||||
else
|
||||
Windows.SetWindowPos(Handle, 0, IntfLeft, IntfTop, IntfWidth, IntfHeight, SWP_NOZORDER or SWP_NOACTIVATE);
|
||||
finally
|
||||
LockWindowPosChanging := False;
|
||||
end;
|
||||
end;
|
||||
LCLControlSizeNeedsUpdate(AWinControl, True);
|
||||
// If this control is a child of an MDI form, then we need to update the MDI client bounds in
|
||||
|
@ -355,6 +355,19 @@ function CustomFormWndProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam; LPar
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure CallWindowPosChanging;
|
||||
var
|
||||
WP: PWindowPos;
|
||||
begin
|
||||
if not LockWindowPosChanging then
|
||||
Exit;
|
||||
WP := PWindowPos(LParam);
|
||||
if (WP^.flags and SWP_NOMOVE)<>0 then
|
||||
Exit;
|
||||
WP^.x := LockWindowPosChangingXY.X;
|
||||
WP^.y := LockWindowPosChangingXY.Y;
|
||||
end;
|
||||
|
||||
var
|
||||
Info: PWin32WindowInfo;
|
||||
WinControl: TWinControl;
|
||||
@ -362,6 +375,8 @@ begin
|
||||
Info := GetWin32WindowInfo(Window);
|
||||
WinControl := Info^.WinControl;
|
||||
case Msg of
|
||||
WM_WINDOWPOSCHANGING:
|
||||
CallWindowPosChanging;
|
||||
WM_GETMINMAXINFO:
|
||||
begin
|
||||
SetMinMaxInfo(WinControl, PMINMAXINFO(LParam)^);
|
||||
|
Loading…
Reference in New Issue
Block a user