Browse Source

Removed TopLevelImpl validating layer.

The validating layer introduced in #7369 has done its job and caught a few bugs, but was causing difficulties in certain places so removing it now.

Fixes #7573
pull/7701/head
Steven Kirk 4 years ago
parent
commit
bdd576bfc0
  1. 2
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  2. 2
      src/Avalonia.Controls/TopLevel.cs
  3. 344
      src/Avalonia.Controls/ValidatingToplevel.cs
  4. 11
      src/Avalonia.Controls/Window.cs
  5. 9
      src/Avalonia.Controls/WindowBase.cs
  6. 2
      tests/Avalonia.Controls.UnitTests/WindowTests.cs
  7. 4
      tests/Avalonia.LeakTests/ControlTests.cs

2
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -44,7 +44,7 @@ namespace Avalonia.Controls.Primitives
/// The dependency resolver to use. If null the default dependency resolver will be used.
/// </param>
public PopupRoot(TopLevel parent, IPopupImpl impl, IAvaloniaDependencyResolver? dependencyResolver)
: base(ValidatingPopupImpl.Wrap(impl), dependencyResolver)
: base(impl, dependencyResolver)
{
_parent = parent;
}

2
src/Avalonia.Controls/TopLevel.cs

@ -134,8 +134,6 @@ namespace Avalonia.Controls
"Could not create window implementation: maybe no windowing subsystem was initialized?");
}
impl = ValidatingToplevelImpl.Wrap(impl);
PlatformImpl = impl;
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;

344
src/Avalonia.Controls/ValidatingToplevel.cs

