@@ -17,8 +17,10 @@ public sealed class AvaloniaQuickWindowLayoutController : IQuickWindowLayoutCont
1717 /// <param name="target">The target screen region.</param>
1818 public void Move ( Window window , QuickMoveTarget target )
1919 {
20- double scaling = GetScaling ( window ) ;
21- WindowRect result = QuickWindowLayout . Move ( ToPhysicalRect ( window , scaling ) , GetWorkingArea ( window ) , target ) ;
20+ double scaling = WindowScreenScaling . Get ( window ) ;
21+ WindowRect current = ToPhysicalRect ( window , scaling ) ;
22+ WindowRect result = QuickWindowLayout . Move ( current , GetWorkingArea ( window ) , target ) ;
23+ AppLogger . Debug ( $ "QuickLayout move: target={ target } scaling={ scaling } current={ current } result={ result } ") ;
2224 Apply ( window , result , scaling ) ;
2325 }
2426
@@ -30,14 +32,16 @@ public void Move(Window window, QuickMoveTarget target)
3032 /// <param name="height">The requested height in logical units.</param>
3133 public void Resize ( Window window , double width , double height )
3234 {
33- double scaling = GetScaling ( window ) ;
35+ double scaling = WindowScreenScaling . Get ( window ) ;
36+ WindowRect current = ToPhysicalRect ( window , scaling ) ;
3437 WindowRect result = QuickWindowLayout . Resize (
35- ToPhysicalRect ( window , scaling ) ,
38+ current ,
3639 GetWorkingArea ( window ) ,
3740 width * scaling ,
3841 height * scaling ,
3942 window . MinWidth * scaling ,
4043 window . MinHeight * scaling ) ;
44+ AppLogger . Debug ( $ "QuickLayout resize: requestedDip={ width } x{ height } scaling={ scaling } current={ current } result={ result } ") ;
4145 Apply ( window , result , scaling ) ;
4246 }
4347
@@ -49,26 +53,26 @@ public void Resize(Window window, double width, double height)
4953 public void ApplyBounds ( Window window , WindowRect bounds )
5054 {
5155 // Left/Top arrive in physical pixels (window position space) and Width/Height in DIP
52- // (window size space), so each component is applied to its matching coordinate space.
53- window . Position = new PixelPoint ( ( int ) Math . Round ( bounds . Left ) , ( int ) Math . Round ( bounds . Top ) ) ;
56+ // (window size space). Left/Top is mapped through the platform position seam (identity on
57+ // Windows, divide-by-scaling on macOS); Width/Height are already DIP and applied directly.
58+ double scaling = WindowScreenScaling . Get ( window ) ;
59+ int left = ( int ) Math . Round ( WindowPositionScaling . PhysicalToPosition ( bounds . Left , scaling , WindowPositionScaling . PositionIsLogical ) ) ;
60+ int top = ( int ) Math . Round ( WindowPositionScaling . PhysicalToPosition ( bounds . Top , scaling , WindowPositionScaling . PositionIsLogical ) ) ;
61+ window . Position = new PixelPoint ( left , top ) ;
5462 window . Width = Math . Max ( window . MinWidth , bounds . Width ) ;
5563 window . Height = Math . Max ( window . MinHeight , bounds . Height ) ;
64+ AppLogger . Debug ( $ "QuickLayout applyBounds: bounds={ bounds } scaling={ scaling } pos=({ left } ,{ top } ) sizeDip={ window . Width } x{ window . Height } ") ;
5665 }
5766
58- // Avalonia exposes window position in physical pixels but width/height in logical units,
59- // while screen working areas are physical pixels. Quick-layout math must run in a single
60- // space, so everything is normalized to physical pixels here using the window scaling.
67+ // Avalonia exposes window width/height in logical units while screen working areas are physical
68+ // pixels, and Window.Position is physical pixels on Windows but logical points on macOS. Quick-
69+ // layout math must run in a single space, so everything is normalized to physical pixels here:
70+ // the position is mapped through the platform seam and the DIP size is multiplied by scaling.
6171 private static WindowRect ToPhysicalRect ( Window window , double scaling )
6272 {
63- return new WindowRect ( window . Position . X , window . Position . Y , window . Width * scaling , window . Height * scaling ) ;
64- }
65-
66- private static double GetScaling ( Window window )
67- {
68- Screen ? screen = window . Screens . ScreenFromWindow ( window ) ?? window . Screens . Primary ;
69- double scaling = screen ? . Scaling ?? window . RenderScaling ;
70-
71- return scaling <= 0 ? 1.0 : scaling ;
73+ double left = WindowPositionScaling . PositionToPhysical ( window . Position . X , scaling , WindowPositionScaling . PositionIsLogical ) ;
74+ double top = WindowPositionScaling . PositionToPhysical ( window . Position . Y , scaling , WindowPositionScaling . PositionIsLogical ) ;
75+ return new WindowRect ( left , top , window . Width * scaling , window . Height * scaling ) ;
7276 }
7377
7478 private static WindowRect GetWorkingArea ( Window window )
@@ -81,9 +85,12 @@ private static WindowRect GetWorkingArea(Window window)
8185
8286 private static void Apply ( Window window , WindowRect rect , double scaling )
8387 {
84- window . Position = new PixelPoint ( ( int ) Math . Round ( rect . Left ) , ( int ) Math . Round ( rect . Top ) ) ;
88+ int left = ( int ) Math . Round ( WindowPositionScaling . PhysicalToPosition ( rect . Left , scaling , WindowPositionScaling . PositionIsLogical ) ) ;
89+ int top = ( int ) Math . Round ( WindowPositionScaling . PhysicalToPosition ( rect . Top , scaling , WindowPositionScaling . PositionIsLogical ) ) ;
90+ window . Position = new PixelPoint ( left , top ) ;
8591 window . Width = rect . Width / scaling ;
8692 window . Height = rect . Height / scaling ;
93+ AppLogger . Debug ( $ "QuickLayout apply: rect={ rect } scaling={ scaling } pos=({ left } ,{ top } ) sizeDip={ window . Width } x{ window . Height } ") ;
8794 }
8895 }
8996}
0 commit comments