diff --git a/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs b/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs
index 7a282bf306..26dffa8f5d 100644
--- a/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs
+++ b/src/Avalonia.Controls/Chrome/WindowDrawnDecorations.cs
@@ -1,6 +1,7 @@
using System;
using Avalonia.Automation;
using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.LogicalTree;
@@ -15,7 +16,8 @@ namespace Avalonia.Controls.Chrome;
/// TopLevelHost extracts overlay/underlay/popover visuals from the template content
/// and inserts them into its own visual tree.
///
-[PseudoClasses(pcNormal, pcMaximized, pcFullscreen, pcHasShadow, pcHasBorder, pcHasTitlebar)]
+[PseudoClasses(pcNormal, pcMaximized, pcFullscreen, pcHasShadow, pcHasBorder, pcHasTitlebar,
+ pcHasMaximize, pcHasFullscreen, pcHasMinimize)]
[TemplatePart(PART_CloseButton, typeof(Button))]
[TemplatePart(PART_MinimizeButton, typeof(Button))]
[TemplatePart(PART_MaximizeButton, typeof(Button))]
@@ -31,6 +33,9 @@ public class WindowDrawnDecorations : StyledElement
internal const string pcHasShadow = ":has-shadow";
internal const string pcHasBorder = ":has-border";
internal const string pcHasTitlebar = ":has-titlebar";
+ internal const string pcHasMaximize = ":has-maximize";
+ internal const string pcHasFullscreen = ":has-fullscreen";
+ internal const string pcHasMinimize = ":has-minimize";
// Template part names for caption buttons
internal const string PART_CloseButton = "PART_CloseButton";
@@ -383,8 +388,11 @@ public class WindowDrawnDecorations : StyledElement
Detach();
_hostWindow = window;
+ window.AllowedWindowActionsChanged += OnAllowedWindowActionsChanged;
+
_windowSubscriptions = new CompositeDisposable
{
+ Disposable.Create(() => window.AllowedWindowActionsChanged -= OnAllowedWindowActionsChanged),
window.GetObservable(Window.TitleProperty)
.Subscribe(title => SetCurrentValue(TitleProperty, title)),
window.GetObservable(Window.CanMaximizeProperty)
@@ -407,6 +415,7 @@ public class WindowDrawnDecorations : StyledElement
}),
};
+ UpdateAllowedActionsPseudoClasses();
UpdateMaximizeButtonState();
UpdateMinimizeButtonState();
UpdateFullScreenButtonState();
@@ -547,32 +556,54 @@ public class WindowDrawnDecorations : StyledElement
e.Handled = true;
}
+ private PlatformAllowedWindowActions EffectiveAllowedActions =>
+ _hostWindow?.AllowedWindowActions ?? PlatformAllowedWindowActions.All;
+
private void UpdateMaximizeButtonState()
{
if (_maximizeButton == null)
return;
- _maximizeButton.IsEnabled = _hostWindow?.WindowState switch
- {
- WindowState.Maximized or WindowState.FullScreen => _hostWindow.CanResize,
- WindowState.Normal => _hostWindow.CanMaximize,
- _ => true
- };
+ _maximizeButton.IsEnabled = EffectiveAllowedActions.HasFlag(PlatformAllowedWindowActions.Maximize)
+ && (_hostWindow?.WindowState switch
+ {
+ WindowState.Maximized or WindowState.FullScreen => _hostWindow.CanResize,
+ WindowState.Normal => _hostWindow.CanMaximize,
+ _ => true
+ });
}
private void UpdateMinimizeButtonState()
{
if (_minimizeButton == null)
return;
- _minimizeButton.IsEnabled = _hostWindow?.CanMinimize ?? true;
+ _minimizeButton.IsEnabled = EffectiveAllowedActions.HasFlag(PlatformAllowedWindowActions.Minimize)
+ && (_hostWindow?.CanMinimize ?? true);
}
private void UpdateFullScreenButtonState()
{
if (_fullScreenButton == null)
return;
- _fullScreenButton.IsEnabled = _hostWindow?.WindowState == WindowState.FullScreen
- ? _hostWindow.CanResize
- : _hostWindow?.CanMaximize ?? true;
+ _fullScreenButton.IsEnabled = EffectiveAllowedActions.HasFlag(PlatformAllowedWindowActions.Fullscreen)
+ && (_hostWindow?.WindowState == WindowState.FullScreen
+ ? _hostWindow.CanResize
+ : _hostWindow?.CanMaximize ?? true);
+ }
+
+ private void OnAllowedWindowActionsChanged(PlatformAllowedWindowActions actions)
+ {
+ UpdateAllowedActionsPseudoClasses();
+ UpdateMaximizeButtonState();
+ UpdateMinimizeButtonState();
+ UpdateFullScreenButtonState();
+ }
+
+ private void UpdateAllowedActionsPseudoClasses()
+ {
+ var actions = EffectiveAllowedActions;
+ PseudoClasses.Set(pcHasMaximize, actions.HasFlag(PlatformAllowedWindowActions.Maximize));
+ PseudoClasses.Set(pcHasFullscreen, actions.HasFlag(PlatformAllowedWindowActions.Fullscreen));
+ PseudoClasses.Set(pcHasMinimize, actions.HasFlag(PlatformAllowedWindowActions.Minimize));
}
private void UpdateEffectiveGeometry()
diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs
index 42be775f0d..d864ca35c3 100644
--- a/src/Avalonia.Controls/Platform/IWindowImpl.cs
+++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs
@@ -162,5 +162,15 @@ namespace Avalonia.Platform
///
/// -1 for platform default, otherwise the height in DIPs.
void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight);
+
+ ///
+ /// Gets the window actions that the underlying platform currently allows.
+ ///
+ PlatformAllowedWindowActions AllowedWindowActions => PlatformAllowedWindowActions.All;
+
+ ///
+ /// Gets or sets a callback invoked when changes.
+ ///
+ Action? AllowedWindowActionsChanged { get => null; set { } }
}
}
diff --git a/src/Avalonia.Controls/Platform/PlatformAllowedWindowActions.cs b/src/Avalonia.Controls/Platform/PlatformAllowedWindowActions.cs
new file mode 100644
index 0000000000..35871c0803
--- /dev/null
+++ b/src/Avalonia.Controls/Platform/PlatformAllowedWindowActions.cs
@@ -0,0 +1,33 @@
+using System;
+using Avalonia.Metadata;
+
+namespace Avalonia.Controls.Platform;
+
+///
+/// Flags indicating which window actions the underlying platform supports.
+///
+[Flags, PrivateApi]
+public enum PlatformAllowedWindowActions
+{
+ None = 0,
+
+ ///
+ /// The underlying platform supports maximizing/unmaximizing windows.
+ ///
+ Maximize = 1 << 0,
+
+ ///
+ /// The underlying platform supports fullscreen mode.
+ ///
+ Fullscreen = 1 << 1,
+
+ ///
+ /// The underlying platform supports minimizing windows.
+ ///
+ Minimize = 1 << 2,
+
+ ///
+ /// All actions are supported (default when the underlying platform does not report capabilities).
+ ///
+ All = Maximize | Fullscreen | Minimize,
+}
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 4dab3574eb..0797f39733 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -220,6 +220,7 @@ namespace Avalonia.Controls
private bool _positionWasSet;
private bool _wasShownBefore;
private IDisposable? _modalSubscription;
+ private PlatformAllowedWindowActions _allowedWindowActions = PlatformAllowedWindowActions.All;
///
/// Initializes static members of the class.
@@ -250,6 +251,8 @@ namespace Avalonia.Controls
impl.WindowStateChanged = HandleWindowStateChanged;
_maxPlatformClientSize = PlatformImpl?.MaxAutoSizeHint ?? default(Size);
impl.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged;
+ impl.AllowedWindowActionsChanged = OnAllowedWindowActionsChanged;
+ _allowedWindowActions = impl.AllowedWindowActions;
this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x =>
{
ResizePlatformImpl(x, WindowResizeReason.Application);
@@ -485,6 +488,11 @@ namespace Avalonia.Controls
set => SetValue(CanMaximizeProperty, value);
}
+ ///
+ /// Gets the window actions currently allowed by the underlying platform.
+ ///
+ internal PlatformAllowedWindowActions AllowedWindowActions => _allowedWindowActions;
+
///
/// Gets or sets the icon of the window.
///
@@ -673,6 +681,14 @@ namespace Avalonia.Controls
UpdateDrawnDecorationParts();
}
+ internal event Action? AllowedWindowActionsChanged;
+
+ private void OnAllowedWindowActionsChanged(PlatformAllowedWindowActions actions)
+ {
+ _allowedWindowActions = actions;
+ AllowedWindowActionsChanged?.Invoke(actions);
+ }
+
private void ExtendClientAreaToDecorationsChanged(bool isExtended)
{
IsExtendedIntoWindowDecorations = isExtended;
diff --git a/src/Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.xaml b/src/Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.xaml
index b2d66fdbbd..3ccda42ce3 100644
--- a/src/Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/WindowDrawnDecorations.xaml
@@ -196,6 +196,20 @@
+
+
+
+
+
+
+
+
+
+
+
+