From bdd576bfc066021f69944c0ae80bf9ce0c19a137 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 24 Feb 2022 22:22:33 +0100 Subject: [PATCH] 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 --- src/Avalonia.Controls/Primitives/PopupRoot.cs | 2 +- src/Avalonia.Controls/TopLevel.cs | 2 - src/Avalonia.Controls/ValidatingToplevel.cs | 344 ------------------ src/Avalonia.Controls/Window.cs | 11 +- src/Avalonia.Controls/WindowBase.cs | 9 +- .../WindowTests.cs | 2 +- tests/Avalonia.LeakTests/ControlTests.cs | 4 +- 7 files changed, 13 insertions(+), 361 deletions(-) delete mode 100644 src/Avalonia.Controls/ValidatingToplevel.cs diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs index be447ea5122..a9a362a7622 100644 --- a/src/Avalonia.Controls/Primitives/PopupRoot.cs +++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs @@ -44,7 +44,7 @@ public PopupRoot(TopLevel parent, IPopupImpl impl) /// The dependency resolver to use. If null the default dependency resolver will be used. /// public PopupRoot(TopLevel parent, IPopupImpl impl, IAvaloniaDependencyResolver? dependencyResolver) - : base(ValidatingPopupImpl.Wrap(impl), dependencyResolver) + : base(impl, dependencyResolver) { _parent = parent; } diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 6bba8897488..a4fe1545158 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -134,8 +134,6 @@ public TopLevel(ITopLevelImpl impl, IAvaloniaDependencyResolver? dependencyResol "Could not create window implementation: maybe no windowing subsystem was initialized?"); } - impl = ValidatingToplevelImpl.Wrap(impl); - PlatformImpl = impl; _actualTransparencyLevel = PlatformImpl.TransparencyLevel; diff --git a/src/Avalonia.Controls/ValidatingToplevel.cs b/src/Avalonia.Controls/ValidatingToplevel.cs deleted file mode 100644 index 7e15bf4879a..00000000000 --- a/src/Avalonia.Controls/ValidatingToplevel.cs +++ /dev/null @@ -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 Surfaces => Inner.Surfaces; - - public Action? Input - { - get => Inner.Input; - set => Inner.Input = value; - } - - public Action? Paint - { - get => Inner.Paint; - set => Inner.Paint = value; - } - - public Action? Resized - { - get => Inner.Resized; - set => Inner.Resized = value; - } - - public Action? ScalingChanged - { - get => Inner.ScalingChanged; - set => Inner.ScalingChanged = value; - } - - public Action? 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? 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 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 Closing - { - get => Inner.Closing; - set => Inner.Closing = value; - } - - public bool IsClientAreaExtendedToDecorations => Inner.IsClientAreaExtendedToDecorations; - - public Action 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); -} diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 2e31e1095d5..e138a05c7d7 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -237,14 +237,13 @@ public Window() /// /// The window implementation. 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); diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 44644910200..cebdd8d8976 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -57,13 +57,12 @@ public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current) { } - 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; } /// diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 41662424553..eb128ef0385 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -821,7 +821,7 @@ public void Setting_Width_Should_Resize_WindowImpl() 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); } diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index eed767e7712..087d42370ee 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -496,7 +496,7 @@ void AttachShowAndDetachContextMenu(Control control) 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()).ObjectsCount)); dotMemory.Check(memory => @@ -541,7 +541,7 @@ void BuildAndShowContextMenu(Control control) 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()).ObjectsCount)); dotMemory.Check(memory =>