mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-25 11:48:18 +02:00
lcl: consider compositor/DWM extended frame for snapping
This commit is contained in:
parent
0b50d7cfc2
commit
da8aa82003
@ -441,6 +441,7 @@ type
|
|||||||
FEnabled: boolean;
|
FEnabled: boolean;
|
||||||
FActiveForm: TCustomForm;
|
FActiveForm: TCustomForm;
|
||||||
FPreviousSource, FPreviousReturn: TWindowPos;
|
FPreviousSource, FPreviousReturn: TWindowPos;
|
||||||
|
FCompositorBorders: TRect;
|
||||||
protected
|
protected
|
||||||
function SnapToSides(var x, cx: integer; px, pcx, pxout, pcxout: integer; dist: integer; leftsides, rightsides: TIntegerDynArray): boolean;
|
function SnapToSides(var x, cx: integer; px, pcx, pxout, pcxout: integer; dist: integer; leftsides, rightsides: TIntegerDynArray): boolean;
|
||||||
function SnapToMonitor(Opts: TWindowMagnetOptions; var WindowPos: TWindowPos): boolean;
|
function SnapToMonitor(Opts: TWindowMagnetOptions; var WindowPos: TWindowPos): boolean;
|
||||||
|
@ -968,6 +968,12 @@ begin
|
|||||||
Result := -1;
|
Result := -1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TWidgetSet.GetCompositorExtendedBorder(handle : HWND; var Borders: TRect) : Boolean;
|
||||||
|
begin
|
||||||
|
Borders:= Rect(0,0,0,0);
|
||||||
|
Result:= True;
|
||||||
|
end;
|
||||||
|
|
||||||
function TWidgetSet.GetCurrentObject(DC: HDC; uObjectType: UINT): HGDIOBJ;
|
function TWidgetSet.GetCurrentObject(DC: HDC; uObjectType: UINT): HGDIOBJ;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
|
@ -360,6 +360,11 @@ begin
|
|||||||
Result := WidgetSet.GetClipRGN(DC, RGN);
|
Result := WidgetSet.GetClipRGN(DC, RGN);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GetCompositorExtendedBorder(handle : HWND; var Borders: TRect) : Boolean;
|
||||||
|
begin
|
||||||
|
Result := WidgetSet.GetCompositorExtendedBorder(handle, Borders);
|
||||||
|
end;
|
||||||
|
|
||||||
function GetCursorPos(var lpPoint:TPoint): Boolean;
|
function GetCursorPos(var lpPoint:TPoint): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := WidgetSet.GetCursorPos(lpPoint);
|
Result := WidgetSet.GetCursorPos(lpPoint);
|
||||||
|
@ -116,6 +116,7 @@ function GetCaretPos(var lpPoint: TPoint): Boolean; {$IFDEF IF_BASE_MEMBER}virtu
|
|||||||
function GetClientRect(handle : HWND; var Rect: TRect) : Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
function GetClientRect(handle : HWND; var Rect: TRect) : Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
||||||
function GetClipBox(DC : hDC; lpRect : PRect) : Longint; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
function GetClipBox(DC : hDC; lpRect : PRect) : Longint; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
||||||
function GetClipRGN(DC : hDC; RGN : hRGN) : Longint; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
function GetClipRGN(DC : hDC; RGN : hRGN) : Longint; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
||||||
|
function GetCompositorExtendedBorder(handle : HWND; var Borders: TRect) : Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
||||||
function GetCurrentObject(DC: HDC; uObjectType: UINT): HGDIOBJ; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
function GetCurrentObject(DC: HDC; uObjectType: UINT): HGDIOBJ; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
||||||
function GetCursorPos(var lpPoint: TPoint): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
function GetCursorPos(var lpPoint: TPoint): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
|
||||||
function GetCharABCWidths(DC: HDC; p2, p3: UINT; const ABCStructs): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF} //pbd
|
function GetCharABCWidths(DC: HDC; p2, p3: UINT; const ABCStructs): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF} //pbd
|
||||||
|
@ -49,6 +49,7 @@ begin
|
|||||||
FActiveForm:= nil;
|
FActiveForm:= nil;
|
||||||
FPreviousSource:= Default(TWindowPos);
|
FPreviousSource:= Default(TWindowPos);
|
||||||
FPreviousReturn:= Default(TWindowPos);
|
FPreviousReturn:= Default(TWindowPos);
|
||||||
|
FCompositorBorders:= Rect(0, 0, 0, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TWindowMagnetManager.SnapForm(Form: TCustomForm; var WindowPos: TWindowPos): boolean;
|
function TWindowMagnetManager.SnapForm(Form: TCustomForm; var WindowPos: TWindowPos): boolean;
|
||||||
@ -71,6 +72,9 @@ begin
|
|||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if not GetCompositorExtendedBorder(Form.Handle, FCompositorBorders) then
|
||||||
|
FCompositorBorders:= Rect(0, 0, 0, 0);
|
||||||
|
|
||||||
Result:= SnapToMonitor(Form.SnapOptions, WindowPos) or
|
Result:= SnapToMonitor(Form.SnapOptions, WindowPos) or
|
||||||
SnapToForms(Form.SnapOptions, WindowPos);
|
SnapToForms(Form.SnapOptions, WindowPos);
|
||||||
|
|
||||||
@ -147,8 +151,10 @@ begin
|
|||||||
Area:= Screen.MonitorFromRect(Rect).WorkareaRect;
|
Area:= Screen.MonitorFromRect(Rect).WorkareaRect;
|
||||||
{$push}
|
{$push}
|
||||||
{$BoolEval on} // do not short-circuit, SnapToSides has sideffects that must take place either way
|
{$BoolEval on} // do not short-circuit, SnapToSides has sideffects that must take place either way
|
||||||
Result:= SnapToSides(WindowPos.x, WindowPos.cx, FPreviousSource.x, FPreviousSource.cx, FPreviousReturn.x, FPreviousReturn.cx, Opts.Distance, [Area.Left], [Area.Right]) or
|
Result:= SnapToSides(WindowPos.x, WindowPos.cx, FPreviousSource.x, FPreviousSource.cx, FPreviousReturn.x, FPreviousReturn.cx,
|
||||||
SnapToSides(WindowPos.y, WindowPos.cy, FPreviousSource.y, FPreviousSource.cy, FPreviousReturn.y, FPreviousReturn.cy, Opts.Distance, [Area.Top], [Area.Bottom]);
|
Opts.Distance, [Area.Left - FCompositorBorders.Left], [Area.Right + FCompositorBorders.Right]) or
|
||||||
|
SnapToSides(WindowPos.y, WindowPos.cy, FPreviousSource.y, FPreviousSource.cy, FPreviousReturn.y, FPreviousReturn.cy,
|
||||||
|
Opts.Distance, [Area.Top - FCompositorBorders.Top], [Area.Bottom + FCompositorBorders.Bottom]);
|
||||||
{$pop}
|
{$pop}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -159,13 +165,17 @@ function TWindowMagnetManager.SnapToForms(Opts: TWindowMagnetOptions; var Window
|
|||||||
Insert(Item, List, Length(List));
|
Insert(Item, List, Length(List));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure AddGoals(wtop, wbot, otop, obot, oleft, oright, mleft, mright: integer; var snapleft, snapright, snapup, snapdown: TIntegerDynArray);
|
procedure AddGoals(wtop, wbot, otop, obot, oleft, oright, mleft, mright,
|
||||||
|
btop, bbot, bleft, bright: integer;
|
||||||
|
var snapleft, snapright, snapup, snapdown: TIntegerDynArray);
|
||||||
begin
|
begin
|
||||||
// is there any overlap?
|
// is there any true overlap?
|
||||||
if (wtop < obot) and (wbot > otop) then begin
|
if (wtop + btop < obot - bbot) and (wbot - bbot > otop + btop) then begin
|
||||||
Append(oleft, snapright);
|
// add borders in order "apparent +- mine +- theirs"
|
||||||
Append(oright, snapleft);
|
Append(oleft + bright + bleft, snapright);
|
||||||
if (oleft = mright) or (oright = mleft) then begin
|
Append(oright - bleft - bright, snapleft);
|
||||||
|
if (oleft + bleft = mright - bright) or
|
||||||
|
(oright - bright = mleft + bleft) then begin
|
||||||
// already magnetised on L-R axis, include top-top/bottom-bottom align goals
|
// already magnetised on L-R axis, include top-top/bottom-bottom align goals
|
||||||
Append(otop, snapup);
|
Append(otop, snapup);
|
||||||
Append(obot, snapdown);
|
Append(obot, snapdown);
|
||||||
@ -196,9 +206,13 @@ begin
|
|||||||
if not frm.SnapOptions.SnapFormTarget then continue;
|
if not frm.SnapOptions.SnapFormTarget then continue;
|
||||||
if GetWindowRect(frm.Handle, br) = 0 then continue;
|
if GetWindowRect(frm.Handle, br) = 0 then continue;
|
||||||
// Left-Right snapping
|
// Left-Right snapping
|
||||||
AddGoals(Rect.Top, Rect.Bottom, br.Top, br.Bottom, br.Left, br.Right, PrevRect.Left, PrevRect.Right, SnapTo[3], SnapTo[1], SnapTo[0], SnapTo[2]);
|
AddGoals(Rect.Top, Rect.Bottom, br.Top, br.Bottom, br.Left, br.Right, PrevRect.Left, PrevRect.Right,
|
||||||
|
FCompositorBorders.Top, FCompositorBorders.Bottom, FCompositorBorders.Left, FCompositorBorders.Right,
|
||||||
|
SnapTo[3], SnapTo[1], SnapTo[0], SnapTo[2]);
|
||||||
// Up-Down snapping
|
// Up-Down snapping
|
||||||
AddGoals(Rect.Left, Rect.Right, br.Left, br.Right, br.Top, br.Bottom, PrevRect.Top, PrevRect.Bottom, SnapTo[0], SnapTo[2], SnapTo[3], SnapTo[1]);
|
AddGoals(Rect.Left, Rect.Right, br.Left, br.Right, br.Top, br.Bottom, PrevRect.Top, PrevRect.Bottom,
|
||||||
|
FCompositorBorders.Left, FCompositorBorders.Right, FCompositorBorders.Top, FCompositorBorders.Bottom,
|
||||||
|
SnapTo[0], SnapTo[2], SnapTo[3], SnapTo[1]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$push}
|
{$push}
|
||||||
|
@ -30,7 +30,7 @@ interface
|
|||||||
}
|
}
|
||||||
uses
|
uses
|
||||||
Windows, // keep as first
|
Windows, // keep as first
|
||||||
Classes, SysUtils, RtlConsts, ActiveX, MultiMon, CommCtrl, UxTheme, ctypes,
|
Classes, SysUtils, RtlConsts, ActiveX, MultiMon, CommCtrl, UxTheme, ctypes, DwmApi,
|
||||||
{$IF FPC_FULLVERSION>=30000}
|
{$IF FPC_FULLVERSION>=30000}
|
||||||
character,
|
character,
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -563,6 +563,8 @@ initialization
|
|||||||
LCLCheckListboxClsName[L+L1] := #0;
|
LCLCheckListboxClsName[L+L1] := #0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
InitDwmLibrary;
|
||||||
|
|
||||||
finalization
|
finalization
|
||||||
if CurDoubleBuffer.Bitmap <> 0 then
|
if CurDoubleBuffer.Bitmap <> 0 then
|
||||||
begin
|
begin
|
||||||
@ -577,4 +579,6 @@ finalization
|
|||||||
Windows.UnregisterClassW(PWideChar( WideString(LCLComboboxClsName) ), System.HInstance);
|
Windows.UnregisterClassW(PWideChar( WideString(LCLComboboxClsName) ), System.HInstance);
|
||||||
Windows.UnregisterClassW(PWideChar( WideString(LCLCheckListboxClsName) ), System.HInstance);
|
Windows.UnregisterClassW(PWideChar( WideString(LCLCheckListboxClsName) ), System.HInstance);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
FreeDwmLibrary;
|
||||||
end.
|
end.
|
||||||
|
@ -1801,6 +1801,45 @@ begin
|
|||||||
Result := Windows.GetClipRGN(DC, RGN);
|
Result := Windows.GetClipRGN(DC, RGN);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------
|
||||||
|
Method: GetCompositorExtendedBorder
|
||||||
|
Params:
|
||||||
|
handle - A handle to a window
|
||||||
|
Borders - Record to recieve borders
|
||||||
|
Returns: If the function succeeds, return the internal border added by the compositor. Positive values indicate the window
|
||||||
|
appears smaller than it is.
|
||||||
|
If the function fails, Rect is unchanged.
|
||||||
|
Example:
|
||||||
|
If GetWindowRect returned Rect(0, 0, 1280, 1024) on Windows 10, the visible bounds rect is much smaller, with the difference
|
||||||
|
appearing as if it is not part of the window (transparent shadow). The "actual" frame is drawn at Rect(7, 0, 1273, 1017).
|
||||||
|
In this case, this function returns Rect(7, 0, 7, 7)
|
||||||
|
------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
function TWin32WidgetSet.GetCompositorExtendedBorder(handle : HWND; var Borders: TRect) : Boolean;
|
||||||
|
var
|
||||||
|
wr, efb: TRect;
|
||||||
|
begin
|
||||||
|
if not Assigned(DwmGetWindowAttribute) or not DwmCompositionEnabled then begin
|
||||||
|
// system does not have a compositor - no extended border
|
||||||
|
Borders:= Rect(0, 0, 0, 0);
|
||||||
|
Exit(True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result:= GetWindowRect(handle, wr) <> 0;
|
||||||
|
if not Result then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
Result:= DwmGetWindowAttribute(handle, DWMWA_EXTENDED_FRAME_BOUNDS, @efb, sizeof(efb)) = S_OK;
|
||||||
|
if not Result then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
Borders.Left:= efb.Left - wr.Left;
|
||||||
|
Borders.Top:= efb.Top - wr.Top;
|
||||||
|
Borders.Right:= wr.Right - efb.Right;
|
||||||
|
Borders.Bottom:= wr.Bottom - efb.Bottom;
|
||||||
|
end;
|
||||||
|
|
||||||
{------------------------------------------------------------------------------
|
{------------------------------------------------------------------------------
|
||||||
Method: GetCurrentObject
|
Method: GetCurrentObject
|
||||||
Params:
|
Params:
|
||||||
|
@ -97,6 +97,7 @@ function GetClientBounds(Handle: HWND; Var Rect: TRect): Boolean; override;
|
|||||||
function GetClientRect(Handle: HWND; Var Rect: TRect): Boolean; override;
|
function GetClientRect(Handle: HWND; Var Rect: TRect): Boolean; override;
|
||||||
function GetClipBox(DC : hDC; lpRect : PRect) : Longint; override;
|
function GetClipBox(DC : hDC; lpRect : PRect) : Longint; override;
|
||||||
function GetClipRGN(DC : hDC; RGN : hRGN) : Longint; override;
|
function GetClipRGN(DC : hDC; RGN : hRGN) : Longint; override;
|
||||||
|
function GetCompositorExtendedBorder(handle : HWND; var Borders: TRect) : Boolean; override;
|
||||||
function GetCurrentObject(DC: HDC; uObjectType: UINT): HGDIOBJ; override;
|
function GetCurrentObject(DC: HDC; uObjectType: UINT): HGDIOBJ; override;
|
||||||
function GetCursorPos(var LPPoint: TPoint): Boolean; override;
|
function GetCursorPos(var LPPoint: TPoint): Boolean; override;
|
||||||
function GetDC(HWnd: HWND): HDC; override;
|
function GetDC(HWnd: HWND): HDC; override;
|
||||||
|
Loading…
Reference in New Issue
Block a user