diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index d92a46a70a..db3ec6a077 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -248,7 +248,7 @@ namespace Avalonia.Controls this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x, WindowResizeReason.Application)); CreatePlatformImplBinding(TitleProperty, title => PlatformImpl!.SetTitle(title)); - CreatePlatformImplBinding(IconProperty, icon => PlatformImpl!.SetIcon((icon ?? s_defaultIcon.Value)?.PlatformImpl)); + CreatePlatformImplBinding(IconProperty, SetEffectiveIcon); CreatePlatformImplBinding(CanResizeProperty, canResize => PlatformImpl!.CanResize(canResize)); CreatePlatformImplBinding(CanMinimizeProperty, canMinimize => PlatformImpl!.SetCanMinimize(canMinimize)); CreatePlatformImplBinding(CanMaximizeProperty, canMaximize => PlatformImpl!.SetCanMaximize(canMaximize)); @@ -892,6 +892,8 @@ namespace Avalonia.Controls _shown = true; IsVisible = true; + SetEffectiveIcon(Icon); + // If window position was not set before then platform may provide incorrect scaling at this time, // but we need it for proper calculation of position and in some cases size (size to content) SetExpectedScaling(owner); @@ -1378,7 +1380,7 @@ namespace Avalonia.Controls private static WindowIcon? LoadDefaultIcon() { - // Use AvaloniaLocator instead of static AssetLoader, so it won't fail on Unit Tests without any asset loader. + // Use AvaloniaLocator instead of static AssetLoader, so it won't fail on Unit Tests without any asset loader. if (AvaloniaLocator.Current.GetService() is { } assetLoader && Assembly.GetEntryAssembly()?.GetName()?.Name is { } assemblyName && Uri.TryCreate($"avares://{assemblyName}/!__AvaloniaDefaultWindowIcon", UriKind.Absolute, out var path) @@ -1390,6 +1392,12 @@ namespace Avalonia.Controls return null; } + private void SetEffectiveIcon(WindowIcon? icon) + { + icon ??= _shown ? s_defaultIcon.Value : null; + PlatformImpl?.SetIcon(icon?.PlatformImpl); + } + private static bool CoerceCanMaximize(AvaloniaObject target, bool value) => value && target is not Window { CanResize: false }; } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index a57e1986ac..14e0f0dea8 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -71,6 +71,7 @@ namespace Avalonia.X11 private bool _useCompositorDrivenRenderWindowResize = false; private bool _usePositioningFlags = false; private X11WindowMode _mode; + private IWindowIconImpl? _iconImpl; private enum XSyncState { @@ -1530,6 +1531,11 @@ namespace Avalonia.X11 public void SetIcon(IWindowIconImpl? icon) { + if (ReferenceEquals(_iconImpl, icon)) + return; + + _iconImpl = icon; + if (icon != null) { var data = ((X11IconData)icon).Data; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index cc2e7211f1..db42fca251 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -809,6 +809,9 @@ namespace Avalonia.Win32 public void SetIcon(IWindowIconImpl? icon) { + if (ReferenceEquals(_iconImpl, icon)) + return; + _iconImpl = (IconImpl?)icon; ClearIconCache(); RefreshIcon(); diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 7ab69c8d86..59a84462ef 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -1188,6 +1188,26 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Show_Should_Apply_Default_Icon_When_No_Custom_Icon_Is_Set() + { + var windowImpl = MockWindowingPlatform.CreateWindowMock(); + var windowingPlatform = new MockWindowingPlatform(() => windowImpl.Object); + + using (UnitTestApplication.Start(TestServices.StyledWindow.With(windowingPlatform: windowingPlatform))) + { + var target = new Window(); + + // Clear any SetIcon calls from construction. + windowImpl.Invocations.Clear(); + + target.Show(); + + // ShowCore should apply the default icon when no custom icon was set. + windowImpl.Verify(x => x.SetIcon(It.IsAny()), Times.AtLeastOnce()); + } + } + private class TopmostWindow : Window { static TopmostWindow()