Skip to content

Fix white border artifact on maximized Form (Windows 11)#116

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-white-border-win11
Draft

Fix white border artifact on maximized Form (Windows 11)#116
Copilot wants to merge 3 commits intomainfrom
copilot/fix-white-border-win11

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

On Windows 11 (particularly at fractional DPI scaling), maximizing a Form with UseSystemDecorations = false produces empty space at the window edges where content is not drawn and the window background shows through. The content is in the correct location but is clipped, and the top/left edge is not fully drawn.

Root Causes

Two separate root causes were identified and fixed:

1. Form always painted a 1px border even when maximizedForm.DefaultStyle sets Border.Width = 1, creating a visible colored strip at the screen edges and an offset that prevents content from filling the window corners.

2. Floating-point precision loss in DoPaint and OnResizeScaledClientSize was computed as (int)(ClientSize.Width * RenderScaling). Because ClientSize.Width = GetClientRect.right / RenderScaling (a float division), the round-trip pixels ÷ scale × scale loses 1 pixel — e.g. 2576 / 1.5 × 1.5 = 2575.999… → (int) = 2575. This made the DrawBorder rectangle and ClipRect 1 pixel too small, leaving a strip of form background at the edges and clipping the top/left content pixel.

Changes

  • No border when maximized (Form.cs) — Added a per-instance maximized_style (ControlStyle inheriting dynamically from the instance Style via parent chain) with Border.Width = 0. CurrentStyle is overridden to return it when WindowState == Maximized, causing ControlAdapter.OnPaint to use form_x = form_y = 0 so controls fill from the very edge of the framebuffer.

  • Disable resize handling when maximized (Form.cs) — HandleMouseDown returns false immediately when maximized (prevents accidental resize drags from window edges). HandleMouseMove delegates to base when maximized (suppresses resize cursors).

  • Use actual framebuffer dimensions in DoPaint (WindowBase.cs) — Replaced ScaledClientSize with framebuffer.Size.Width/Height for both DrawBorder and ClipRect, eliminating the float round-trip precision loss. Also fixed the ClipRect formula from the accidentally-correct Width+1 to the semantically correct fb_display_rect.Right/Bottom.

  • Use Math.Ceiling in OnResize (WindowBase.cs) — Changed adapter.SetBounds from (int)size.Width to (int)Math.Ceiling(size.Width) so controls always cover the full framebuffer even when the logical window size is fractional (e.g. 2576 px / 1.5 = 1717.33 logical px).

// maximized_style suppresses the border when the window is maximized
maximized_style = new ControlStyle(Style);
maximized_style.Border.Width = 0;

public override ControlStyle CurrentStyle =>
    WindowState == FormWindowState.Maximized ? maximized_style : base.CurrentStyle;

// DoPaint: use exact framebuffer dimensions to avoid float round-trip loss
var fb_width = framebuffer.Size.Width;
var fb_height = framebuffer.Size.Height;
e.Canvas.DrawBorder(new Rectangle(0, 0, fb_width, fb_height), CurrentStyle);
e.Canvas.ClipRect(new SKRect(fb_display_rect.Left, fb_display_rect.Top,
                              fb_display_rect.Right, fb_display_rect.Bottom));

// OnResize: ceiling ensures controls fill the framebuffer at fractional DPI
adapter.SetBounds(DisplayRectangle.Left, DisplayRectangle.Top,
                  (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));

Copilot AI linked an issue Apr 3, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix white border maximization issue in Win11 Fix white border artifact on maximized Form (Windows 11) Apr 3, 2026
Copilot AI requested a review from jpobst April 3, 2026 01:03
@jpobst
Copy link
Copy Markdown
Collaborator

jpobst commented Apr 4, 2026

@copilot While these are good changes, it does not fix the "border" around the maximized window. Some additional information that might help solve the issue:

  • It is not actually a border, it is empty space on the left and right side where we are not drawing content, and the window background is showing through.
  • The content isn't simply moved down and right X pixels, it is in the correct location, however it is being clipped and the top/left edge is not getting fully drawn.
  • This only happens when Form.UseSystemDecorations = false. That is, when the system draws the window titlebar it works correctly. This blank space only appears when the system decorations are turned off and we are using the default custom FormTitleBar instead.

…eiling in OnResize

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>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot While these are good changes, it does not fix the "border" around the maximized window. Some additional information that might help solve the issue:

  • It is not actually a border, it is em...

Thanks for the detailed explanation — that pointed me to two additional root causes I was missing.

Root cause 1 — Border drawn even when maximized (addressed in first commit): Form.DefaultStyle always paints a 1px border, which creates a visible colored strip at the maximized window edges. I added a maximized_style with Border.Width = 0 and override CurrentStyle to return it when maximized. I also disabled the resize drag/cursor logic when maximized.

Root cause 2 — Float precision loss in DoPaint and OnResize (commit 9b3dba8): This is the actual source of the "empty space on left/right" and "content clipped" behavior. The original code computed ScaledClientSize as (int)(ClientSize.Width * RenderScaling). Because ClientSize.Width = GetClientRect.right / RenderScaling (a float division), the round-trip pixels ÷ scale × scale loses 1 pixel — e.g. 2576 / 1.5 × 1.5 = 2575.999… → (int) = 2575. This made the DrawBorder rect and ClipRect 1 pixel too small, leaving a strip of form background showing at the edges, and the ClipRect starting inside the first content pixel, causing the top/left clipping artefact.

Fixes in WindowBase.cs:

  • DoPaint: use framebuffer.Size.Width/Height directly (the exact pixel count from the OS) for DrawBorder and ClipRect; also fixed the ClipRect formula from the accidentally-correct Width+1 to the semantically correct fb_display_rect.Right/Bottom
  • OnResize: use Math.Ceiling(size.Width/Height) instead of truncating (int) so controls always cover the full framebuffer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Maximize the white border of the Win11

2 participants