diff --git a/src/OddSnap/App.xaml b/src/OddSnap/App.xaml
index 71e62bb4..ce66b318 100644
--- a/src/OddSnap/App.xaml
+++ b/src/OddSnap/App.xaml
@@ -85,7 +85,7 @@
-
+
diff --git a/src/OddSnap/UI/OddSnapWindowChrome.cs b/src/OddSnap/UI/OddSnapWindowChrome.cs
index 342c4111..71261d04 100644
--- a/src/OddSnap/UI/OddSnapWindowChrome.cs
+++ b/src/OddSnap/UI/OddSnapWindowChrome.cs
@@ -7,20 +7,20 @@ namespace OddSnap.UI;
public static class OddSnapWindowChrome
{
- private const double DefaultCornerRadius = 12;
+ private const double DefaultCornerRadius = 7;
- public static void Apply(Window window)
+ public static void Apply(Window window, double cornerRadius = DefaultCornerRadius)
{
WindowChrome.SetWindowChrome(window, new WindowChrome
{
CaptionHeight = 0,
- CornerRadius = new CornerRadius(DefaultCornerRadius),
+ CornerRadius = new CornerRadius(cornerRadius),
GlassFrameThickness = new Thickness(0),
ResizeBorderThickness = new Thickness(8),
UseAeroCaptionButtons = false
});
- ApplyRoundedCorners(window, DefaultCornerRadius);
+ ApplyRoundedCorners(window, cornerRadius);
}
public static void ApplyRoundedCorners(Window window, double radius)
@@ -35,6 +35,10 @@ void ApplyCurrentRegion()
Dwm.TrySetWindowCornerPreference(hwnd, Dwm.DWMWCP_ROUND);
Dwm.TrySetImmersiveDarkMode(hwnd, Theme.IsDark);
+
+ // On Windows 11 DWM rounds layered windows themselves, so clipping
+ // a region on top of that would leave a crescent wherever the two
+ // roundings disagree. Only Windows 10 needs the manual region.
if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000))
return;
@@ -43,8 +47,15 @@ void ApplyCurrentRegion()
window.SourceInitialized += (_, _) => ApplyCurrentRegion();
window.SizeChanged += (_, _) => ApplyCurrentRegion();
+
+ // On Windows 10 the region must be recomputed when the UI scale
+ // changes, because the content rounding scales with it.
+ void OnUiScaleChanged(double _) => ApplyCurrentRegion();
+ UiScale.Changed += OnUiScaleChanged;
+
window.Closed += (_, _) =>
{
+ UiScale.Changed -= OnUiScaleChanged;
var hwnd = new WindowInteropHelper(window).Handle;
if (hwnd != IntPtr.Zero)
User32.SetWindowRgn(hwnd, IntPtr.Zero, true);
@@ -60,10 +71,17 @@ private static void SetRoundedWindowRegion(Window window, IntPtr hwnd, double ra
var transform = source?.CompositionTarget?.TransformToDevice ?? System.Windows.Media.Matrix.Identity;
int width = Math.Max(1, (int)Math.Ceiling(window.ActualWidth * transform.M11));
int height = Math.Max(1, (int)Math.Ceiling(window.ActualHeight * transform.M22));
- int diameterX = Math.Max(1, (int)Math.Round(radius * 2 * transform.M11));
- int diameterY = Math.Max(1, (int)Math.Round(radius * 2 * transform.M22));
- var region = Gdi32.CreateRoundRectRgn(0, 0, width + 1, height + 1, diameterX, diameterY);
+ // The root element is scaled by UiScale via a LayoutTransform, so the
+ // visible corner radius is radius * uiScale in layout units.
+ var effectiveRadius = radius * UiScale.Current;
+
+ // GDI takes the ellipse *diameter*; WPF's CornerRadius is the radius.
+ int diameterX = Math.Max(2, (int)Math.Round(effectiveRadius * 2 * transform.M11));
+ int diameterY = Math.Max(2, (int)Math.Round(effectiveRadius * 2 * transform.M22));
+
+ // Use the exact device bounds so the region lines up with the content.
+ var region = Gdi32.CreateRoundRectRgn(0, 0, width, height, diameterX, diameterY);
if (region == IntPtr.Zero)
return;
diff --git a/src/OddSnap/UI/SettingsWindow.xaml b/src/OddSnap/UI/SettingsWindow.xaml
index 4c3e11e5..39820019 100644
--- a/src/OddSnap/UI/SettingsWindow.xaml
+++ b/src/OddSnap/UI/SettingsWindow.xaml
@@ -643,8 +643,13 @@
-
-
+
@@ -4491,5 +4496,4 @@
-
diff --git a/src/OddSnap/UI/UpscaleResultWindow.xaml b/src/OddSnap/UI/UpscaleResultWindow.xaml
index e3038267..8ca85e1e 100644
--- a/src/OddSnap/UI/UpscaleResultWindow.xaml
+++ b/src/OddSnap/UI/UpscaleResultWindow.xaml
@@ -22,7 +22,7 @@
-
+