@ -1,344 +0,0 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Input.TextInput;
using Avalonia.Platform;
using Avalonia.Rendering;
namespace Avalonia.Controls;
internal class ValidatingToplevelImpl : ITopLevelImpl, ITopLevelImplWithNativeControlHost,
ITopLevelImplWithNativeMenuExporter, ITopLevelImplWithTextInputMethod
{
private readonly ITopLevelImpl _impl;
private bool _disposed;
public ValidatingToplevelImpl(ITopLevelImpl impl)
{
_impl = impl ?? throw new InvalidOperationException(
"Could not create TopLevel implementation: maybe no windowing subsystem was initialized?");
}
public void Dispose()
{
_disposed = true;
_impl.Dispose();
}
protected void CheckDisposed()
{
if (_disposed)
throw new ObjectDisposedException(_impl.GetType().FullName);
}
protected ITopLevelImpl Inner
{
get
{
CheckDisposed();
return _impl;
}
}
public static ITopLevelImpl Wrap(ITopLevelImpl impl)
{
#if DEBUG
if (impl is ValidatingToplevelImpl)
return impl;
return new ValidatingToplevelImpl(impl);
#else
return impl;
#endif
}
public Size ClientSize => Inner.ClientSize;
public Size? FrameSize => Inner.FrameSize;
public double RenderScaling => Inner.RenderScaling;
public IEnumerable<object> Surfaces => Inner.Surfaces;
public Action<RawInputEventArgs>? Input
{
get => Inner.Input;
set => Inner.Input = value;
}
public Action<Rect>? Paint
{
get => Inner.Paint;
set => Inner.Paint = value;
}
public Action<Size, PlatformResizeReason>? Resized
{
get => Inner.Resized;
set => Inner.Resized = value;
}
public Action<double>? ScalingChanged
{
get => Inner.ScalingChanged;
set => Inner.ScalingChanged = value;
}
public Action<WindowTransparencyLevel>? TransparencyLevelChanged
{
get => Inner.TransparencyLevelChanged;
set => Inner.TransparencyLevelChanged = value;
}
public IRenderer CreateRenderer(IRenderRoot root) => Inner.CreateRenderer(root);
public void Invalidate(Rect rect) => Inner.Invalidate(rect);
public void SetInputRoot(IInputRoot inputRoot) => Inner.SetInputRoot(inputRoot);
public Point PointToClient(PixelPoint point) => Inner.PointToClient(point);
public PixelPoint PointToScreen(Point point) => Inner.PointToScreen(point);
public void SetCursor(ICursorImpl? cursor) => Inner.SetCursor(cursor);
public Action? Closed
{
get => Inner.Closed;
set => Inner.Closed = value;
}
public Action? LostFocus
{
get => Inner.LostFocus;
set => Inner.LostFocus = value;
}
// Exception: for some reason we are notifying platform mouse device from TopLevel.cs
public IMouseDevice MouseDevice => _impl.MouseDevice;
public IPopupImpl? CreatePopup() => Inner.CreatePopup();
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) =>
Inner.SetTransparencyLevelHint(transparencyLevel);
public WindowTransparencyLevel TransparencyLevel => Inner.TransparencyLevel;
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => Inner.AcrylicCompensationLevels;
public INativeControlHostImpl? NativeControlHost => (Inner as ITopLevelImplWithNativeControlHost)?.NativeControlHost;
public ITopLevelNativeMenuExporter? NativeMenuExporter =>
(Inner as ITopLevelImplWithNativeMenuExporter)?.NativeMenuExporter;
public ITextInputMethodImpl? TextInputMethod => (Inner as ITopLevelImplWithTextInputMethod)?.TextInputMethod;
}
internal class ValidatingWindowBaseImpl : ValidatingToplevelImpl, IWindowBaseImpl
{
private readonly IWindowBaseImpl _impl;
public ValidatingWindowBaseImpl(IWindowBaseImpl impl) : base(impl)
{
_impl = impl;
}
protected new IWindowBaseImpl Inner
{
get
{
CheckDisposed();
return _impl;
}
}
public static IWindowBaseImpl Wrap(IWindowBaseImpl impl)
{
#if DEBUG
if (impl is ValidatingToplevelImpl)
return impl;
return new ValidatingWindowBaseImpl(impl);
#else
return impl;
#endif
}
public void Show(bool activate, bool isDialog) => Inner.Show(activate, isDialog);
public void Hide() => Inner.Hide();
public double DesktopScaling => Inner.DesktopScaling;
public PixelPoint Position => Inner.Position;
public Action<PixelPoint>? PositionChanged
{
get => Inner.PositionChanged;
set => Inner.PositionChanged = value;
}
public void Activate() => Inner.Activate();
public Action? Deactivated
{
get => Inner.Deactivated;
set => Inner.Deactivated = value;
}
public Action? Activated
{
get => Inner.Activated;
set => Inner.Activated = value;
}
public IPlatformHandle Handle => Inner.Handle;
public Size MaxAutoSizeHint => Inner.MaxAutoSizeHint;
public void SetTopmost(bool value) => Inner.SetTopmost(value);
public IScreenImpl Screen => Inner.Screen;
}
internal class ValidatingWindowImpl : ValidatingWindowBaseImpl, IWindowImpl
{
private readonly IWindowImpl _impl;
public ValidatingWindowImpl(IWindowImpl impl) : base(impl)
{
_impl = impl;
}
protected new IWindowImpl Inner
{
get
{
CheckDisposed();
return _impl;
}
}
public static IWindowImpl Unwrap(IWindowImpl impl)
{
if (impl is ValidatingWindowImpl v)
return v.Inner;
return impl;
}
public static IWindowImpl Wrap(IWindowImpl impl)
{
#if DEBUG
if (impl is ValidatingToplevelImpl)
return impl;
return new ValidatingWindowImpl(impl);
#else
return impl;
#endif
}
public WindowState WindowState
{
get => Inner.WindowState;
set => Inner.WindowState = value;
}
public Action<WindowState> WindowStateChanged
{
get => Inner.WindowStateChanged;
set => Inner.WindowStateChanged = value;
}
public void SetTitle(string? title) => Inner.SetTitle(title);
public void SetParent(IWindowImpl parent)
{
//Workaround. SetParent will cast IWindowImpl to WindowImpl but ValidatingWindowImpl isn't actual WindowImpl so it will fail with InvalidCastException.
if (parent is ValidatingWindowImpl validatingToplevelImpl)
{
Inner.SetParent(validatingToplevelImpl.Inner);
}
else
{
Inner.SetParent(parent);
}
}
public void SetEnabled(bool enable) => Inner.SetEnabled(enable);
public Action GotInputWhenDisabled
{
get => Inner.GotInputWhenDisabled;
set => Inner.GotInputWhenDisabled = value;
}
public void SetSystemDecorations(SystemDecorations enabled) => Inner.SetSystemDecorations(enabled);
public void SetIcon(IWindowIconImpl? icon) => Inner.SetIcon(icon);
public void ShowTaskbarIcon(bool value) => Inner.ShowTaskbarIcon(value);
public void CanResize(bool value) => Inner.CanResize(value);
public Func<bool> Closing
{
get => Inner.Closing;
set => Inner.Closing = value;
}
public bool IsClientAreaExtendedToDecorations => Inner.IsClientAreaExtendedToDecorations;
public Action<bool> ExtendClientAreaToDecorationsChanged
{
get => Inner.ExtendClientAreaToDecorationsChanged;
set => Inner.ExtendClientAreaToDecorationsChanged = value;
}
public bool NeedsManagedDecorations => Inner.NeedsManagedDecorations;
public Thickness ExtendedMargins => Inner.ExtendedMargins;
public Thickness OffScreenMargin => Inner.OffScreenMargin;
public void BeginMoveDrag(PointerPressedEventArgs e) => Inner.BeginMoveDrag(e);
public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e) => Inner.BeginResizeDrag(edge, e);
public void Resize(Size clientSize, PlatformResizeReason reason) =>
Inner.Resize(clientSize, reason);
public void Move(PixelPoint point) => Inner.Move(point);
public void SetMinMaxSize(Size minSize, Size maxSize) => Inner.SetMinMaxSize(minSize, maxSize);
public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) =>
Inner.SetExtendClientAreaToDecorationsHint(extendIntoClientAreaHint);
public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) =>
Inner.SetExtendClientAreaChromeHints(hints);
public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) =>
Inner.SetExtendClientAreaTitleBarHeightHint(titleBarHeight);
}
internal class ValidatingPopupImpl : ValidatingWindowBaseImpl, IPopupImpl
{
private readonly IPopupImpl _impl;
public ValidatingPopupImpl(IPopupImpl impl) : base(impl)
{
_impl = impl;
}
protected new IPopupImpl Inner
{
get
{
CheckDisposed();
return _impl;
}
}
public static IPopupImpl Wrap(IPopupImpl impl)
{
#if DEBUG
if (impl is ValidatingToplevelImpl)
return impl;
return new ValidatingPopupImpl(impl);
#else
return impl;
#endif
}
public IPopupPositioner PopupPositioner => Inner.PopupPositioner;
public void SetWindowManagerAddShadowHint(bool enabled) => Inner.SetWindowManagerAddShadowHint(enabled);
}

