From b35cac5654fb381971d9b2c0dc797c50393e7830 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 00:51:49 +0000 Subject: [PATCH 1/3] Initial plan From 8a63bc056044b090249de53b30c17074cbf70247 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 01:02:24 +0000 Subject: [PATCH 2/3] Fix white border artifact when maximizing Form on Windows 11 Agent-Logs-Url: https://github.com/modern-forms/Modern.Forms/sessions/5ed1c64d-ba49-4a69-b431-72f7f13f8d22 Co-authored-by: jpobst <179295+jpobst@users.noreply.github.com> --- src/Modern.Forms/Form.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Modern.Forms/Form.cs b/src/Modern.Forms/Form.cs index c456f25..f3991c8 100644 --- a/src/Modern.Forms/Form.cs +++ b/src/Modern.Forms/Form.cs @@ -24,6 +24,7 @@ public class Form : WindowBase, ICloseable private bool show_focus_cues; private string text = string.Empty; private bool use_system_decorations; + private readonly ControlStyle maximized_style; /// /// Initializes a new instance of the Form class. @@ -32,6 +33,11 @@ public Form () : base (AvaloniaGlobals.GetRequiredService () { TitleBar = Controls.AddImplicitControl (new FormTitleBar ()); + // Style used when the window is maximized: inherits everything from the instance + // Style but suppresses the border so no thin colored strip is visible at the edges. + maximized_style = new ControlStyle (Style); + maximized_style.Border.Width = 0; + Resizeable = true; Window.SetSystemDecorations (SystemDecorations.None); Window.SetExtendClientAreaToDecorationsHint (true); @@ -79,6 +85,10 @@ public bool AllowMinimize { } } + /// + /// Returns a no-border style when the window is maximized to prevent a thin border artifact at screen edges. + public override ControlStyle CurrentStyle => WindowState == FormWindowState.Maximized ? maximized_style : base.CurrentStyle; + /// public override void Close () { @@ -183,6 +193,9 @@ private WindowElement GetElementAtLocation (int x, int y) internal override bool HandleMouseDown (int x, int y) { + if (WindowState == FormWindowState.Maximized) + return false; + var element = GetElementAtLocation (x, y); switch (element) { @@ -217,6 +230,9 @@ internal override bool HandleMouseDown (int x, int y) internal override bool HandleMouseMove (int x, int y) { + if (WindowState == FormWindowState.Maximized) + return base.HandleMouseMove (x, y); + var element = GetElementAtLocation (x, y); switch (element) { From 9b3dba8034d8bffadd769f765d954392b09a9a32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:39:56 +0000 Subject: [PATCH 3/3] Fix maximize white border: use framebuffer size in DoPaint and Math.Ceiling in OnResize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two root causes are addressed: 1. DoPaint used ScaledClientSize (= (int)(ClientSize * scale)) for the DrawBorder rect and ClipRect. The float round-trip loses 1 device pixel at fractional DPI (e.g. 2576/1.5*1.5 = 2575.99 → int 2575), leaving a 1-pixel strip of form background visible at the right/bottom edges. Fix: use framebuffer.Size directly (the actual pixel count from the OS), and use fb_display_rect.Right/Bottom for the ClipRect instead of the coincidentally-correct Width+1/Height+1 formula. 2. OnResize passed (int)size.Width to adapter.SetBounds, truncating any fractional logical width. Controls ended up 1 logical pixel too narrow, so their device pixel buffers were 1-2 pixels short of the framebuffer. Fix: use Math.Ceiling(size.Width/Height) so controls always cover the full framebuffer even when the logical size is non-integer. Agent-Logs-Url: https://github.com/modern-forms/Modern.Forms/sessions/ea515327-4889-4d74-8182-1e6b64106d6c Co-authored-by: jpobst <179295+jpobst@users.noreply.github.com> --- src/Modern.Forms/WindowBase.cs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Modern.Forms/WindowBase.cs b/src/Modern.Forms/WindowBase.cs index 0a89e82..84ca328 100644 --- a/src/Modern.Forms/WindowBase.cs +++ b/src/Modern.Forms/WindowBase.cs @@ -294,17 +294,26 @@ private void DoPaint (Rect r) var framebufferImageInfo = new SKImageInfo (framebuffer.Size.Width, framebuffer.Size.Height, framebuffer.Format.ToSkColorType (), framebuffer.Format == PixelFormat.Rgb565 ? SKAlphaType.Opaque : SKAlphaType.Premul); - var scaled_client_size = ScaledClientSize; - var scaled_display_rect = ScaledDisplayRectangle; + // Use the actual framebuffer pixel dimensions directly. Computing the size via + // (int)(ClientSize * RenderScaling) can lose 1 pixel at fractional DPI (e.g. 150%) + // because the float round-trip (pixels / scale * scale) truncates to one fewer pixel, + // leaving a strip of unfilled background at the right/bottom edges. + var fb_width = framebuffer.Size.Width; + var fb_height = framebuffer.Size.Height; + var border = CurrentStyle.Border; + var fb_display_rect = new System.Drawing.Rectangle ( + border.Left.GetWidth (), border.Top.GetWidth (), + fb_width - border.Left.GetWidth () - border.Right.GetWidth (), + fb_height - border.Top.GetWidth () - border.Bottom.GetWidth ()); using var surface = SKSurface.Create (framebufferImageInfo, framebuffer.Address, framebuffer.RowBytes); var e = new PaintEventArgs (framebufferImageInfo, surface.Canvas, Scaling); OnPaintBackground (e); - e.Canvas.DrawBorder (new System.Drawing.Rectangle (0, 0, (int)scaled_client_size.Width, (int)scaled_client_size.Height), CurrentStyle); + e.Canvas.DrawBorder (new System.Drawing.Rectangle (0, 0, fb_width, fb_height), CurrentStyle); OnPaint (e); - e.Canvas.ClipRect (new SKRect (scaled_display_rect.Left, scaled_display_rect.Top, scaled_display_rect.Width + 1, scaled_display_rect.Height + 1)); + e.Canvas.ClipRect (new SKRect (fb_display_rect.Left, fb_display_rect.Top, fb_display_rect.Right, fb_display_rect.Bottom)); adapter.RaisePaintBackground (e); adapter.RaisePaint (e); @@ -344,7 +353,11 @@ protected virtual void OnPaintBackground (PaintEventArgs e) private void OnResize (Size size, WindowResizeReason reason) { - adapter.SetBounds (DisplayRectangle.Left, DisplayRectangle.Top, Size.Width, Size.Height); + // Use Math.Ceiling so controls are sized to cover the full framebuffer even when + // the logical window size is fractional (e.g. 2576 device px / 1.5 = 1717.33 logical px). + // Without ceiling, (int) truncation would make controls 1 logical pixel too narrow, + // leaving a strip of form background showing at the right/bottom edges. + adapter.SetBounds (DisplayRectangle.Left, DisplayRectangle.Top, (int)Math.Ceiling (size.Width), (int)Math.Ceiling (size.Height)); } ///