diff --git a/src/Avalonia.Controls/Platform/IWin32OptionsTopLevelImpl.cs b/src/Avalonia.Controls/Platform/IWin32OptionsTopLevelImpl.cs
index 2e363e647d6..9ca897a948d 100644
--- a/src/Avalonia.Controls/Platform/IWin32OptionsTopLevelImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWin32OptionsTopLevelImpl.cs
@@ -21,5 +21,10 @@ public interface IWin32OptionsTopLevelImpl : ITopLevelImpl
/// Gets or sets a custom callback for the window's WndProc
///
public CustomWndProcHookCallback? WndProcHookCallback { get; set; }
+
+ ///
+ /// Sets hints that configure the shape of window corners.
+ ///
+ void SetWindowCornerHints(Win32WindowCornerHints hints);
}
}
diff --git a/src/Avalonia.Controls/Platform/Win32CornerHints.cs b/src/Avalonia.Controls/Platform/Win32CornerHints.cs
new file mode 100644
index 00000000000..cb197cf8f6e
--- /dev/null
+++ b/src/Avalonia.Controls/Platform/Win32CornerHints.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Avalonia.Platform;
+
+///
+/// Specifies hints for window corner appearance.
+///
+[Flags]
+public enum Win32WindowCornerHints
+{
+ ///
+ /// Default Avalonia behavior.
+ ///
+ NoHint,
+
+ ///
+ /// The platform's default corner style.
+ ///
+ PlatformDefault,
+
+ ///
+ /// Rounded corners for the window.
+ ///
+ Rounded,
+
+ ///
+ /// Prevents corners from being rounded.
+ ///
+ NotRounded
+}
diff --git a/src/Avalonia.Controls/Platform/Win32Properties.cs b/src/Avalonia.Controls/Platform/Win32Properties.cs
index 13b1333ee64..badb69b0702 100644
--- a/src/Avalonia.Controls/Platform/Win32Properties.cs
+++ b/src/Avalonia.Controls/Platform/Win32Properties.cs
@@ -14,8 +14,14 @@ namespace Avalonia.Controls
///
/// Set of Win32 specific properties and events that allow deeper customization of the application per platform.
///
- public static class Win32Properties
+ public class Win32Properties
{
+ public static readonly AttachedProperty WindowCornerHintProperty =
+ AvaloniaProperty.RegisterAttached("WindowCornerHint");
+
+ public static void SetWindowCornerHint(Window obj, Win32WindowCornerHints value) => obj.SetValue(WindowCornerHintProperty, value);
+ public static Win32WindowCornerHints GetWindowCornerHint(Window obj) => obj.GetValue(WindowCornerHintProperty);
+
public delegate (uint style, uint exStyle) CustomWindowStylesCallback(uint style, uint exStyle);
public delegate IntPtr CustomWndProcHookCallback(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, ref bool handled);
@@ -70,5 +76,16 @@ public static void RemoveWndProcHookCallback(TopLevel topLevel, CustomWndProcHoo
toplevelImpl.WndProcHookCallback -= callback;
}
}
+
+ static Win32Properties()
+ {
+ WindowCornerHintProperty.Changed.AddClassHandler((window, e) =>
+ {
+ if (window.PlatformImpl is IWin32OptionsTopLevelImpl toplevelImpl)
+ {
+ toplevelImpl.SetWindowCornerHints(e.GetNewValue());
+ }
+ });
+ }
}
}
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index a9bd0c41966..3c9e972c258 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -100,6 +100,7 @@ internal partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindow
private POINT _maxTrackSize;
private WindowImpl? _parent;
private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default;
+ private Win32WindowCornerHints _cornerHints;
private bool _isCloseRequested;
private bool _shown;
private bool _hiddenWindowIsParent;
@@ -1133,6 +1134,30 @@ private MARGINS UpdateExtendMargins()
return margins;
}
+ private static DwmWindowCornerPreference HintsToCornerPreference(Win32WindowCornerHints cornerHints, DwmWindowCornerPreference noHintDefault)
+ {
+ return cornerHints switch
+ {
+ Win32WindowCornerHints.NoHint => noHintDefault,
+ Win32WindowCornerHints.PlatformDefault => DwmWindowCornerPreference.DWMWCP_DEFAULT,
+ Win32WindowCornerHints.Rounded => DwmWindowCornerPreference.DWMWCP_ROUND,
+ Win32WindowCornerHints.NotRounded => DwmWindowCornerPreference.DWMWCP_DONOTROUND,
+ _ => throw new ArgumentOutOfRangeException(nameof(cornerHints), cornerHints, null)
+ };
+ }
+
+ private void UpdateWindowCornerPreference()
+ {
+ int cornerPreference = (int)HintsToCornerPreference(_cornerHints,
+ _isClientAreaExtended && WindowState != WindowState.FullScreen ?
+ DwmWindowCornerPreference.DWMWCP_ROUND :
+ DwmWindowCornerPreference.DWMWCP_DEFAULT);
+ unsafe
+ {
+ DwmSetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPreference, sizeof(int));
+ }
+ }
+
private void ExtendClientArea()
{
if (!_shown)
@@ -1151,12 +1176,6 @@ private void ExtendClientArea()
{
var margins = UpdateExtendMargins();
DwmExtendFrameIntoClientArea(_hwnd, ref margins);
-
- unsafe
- {
- int cornerPreference = (int)DwmWindowCornerPreference.DWMWCP_ROUND;
- DwmSetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPreference, sizeof(int));
- }
}
else
{
@@ -1165,14 +1184,10 @@ private void ExtendClientArea()
_offScreenMargin = new Thickness();
_extendedMargins = new Thickness();
-
- unsafe
- {
- int cornerPreference = (int)DwmWindowCornerPreference.DWMWCP_DEFAULT;
- DwmSetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPreference, sizeof(int));
- }
}
+ UpdateWindowCornerPreference();
+
if (!_isClientAreaExtended || (_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.SystemChrome) &&
!_extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome)))
{
@@ -1592,6 +1607,14 @@ public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight)
ExtendClientArea();
}
+ ///
+ public void SetWindowCornerHints(Win32WindowCornerHints hints)
+ {
+ _cornerHints = hints;
+
+ UpdateWindowCornerPreference();
+ }
+
///
public void GetWindowsZOrder(Span windows, Span zOrder)
{