diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h
index 37699082ed..7b911ef945 100644
--- a/native/Avalonia.Native/src/OSX/WindowImpl.h
+++ b/native/Avalonia.Native/src/OSX/WindowImpl.h
@@ -45,6 +45,10 @@ BEGIN_INTERFACE_MAP()
void DoZoom();
virtual HRESULT SetCanResize(bool value) override;
+
+ virtual HRESULT SetCanMinimize(bool value) override;
+
+ virtual HRESULT SetCanMaximize(bool value) override;
virtual HRESULT SetDecorations(SystemDecorations value) override;
@@ -82,7 +86,7 @@ BEGIN_INTERFACE_MAP()
bool CanBecomeKeyWindow ();
- bool CanZoom() override { return _isEnabled && _canResize; }
+ bool CanZoom() override { return _isEnabled && _canMaximize; }
protected:
virtual NSWindowStyleMask CalculateStyleMask() override;
@@ -94,6 +98,8 @@ private:
NSString *_lastTitle;
bool _isEnabled;
bool _canResize;
+ bool _canMinimize;
+ bool _canMaximize;
bool _fullScreenActive;
SystemDecorations _decorations;
AvnWindowState _lastWindowState;
diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm
index 341085ec08..5a57715b55 100644
--- a/native/Avalonia.Native/src/OSX/WindowImpl.mm
+++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm
@@ -16,6 +16,8 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events) : TopLevelImpl(events), WindowB
_extendClientHints = AvnDefaultChrome;
_fullScreenActive = false;
_canResize = true;
+ _canMinimize = true;
+ _canMaximize = true;
_decorations = SystemDecorationsFull;
_transitioningWindowState = false;
_inSetWindowState = false;
@@ -191,7 +193,8 @@ bool WindowImpl::IsZoomed() {
void WindowImpl::DoZoom() {
if (_decorations == SystemDecorationsNone ||
_decorations == SystemDecorationsBorderOnly ||
- _canResize == false) {
+ _canResize == false ||
+ _canMaximize == false) {
[Window setFrame:[Window screen].visibleFrame display:true];
} else {
[Window performZoom:Window];
@@ -208,6 +211,22 @@ HRESULT WindowImpl::SetCanResize(bool value) {
}
}
+HRESULT WindowImpl::SetCanMinimize(bool value) {
+ START_COM_ARP_CALL;
+
+ _canMinimize = value;
+ UpdateAppearance();
+ return S_OK;
+}
+
+HRESULT WindowImpl::SetCanMaximize(bool value) {
+ START_COM_ARP_CALL;
+
+ _canMaximize = value;
+ UpdateAppearance();
+ return S_OK;
+}
+
HRESULT WindowImpl::SetDecorations(SystemDecorations value) {
START_COM_CALL;
@@ -583,7 +602,7 @@ NSWindowStyleMask WindowImpl::CalculateStyleMask() {
break;
}
- if (!IsOwned()) {
+ if (_canMinimize && !IsOwned()) {
s |= NSWindowStyleMaskMiniaturizable;
}
@@ -611,9 +630,9 @@ void WindowImpl::UpdateAppearance() {
[closeButton setHidden:!hasTrafficLights];
[closeButton setEnabled:_isEnabled];
[miniaturizeButton setHidden:!hasTrafficLights];
- [miniaturizeButton setEnabled:_isEnabled];
+ [miniaturizeButton setEnabled:_isEnabled && _canMinimize];
[zoomButton setHidden:!hasTrafficLights];
- [zoomButton setEnabled:CanZoom()];
+ [zoomButton setEnabled:CanZoom() || (([Window styleMask] & NSWindowStyleMaskFullScreen) != 0 && _isEnabled)];
}
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events)
diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml
index adcfc285cd..53f41672a9 100644
--- a/samples/ControlCatalog/MainWindow.xaml
+++ b/samples/ControlCatalog/MainWindow.xaml
@@ -10,6 +10,9 @@
ExtendClientAreaToDecorationsHint="{Binding ExtendClientAreaEnabled}"
ExtendClientAreaChromeHints="{Binding ChromeHints}"
ExtendClientAreaTitleBarHeightHint="{Binding TitleBarHeight}"
+ CanResize="{Binding CanResize}"
+ CanMinimize="{Binding CanMinimize}"
+ CanMaximize="{Binding CanMaximize}"
x:Name="MainWindow"
Background="Transparent"
x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}"
diff --git a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml
index bcc1a71243..a647d34356 100644
--- a/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml
+++ b/samples/ControlCatalog/Pages/WindowCustomizationsPage.xaml
@@ -8,18 +8,55 @@
x:DataType="viewModels:MainWindowViewModel"
x:CompileBindings="True">
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
index 1050beedf2..716675f2c6 100644
--- a/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
@@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Controls.Notifications;
using Avalonia.Dialogs;
using Avalonia.Platform;
using System;
@@ -22,6 +21,9 @@ namespace ControlCatalog.ViewModels
private bool _isSystemBarVisible;
private bool _displayEdgeToEdge;
private Thickness _safeAreaPadding;
+ private bool _canResize;
+ private bool _canMinimize;
+ private bool _canMaximize;
public MainWindowViewModel()
{
@@ -49,7 +51,7 @@ namespace ControlCatalog.ViewModels
WindowState.FullScreen,
};
- this.PropertyChanged += (s, e) =>
+ PropertyChanged += (s, e) =>
{
if (e.PropertyName is nameof(SystemTitleBarEnabled) or nameof(PreferSystemChromeEnabled))
{
@@ -67,70 +69,104 @@ namespace ControlCatalog.ViewModels
}
};
- SystemTitleBarEnabled = true;
+ SystemTitleBarEnabled = true;
TitleBarHeight = -1;
+ CanResize = true;
+ CanMinimize = true;
+ CanMaximize = true;
}
public ExtendClientAreaChromeHints ChromeHints
{
get { return _chromeHints; }
- set { this.RaiseAndSetIfChanged(ref _chromeHints, value); }
+ set { RaiseAndSetIfChanged(ref _chromeHints, value); }
}
public bool ExtendClientAreaEnabled
{
get { return _extendClientAreaEnabled; }
- set { this.RaiseAndSetIfChanged(ref _extendClientAreaEnabled, value); }
+ set
+ {
+ if (RaiseAndSetIfChanged(ref _extendClientAreaEnabled, value) && !value)
+ {
+ SystemTitleBarEnabled = true;
+ }
+ }
}
public bool SystemTitleBarEnabled
{
get { return _systemTitleBarEnabled; }
- set { this.RaiseAndSetIfChanged(ref _systemTitleBarEnabled, value); }
+ set
+ {
+ if (RaiseAndSetIfChanged(ref _systemTitleBarEnabled, value) && !value)
+ {
+ TitleBarHeight = -1;
+ }
+ }
}
public bool PreferSystemChromeEnabled
{
get { return _preferSystemChromeEnabled; }
- set { this.RaiseAndSetIfChanged(ref _preferSystemChromeEnabled, value); }
+ set { RaiseAndSetIfChanged(ref _preferSystemChromeEnabled, value); }
}
public double TitleBarHeight
{
get { return _titleBarHeight; }
- set { this.RaiseAndSetIfChanged(ref _titleBarHeight, value); }
+ set { RaiseAndSetIfChanged(ref _titleBarHeight, value); }
}
public WindowState WindowState
{
get { return _windowState; }
- set { this.RaiseAndSetIfChanged(ref _windowState, value); }
+ set { RaiseAndSetIfChanged(ref _windowState, value); }
}
public WindowState[] WindowStates
{
get { return _windowStates; }
- set { this.RaiseAndSetIfChanged(ref _windowStates, value); }
+ set { RaiseAndSetIfChanged(ref _windowStates, value); }
}
public bool IsSystemBarVisible
{
get { return _isSystemBarVisible; }
- set { this.RaiseAndSetIfChanged(ref _isSystemBarVisible, value); }
+ set { RaiseAndSetIfChanged(ref _isSystemBarVisible, value); }
}
public bool DisplayEdgeToEdge
{
get { return _displayEdgeToEdge; }
- set { this.RaiseAndSetIfChanged(ref _displayEdgeToEdge, value); }
+ set { RaiseAndSetIfChanged(ref _displayEdgeToEdge, value); }
}
public Thickness SafeAreaPadding
{
get { return _safeAreaPadding; }
- set { this.RaiseAndSetIfChanged(ref _safeAreaPadding, value); }
+ set { RaiseAndSetIfChanged(ref _safeAreaPadding, value); }
+ }
+
+ public bool CanResize
+ {
+ get { return _canResize; }
+ set { RaiseAndSetIfChanged(ref _canResize, value); }
+ }
+
+ public bool CanMinimize
+ {
+ get { return _canMinimize; }
+ set { RaiseAndSetIfChanged(ref _canMinimize, value); }
}
+ public bool CanMaximize
+ {
+ get { return _canMaximize; }
+ set { RaiseAndSetIfChanged(ref _canMaximize, value); }
+ }
+
+
public MiniCommand AboutCommand { get; }
public MiniCommand ExitCommand { get; }
@@ -144,7 +180,7 @@ namespace ControlCatalog.ViewModels
public DateTime? ValidatedDateExample
{
get => _validatedDateExample;
- set => this.RaiseAndSetIfChanged(ref _validatedDateExample, value);
+ set => RaiseAndSetIfChanged(ref _validatedDateExample, value);
}
}
}
diff --git a/samples/IntegrationTestApp/Pages/WindowPage.axaml b/samples/IntegrationTestApp/Pages/WindowPage.axaml
index db2298b06e..60900a4778 100644
--- a/samples/IntegrationTestApp/Pages/WindowPage.axaml
+++ b/samples/IntegrationTestApp/Pages/WindowPage.axaml
@@ -30,14 +30,16 @@
ExtendClientAreaToDecorationsHint
Can Resize
+ Can Minimize
+ Can Maximize
+
+
-
-
diff --git a/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs b/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs
index 5549e537d3..b7f505a7b2 100644
--- a/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs
+++ b/samples/IntegrationTestApp/Pages/WindowPage.axaml.cs
@@ -23,10 +23,13 @@ public partial class WindowPage : UserControl
private void ShowWindow_Click(object? sender, RoutedEventArgs e)
{
var size = !string.IsNullOrWhiteSpace(ShowWindowSize.Text) ? Size.Parse(ShowWindowSize.Text) : (Size?)null;
+ var canResize = ShowWindowCanResize.IsChecked ?? false;
var window = new ShowWindowTest
{
WindowStartupLocation = (WindowStartupLocation)ShowWindowLocation.SelectedIndex,
- CanResize = ShowWindowCanResize.IsChecked ?? false,
+ CanResize = canResize,
+ CanMinimize = ShowWindowCanMinimize.IsChecked ?? false,
+ CanMaximize = canResize && (ShowWindowCanMaximize.IsChecked ?? false)
};
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
diff --git a/src/Avalonia.Controls/Chrome/CaptionButtons.cs b/src/Avalonia.Controls/Chrome/CaptionButtons.cs
index 07ecbb188e..32bdd8fa96 100644
--- a/src/Avalonia.Controls/Chrome/CaptionButtons.cs
+++ b/src/Avalonia.Controls/Chrome/CaptionButtons.cs
@@ -21,6 +21,8 @@ namespace Avalonia.Controls.Chrome
internal const string PART_FullScreenButton = "PART_FullScreenButton";
private Button? _restoreButton;
+ private Button? _minimizeButton;
+ private Button? _fullScreenButton;
private IDisposable? _disposables;
///
@@ -36,11 +38,16 @@ namespace Avalonia.Controls.Chrome
_disposables = new CompositeDisposable
{
- HostWindow.GetObservable(Window.CanResizeProperty)
- .Subscribe(x =>
+ HostWindow.GetObservable(Window.CanMaximizeProperty)
+ .Subscribe(_ =>
+ {
+ UpdateRestoreButtonState();
+ UpdateFullScreenButtonState();
+ }),
+ HostWindow.GetObservable(Window.CanMinimizeProperty)
+ .Subscribe(_ =>
{
- if (_restoreButton is not null)
- _restoreButton.IsEnabled = x;
+ UpdateMinimizeButtonState();
}),
HostWindow.GetObservable(Window.WindowStateProperty)
.Subscribe(x =>
@@ -49,6 +56,9 @@ namespace Avalonia.Controls.Chrome
PseudoClasses.Set(":normal", x == WindowState.Normal);
PseudoClasses.Set(":maximized", x == WindowState.Maximized);
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen);
+ UpdateRestoreButtonState();
+ UpdateMinimizeButtonState();
+ UpdateFullScreenButtonState();
}),
};
}
@@ -116,8 +126,8 @@ namespace Avalonia.Controls.Chrome
OnRestore();
args.Handled = true;
};
- restoreButton.IsEnabled = HostWindow?.CanResize ?? true;
_restoreButton = restoreButton;
+ UpdateRestoreButtonState();
}
if (e.NameScope.Find
void CanResize(bool value);
+ ///
+ /// Enables or disables minimizing the window.
+ ///
+ void SetCanMinimize(bool value);
+
+ ///
+ /// Enables or disables maximizing the window.
+ ///
+ void SetCanMaximize(bool value);
+
///
/// Gets or sets a method called before the underlying implementation is destroyed.
/// Return true to prevent the underlying implementation from closing.
@@ -124,7 +134,6 @@ namespace Avalonia.Platform
///
/// Minimum width of the window.
///
- ///
void SetMinMaxSize(Size minSize, Size maxSize);
///
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 6fb203b035..1f5d12c536 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -181,9 +181,24 @@ namespace Avalonia.Controls
public static readonly StyledProperty WindowStartupLocationProperty =
AvaloniaProperty.Register(nameof(WindowStartupLocation));
+ ///
+ /// Defines the property.
+ ///
public static readonly StyledProperty CanResizeProperty =
AvaloniaProperty.Register(nameof(CanResize), true);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty CanMinimizeProperty =
+ AvaloniaProperty.Register(nameof(CanMinimize), true);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty CanMaximizeProperty =
+ AvaloniaProperty.Register(nameof(CanMaximize), true, coerce: CoerceCanMaximize);
+
///
/// Routed event that can be used for global tracking of window destruction
///
@@ -236,6 +251,8 @@ namespace Avalonia.Controls
CreatePlatformImplBinding(TitleProperty, title => PlatformImpl!.SetTitle(title));
CreatePlatformImplBinding(IconProperty, icon => PlatformImpl!.SetIcon((icon ?? s_defaultIcon.Value)?.PlatformImpl));
CreatePlatformImplBinding(CanResizeProperty, canResize => PlatformImpl!.CanResize(canResize));
+ CreatePlatformImplBinding(CanMinimizeProperty, canMinimize => PlatformImpl!.SetCanMinimize(canMinimize));
+ CreatePlatformImplBinding(CanMaximizeProperty, canMaximize => PlatformImpl!.SetCanMaximize(canMaximize));
CreatePlatformImplBinding(ShowInTaskbarProperty, show => PlatformImpl!.ShowTaskbarIcon(show));
CreatePlatformImplBinding(WindowStateProperty, state => PlatformImpl!.WindowState = state);
@@ -407,6 +424,32 @@ namespace Avalonia.Controls
set => SetValue(CanResizeProperty, value);
}
+ ///
+ /// Enables or disables minimizing the window.
+ ///
+ ///
+ /// This property might be ignored by some window managers on Linux.
+ ///
+ public bool CanMinimize
+ {
+ get => GetValue(CanMinimizeProperty);
+ set => SetValue(CanMinimizeProperty, value);
+ }
+
+ ///
+ /// Enables or disables maximizing the window.
+ ///
+ ///
+ /// When is false, this property is always false.
+ /// On macOS, setting this property to false also disables the full screen mode.
+ /// This property might be ignored by some window managers on Linux.
+ ///
+ public bool CanMaximize
+ {
+ get => GetValue(CanMaximizeProperty);
+ set => SetValue(CanMaximizeProperty, value);
+ }
+
///
/// Gets or sets the icon of the window.
///
@@ -1184,7 +1227,7 @@ namespace Avalonia.Controls
PlatformImpl?.SetSystemDecorations(typedNewValue);
}
- if (change.Property == OwnerProperty)
+ else if (change.Property == OwnerProperty)
{
var oldParent = change.OldValue as Window;
var newParent = change.NewValue as Window;
@@ -1197,6 +1240,11 @@ namespace Avalonia.Controls
impl.SetParent(_showingAsDialog ? newParent?.PlatformImpl! : (newParent?.PlatformImpl ?? null));
}
}
+
+ else if (change.Property == CanResizeProperty)
+ {
+ CoerceValue(CanMaximizeProperty);
+ }
}
protected override AutomationPeer OnCreateAutomationPeer()
@@ -1217,5 +1265,8 @@ namespace Avalonia.Controls
}
return null;
}
+
+ private static bool CoerceCanMaximize(AvaloniaObject target, bool value)
+ => value && target is not Window { CanResize: false };
}
}
diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
index 84c1d7db19..61924f53ab 100644
--- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
+++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
@@ -133,6 +133,14 @@ namespace Avalonia.DesignerSupport.Remote
{
}
+ public void SetCanMinimize(bool value)
+ {
+ }
+
+ public void SetCanMaximize(bool value)
+ {
+ }
+
public void SetTopmost(bool value)
{
}
diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
index a0e5f3c87e..e83c29c9af 100644
--- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs
+++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
@@ -152,6 +152,14 @@ namespace Avalonia.DesignerSupport.Remote
{
}
+ public void SetCanMinimize(bool value)
+ {
+ }
+
+ public void SetCanMaximize(bool value)
+ {
+ }
+
public void SetTopmost(bool value)
{
}
diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs
index a278bda67e..08aaae669f 100644
--- a/src/Avalonia.Native/WindowImpl.cs
+++ b/src/Avalonia.Native/WindowImpl.cs
@@ -18,6 +18,7 @@ namespace Avalonia.Native
private DoubleClickHelper _doubleClickHelper;
private readonly ITopLevelNativeMenuExporter _nativeMenuExporter;
private bool _canResize = true;
+ private bool _canMaximize = true;
internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts) : base(factory)
{
@@ -77,6 +78,17 @@ namespace Avalonia.Native
_native.SetCanResize(value.AsComBool());
}
+ public void SetCanMinimize(bool value)
+ {
+ _native.SetCanMinimize(value.AsComBool());
+ }
+
+ public void SetCanMaximize(bool value)
+ {
+ _canMaximize = value;
+ _native.SetCanMaximize(value.AsComBool());
+ }
+
public void SetSystemDecorations(Controls.SystemDecorations enabled)
{
_native.SetDecorations((Interop.SystemDecorations)enabled);
@@ -138,10 +150,17 @@ namespace Avalonia.Native
{
if (_doubleClickHelper.IsDoubleClick(e.Timestamp, e.Position))
{
- if (_canResize)
+ switch (WindowState)
{
- WindowState = WindowState is WindowState.Maximized or WindowState.FullScreen ?
- WindowState.Normal : WindowState.Maximized;
+ case WindowState.Maximized or WindowState.FullScreen
+ when _canResize:
+ WindowState = WindowState.Normal;
+ break;
+
+ case WindowState.Normal
+ when _canMaximize:
+ WindowState = WindowState.Maximized;
+ break;
}
}
else
diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl
index bc2d6ddd1a..97afb8667e 100644
--- a/src/Avalonia.Native/avn.idl
+++ b/src/Avalonia.Native/avn.idl
@@ -772,6 +772,8 @@ interface IAvnWindow : IAvnWindowBase
{
HRESULT SetEnabled(bool enable);
HRESULT SetCanResize(bool value);
+ HRESULT SetCanMinimize(bool value);
+ HRESULT SetCanMaximize(bool value);
HRESULT SetDecorations(SystemDecorations value);
HRESULT SetTitle(char* utf8Title);
HRESULT SetTitleBarColor(AvnColor color);
diff --git a/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml b/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
index bcaeac8012..d9f9343925 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
@@ -112,7 +112,7 @@
-
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index 0fecf6a47d..eee61a707f 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -316,22 +316,28 @@ namespace Avalonia.X11
|| _systemDecorations == SystemDecorations.None)
decorations = 0;
- if (!_canResize || !IsEnabled)
+ var isDisabled = !IsEnabled;
+
+ if (!_canResize || isDisabled)
{
- functions &= ~(MotifFunctions.Resize | MotifFunctions.Maximize);
- decorations &= ~(MotifDecorations.Maximize | MotifDecorations.ResizeH);
+ functions &= ~MotifFunctions.Resize;
+ decorations &= ~MotifDecorations.ResizeH;
}
- if (!IsEnabled)
- {
- functions &= ~(MotifFunctions.Resize | MotifFunctions.Minimize);
- UpdateSizeHints(null, true);
+ if (!_canMinimize || isDisabled)
+ {
+ functions &= ~MotifFunctions.Minimize;
+ decorations &= ~MotifDecorations.Minimize;
}
- else
+
+ if (!_canMaximize || isDisabled)
{
- UpdateSizeHints(null);
+ functions &= ~MotifFunctions.Maximize;
+ decorations &= ~MotifDecorations.Maximize;
}
+ UpdateSizeHints(null, isDisabled);
+
var hints = new MotifWmHints
{
flags = new IntPtr((int)(MotifFlags.Decorations | MotifFlags.Functions)),
@@ -857,6 +863,8 @@ namespace Avalonia.X11
private SystemDecorations _systemDecorations = SystemDecorations.Full;
private bool _canResize = true;
+ private bool _canMinimize = true;
+ private bool _canMaximize = true;
private const int MaxWindowDimension = 100000;
private (Size minSize, Size maxSize) _scaledMinMaxSize =
@@ -1162,6 +1170,18 @@ namespace Avalonia.X11
UpdateSizeHints(null);
}
+ public void SetCanMinimize(bool value)
+ {
+ _canMinimize = value;
+ UpdateMotifHints();
+ }
+
+ public void SetCanMaximize(bool value)
+ {
+ _canMaximize = value;
+ UpdateMotifHints();
+ }
+
public void SetCursor(ICursorImpl? cursor)
{
if (cursor == null)
diff --git a/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs b/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
index 64ce9945d4..2cd3df7c54 100644
--- a/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
+++ b/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
@@ -165,6 +165,14 @@ namespace Avalonia.Headless
}
+ public void SetCanMinimize(bool value)
+ {
+ }
+
+ public void SetCanMaximize(bool value)
+ {
+ }
+
public Func? Closing { get; set; }
private class FramebufferProxy : ILockedFramebuffer
diff --git a/src/Windows/Avalonia.Win32/EmbeddedWindowImpl.cs b/src/Windows/Avalonia.Win32/EmbeddedWindowImpl.cs
index 509be65784..a039d568c6 100644
--- a/src/Windows/Avalonia.Win32/EmbeddedWindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/EmbeddedWindowImpl.cs
@@ -12,6 +12,8 @@ namespace Avalonia.Win32
{
ShowInTaskbar = false,
IsResizable = false,
+ IsMinimizable = false,
+ IsMaximizable = false,
Decorations = SystemDecorations.None
};
}
diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs
index 95c8178adc..8a8450443f 100644
--- a/src/Windows/Avalonia.Win32/PopupImpl.cs
+++ b/src/Windows/Avalonia.Win32/PopupImpl.cs
@@ -111,6 +111,8 @@ namespace Avalonia.Win32
{
ShowInTaskbar = false,
IsResizable = false,
+ IsMinimizable = false,
+ IsMaximizable = false,
Decorations = SystemDecorations.None,
};
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 784ad7c2aa..54e464720b 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -136,6 +136,8 @@ namespace Avalonia.Win32
{
ShowInTaskbar = false,
IsResizable = true,
+ IsMinimizable = true,
+ IsMaximizable = true,
Decorations = SystemDecorations.Full
};
@@ -858,6 +860,24 @@ namespace Avalonia.Win32
UpdateWindowProperties(newWindowProperties);
}
+ public void SetCanMinimize(bool value)
+ {
+ var newWindowProperties = _windowProperties;
+
+ newWindowProperties.IsMinimizable = value;
+
+ UpdateWindowProperties(newWindowProperties);
+ }
+
+ public void SetCanMaximize(bool value)
+ {
+ var newWindowProperties = _windowProperties;
+
+ newWindowProperties.IsMaximizable = value;
+
+ UpdateWindowProperties(newWindowProperties);
+ }
+
public void SetSystemDecorations(SystemDecorations value)
{
var newWindowProperties = _windowProperties;
@@ -1425,15 +1445,19 @@ namespace Avalonia.Win32
style |= WindowStyles.WS_VISIBLE;
if (newProperties.IsResizable || newProperties.WindowState == WindowState.Maximized)
- {
style |= WindowStyles.WS_THICKFRAME;
- style |= WindowStyles.WS_MAXIMIZEBOX;
- }
else
- {
style &= ~WindowStyles.WS_THICKFRAME;
+
+ if (newProperties.IsMinimizable)
+ style |= WindowStyles.WS_MINIMIZEBOX;
+ else
+ style &= ~WindowStyles.WS_MINIMIZEBOX;
+
+ if (newProperties.IsMaximizable || (newProperties.WindowState == WindowState.Maximized && newProperties.IsResizable))
+ style |= WindowStyles.WS_MAXIMIZEBOX;
+ else
style &= ~WindowStyles.WS_MAXIMIZEBOX;
- }
const WindowStyles fullDecorationFlags = WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU | WindowStyles.WS_BORDER;
@@ -1656,6 +1680,8 @@ namespace Avalonia.Win32
{
public bool ShowInTaskbar;
public bool IsResizable;
+ public bool IsMinimizable;
+ public bool IsMaximizable;
public SystemDecorations Decorations;
public bool IsFullScreen;
public WindowState WindowState;
diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
index a7f2692a57..e769f350af 100644
--- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
@@ -672,6 +672,23 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void CanMaximize_Should_Be_False_If_CanResize_Is_False()
+ {
+ var windowImpl = MockWindowingPlatform.CreateWindowMock();
+
+ using var app = UnitTestApplication.Start(TestServices.StyledWindow.With(
+ windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)));
+
+ var window = new Window();
+
+ Assert.True(window.CanMaximize);
+
+ window.CanResize = false;
+
+ Assert.False(window.CanMaximize);
+ }
+
public class SizingTests : ScopedTestBase
{
[Fact]
diff --git a/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs b/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs
index d4a6380b5d..b6cbf38adf 100644
--- a/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs
+++ b/tests/Avalonia.IntegrationTests.Appium/WindowTests.cs
@@ -311,6 +311,37 @@ namespace Avalonia.IntegrationTests.Appium
}
}
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Window_Minimize_Button_Enabled_Matches_CanMinimize(bool canMinimize)
+ {
+ using (OpenWindow(canMinimize: canMinimize))
+ {
+ var secondaryWindow = Session.GetWindowById("SecondaryWindow");
+ var windowChrome = secondaryWindow.GetSystemChromeButtons();
+
+ Assert.NotNull(windowChrome.Minimize);
+ Assert.Equal(canMinimize, windowChrome.Minimize!.Enabled);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Window_Maximize_Button_Enabled_Matches_CanMaximize(bool canMaximize)
+ {
+ using (OpenWindow(canMaximize: canMaximize))
+ {
+ var secondaryWindow = Session.GetWindowById("SecondaryWindow");
+ var windowChrome = secondaryWindow.GetSystemChromeButtons();
+
+ var maximizeButton = windowChrome.FullScreen ?? windowChrome.Maximize;
+ Assert.NotNull(maximizeButton);
+ Assert.Equal(canMaximize, maximizeButton.Enabled);
+ }
+ }
+
[Fact]
public void Changing_SystemDecorations_Should_Not_Change_Frame_Size_And_Position()
{
@@ -452,13 +483,17 @@ namespace Avalonia.IntegrationTests.Appium
WindowStartupLocation location = WindowStartupLocation.Manual,
WindowState state = Controls.WindowState.Normal,
bool canResize = true,
- bool extendClientArea = false)
+ bool extendClientArea = false,
+ bool canMinimize = true,
+ bool canMaximize = true)
{
var sizeTextBox = Session.FindElementByAccessibilityId("ShowWindowSize");
var modeComboBox = Session.FindElementByAccessibilityId("ShowWindowMode");
var locationComboBox = Session.FindElementByAccessibilityId("ShowWindowLocation");
var stateComboBox = Session.FindElementByAccessibilityId("ShowWindowState");
var canResizeCheckBox = Session.FindElementByAccessibilityId("ShowWindowCanResize");
+ var canMinimizeCheckBox = Session.FindElementByAccessibilityId("ShowWindowCanMinimize");
+ var canMaximizeCheckBox = Session.FindElementByAccessibilityId("ShowWindowCanMaximize");
var showButton = Session.FindElementByAccessibilityId("ShowWindow");
var extendClientAreaCheckBox = Session.FindElementByAccessibilityId("ShowWindowExtendClientAreaToDecorationsHint");
@@ -486,6 +521,12 @@ namespace Avalonia.IntegrationTests.Appium
if (canResizeCheckBox.GetIsChecked() != canResize)
canResizeCheckBox.Click();
+ if (canMinimizeCheckBox.GetIsChecked() != canMinimize)
+ canMinimizeCheckBox.Click();
+
+ if (canMaximizeCheckBox.GetIsChecked() != canMaximize)
+ canMaximizeCheckBox.Click();
+
if (extendClientAreaCheckBox.GetIsChecked() != extendClientArea)
extendClientAreaCheckBox.Click();