11
src/Avalonia.Controls/Window.cs

@ -237,14 +237,13 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="impl">The window implementation.</param>
public Window(IWindowImpl impl)
: base(ValidatingWindowImpl.Wrap(impl))
: base(impl)
{
var wrapped = (IWindowImpl)base.PlatformImpl!;
wrapped.Closing = HandleClosing;
wrapped.GotInputWhenDisabled = OnGotInputWhenDisabled;
wrapped.WindowStateChanged = HandleWindowStateChanged;
impl.Closing = HandleClosing;
impl.GotInputWhenDisabled = OnGotInputWhenDisabled;
impl.WindowStateChanged = HandleWindowStateChanged;
_maxPlatformClientSize = PlatformImpl?.MaxAutoSizeHint ?? default(Size);
wrapped.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged;
impl.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged;
this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x, PlatformResizeReason.Application));
PlatformImpl?.ShowTaskbarIcon(ShowInTaskbar);

9
src/Avalonia.Controls/WindowBase.cs

@ -57,13 +57,12 @@ namespace Avalonia.Controls
{
}
public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver? dependencyResolver) : base(ValidatingWindowBaseImpl.Wrap(impl), dependencyResolver)
public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver? dependencyResolver) : base(impl, dependencyResolver)
{
Screens = new Screens(PlatformImpl?.Screen);
var wrapped = PlatformImpl!;
wrapped.Activated = HandleActivated;
wrapped.Deactivated = HandleDeactivated;
wrapped.PositionChanged = HandlePositionChanged;
impl.Activated = HandleActivated;
impl.Deactivated = HandleDeactivated;
impl.PositionChanged = HandlePositionChanged;
}
/// <summary>

2
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -821,7 +821,7 @@ namespace Avalonia.Controls.UnitTests
target.Width = 410;
target.LayoutManager.ExecuteLayoutPass();
var windowImpl = Mock.Get(ValidatingWindowImpl.Unwrap(target.PlatformImpl));
var windowImpl = Mock.Get(target.PlatformImpl);
windowImpl.Verify(x => x.Resize(new Size(410, 800), PlatformResizeReason.Application));
Assert.Equal(410, target.Width);
}

4
tests/Avalonia.LeakTests/ControlTests.cs

@ -496,7 +496,7 @@ namespace Avalonia.LeakTests
AttachShowAndDetachContextMenu(window);
Mock.Get(ValidatingWindowImpl.Unwrap(window.PlatformImpl)).Invocations.Clear();
Mock.Get(window.PlatformImpl).Invocations.Clear();
dotMemory.Check(memory =>
Assert.Equal(initialMenuCount, memory.GetObjects(where => where.Type.Is<ContextMenu>()).ObjectsCount));
dotMemory.Check(memory =>
@ -541,7 +541,7 @@ namespace Avalonia.LeakTests
BuildAndShowContextMenu(window);
BuildAndShowContextMenu(window);
Mock.Get(ValidatingWindowImpl.Unwrap(window.PlatformImpl)).Invocations.Clear();
Mock.Get(window.PlatformImpl).Invocations.Clear();
dotMemory.Check(memory =>
Assert.Equal(initialMenuCount, memory.GetObjects(where => where.Type.Is<ContextMenu>()).ObjectsCount));
dotMemory.Check(memory =>

Loading…
Cancel
Save