Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix default values of window properties not being sent to IWindowImpl #12656

Merged
merged 2 commits into from
Sep 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions src/Avalonia.Controls/TopLevel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ private static readonly WeakEvent<IResourceHost, ResourcesChangedEventArgs>
private readonly PointerOverPreProcessor? _pointerOverPreProcessor;
private readonly IDisposable? _pointerOverPreProcessorSubscription;
private readonly IDisposable? _backGestureSubscription;
private readonly Dictionary<AvaloniaProperty, Action> _platformImplBindings = new();
private Size _clientSize;
private Size? _frameSize;
private WindowTransparencyLevel _actualTransparencyLevel;
Expand Down Expand Up @@ -198,6 +199,13 @@ public TopLevel(ITopLevelImpl impl, IAvaloniaDependencyResolver? dependencyResol
impl.ScalingChanged = HandleScalingChanged;
impl.TransparencyLevelChanged = HandleTransparencyLevelChanged;

CreatePlatformImplBinding(TransparencyLevelHintProperty, hint => PlatformImpl.SetTransparencyLevelHint(hint ?? Array.Empty<WindowTransparencyLevel>()));
CreatePlatformImplBinding(ActualThemeVariantProperty, variant =>
{
variant ??= ThemeVariant.Default;
PlatformImpl.SetFrameThemeVariant((PlatformThemeVariant?)variant ?? PlatformThemeVariant.Light);
});

_keyboardNavigationHandler?.SetOwner(this);
_accessKeyHandler?.SetOwner(this);

Expand Down Expand Up @@ -394,6 +402,22 @@ internal ILayoutManager LayoutManager
/// </returns>
public IPlatformHandle? TryGetPlatformHandle() => (PlatformImpl as IWindowBaseImpl)?.Handle;

private protected void CreatePlatformImplBinding<TValue>(StyledProperty<TValue> property, Action<TValue> onValue)
{
_platformImplBindings.TryGetValue(property, out var actions);
_platformImplBindings[property] = actions + UpdatePlatformImpl;

UpdatePlatformImpl(); // execute the action now to handle the default value, which may have been overridden

void UpdatePlatformImpl()
{
if (PlatformImpl is not null)
{
onValue(GetValue(property));
}
}
}

/// <summary>
/// Gets the renderer for the window.
/// </summary>
Expand Down Expand Up @@ -550,18 +574,9 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
{
base.OnPropertyChanged(change);

if (change.Property == TransparencyLevelHintProperty)
{
if (PlatformImpl != null)
{
PlatformImpl.SetTransparencyLevelHint(
change.GetNewValue<IReadOnlyList<WindowTransparencyLevel>>() ?? Array.Empty<WindowTransparencyLevel>());
}
}
else if (change.Property == ActualThemeVariantProperty)
if (_platformImplBindings.TryGetValue(change.Property, out var bindingAction))
{
var newThemeVariant = change.GetNewValue<ThemeVariant?>() ?? ThemeVariant.Default;
PlatformImpl?.SetFrameThemeVariant((PlatformThemeVariant?)newThemeVariant ?? PlatformThemeVariant.Light);
bindingAction();
}
}

Expand Down
45 changes: 15 additions & 30 deletions src/Avalonia.Controls/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,35 +177,6 @@ public class Window : WindowBase, IFocusScope, ILayoutRoot
static Window()
{
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
TitleProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetTitle((string?)e.NewValue));
ShowInTaskbarProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue!));

IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon?)e.NewValue)?.PlatformImpl));

CanResizeProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue!));

WindowStateProperty.Changed.AddClassHandler<Window>(
(w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue!; });

ExtendClientAreaToDecorationsHintProperty.Changed.AddClassHandler<Window>(
(w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaToDecorationsHint((bool)e.NewValue!); });

ExtendClientAreaChromeHintsProperty.Changed.AddClassHandler<Window>(
(w, e) =>
{
if (w.PlatformImpl != null)
{
w.PlatformImpl.SetExtendClientAreaChromeHints((ExtendClientAreaChromeHints)e.NewValue!);
}
});

ExtendClientAreaTitleBarHeightHintProperty.Changed.AddClassHandler<Window>(
(w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.SetExtendClientAreaTitleBarHeightHint((double)e.NewValue!); });

MinWidthProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size((double)e.NewValue!, w.MinHeight), new Size(w.MaxWidth, w.MaxHeight)));
MinHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, (double)e.NewValue!), new Size(w.MaxWidth, w.MaxHeight)));
MaxWidthProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size((double)e.NewValue!, w.MaxHeight)));
MaxHeightProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.SetMinMaxSize(new Size(w.MinWidth, w.MinHeight), new Size(w.MaxWidth, (double)e.NewValue!)));
}

/// <summary>
Expand All @@ -230,7 +201,21 @@ public Window(IWindowImpl impl)
impl.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged;
this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x, WindowResizeReason.Application));

PlatformImpl?.ShowTaskbarIcon(ShowInTaskbar);
CreatePlatformImplBinding(TitleProperty, title => PlatformImpl!.SetTitle(title));
CreatePlatformImplBinding(IconProperty, icon => PlatformImpl!.SetIcon(icon?.PlatformImpl));
CreatePlatformImplBinding(CanResizeProperty, canResize => PlatformImpl!.CanResize(canResize));
CreatePlatformImplBinding(ShowInTaskbarProperty, show => PlatformImpl!.ShowTaskbarIcon(show));

CreatePlatformImplBinding(WindowStateProperty, state => PlatformImpl!.WindowState = state);
CreatePlatformImplBinding(ExtendClientAreaToDecorationsHintProperty, hint => PlatformImpl!.SetExtendClientAreaToDecorationsHint(hint));
CreatePlatformImplBinding(ExtendClientAreaChromeHintsProperty, hint => PlatformImpl!.SetExtendClientAreaChromeHints(hint));

CreatePlatformImplBinding(MinWidthProperty, UpdateMinMaxSize);
CreatePlatformImplBinding(MaxWidthProperty, UpdateMinMaxSize);
CreatePlatformImplBinding(MinHeightProperty, UpdateMinMaxSize);
CreatePlatformImplBinding(MaxHeightProperty, UpdateMinMaxSize);

void UpdateMinMaxSize(double _) => PlatformImpl!.SetMinMaxSize(new Size(MinWidth, MinHeight), new Size(MaxWidth, MaxHeight));
}

/// <summary>
Expand Down
19 changes: 13 additions & 6 deletions src/Avalonia.Controls/WindowBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,17 @@ public class WindowBase : TopLevel
private bool _isActive;
private int _ignoreVisibilityChanges;
private WindowBase? _owner;

protected bool IgnoreVisibilityChanges => _ignoreVisibilityChanges > 0;
protected bool IgnoreVisibilityChanges => _ignoreVisibilityChanges > 0;

static WindowBase()
{
IsVisibleProperty.OverrideDefaultValue<WindowBase>(false);
IsVisibleProperty.Changed.AddClassHandler<WindowBase>((x,e) => x.IsVisibleChanged(e));


TopmostProperty.Changed.AddClassHandler<WindowBase>((w, e) => w.PlatformImpl?.SetTopmost((bool)e.NewValue!));
}

public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current)
{
CreatePlatformImplBinding(TopmostProperty, topmost => PlatformImpl!.SetTopmost(topmost));
}

public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver? dependencyResolver) : base(impl, dependencyResolver)
Expand Down Expand Up @@ -192,6 +189,16 @@ protected void EnsureInitialized()
}
}

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);

if (change.Property == IsVisibleProperty)
{
IsVisibleChanged(change);
}
}

/// <inheritdoc/>
protected override void OnClosed(EventArgs e)
{
Expand Down
25 changes: 25 additions & 0 deletions tests/Avalonia.Controls.UnitTests/WindowTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,23 @@ public void Window_Should_Be_Centered_Relative_To_Owner_When_WindowStartupLocati
}
}

[Fact]
public void Window_Topmost_By_Default_Should_Configure_PlatformImpl_When_Constructed()
{
var windowImpl = MockWindowingPlatform.CreateWindowMock();

var windowServices = TestServices.StyledWindow.With(
windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object));

using (UnitTestApplication.Start(windowServices))
{
var window = new TopmostWindow();

Assert.True(window.Topmost);
windowImpl.Verify(i => i.SetTopmost(true));
}
}

public class SizingTests
{
[Fact]
Expand Down Expand Up @@ -1099,5 +1116,13 @@ protected override Size MeasureOverride(Size availableSize)
return base.MeasureOverride(availableSize);
}
}

private class TopmostWindow : Window
{
static TopmostWindow()
{
TopmostProperty.OverrideDefaultValue<TopmostWindow>(true);
}
}
}
}