diff --git a/src/Avalonia.Controls/PresentationSource/PresentationSource.Input.cs b/src/Avalonia.Controls/PresentationSource/PresentationSource.Input.cs new file mode 100644 index 0000000000..53e6e0ea7b --- /dev/null +++ b/src/Avalonia.Controls/PresentationSource/PresentationSource.Input.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using Avalonia.Diagnostics; +using Avalonia.Input; +using Avalonia.Input.Raw; +using Avalonia.Logging; +using Avalonia.Platform; +using Avalonia.Threading; + +namespace Avalonia.Controls; + +internal partial class PresentationSource +{ + /// + /// Handles input from . + /// + /// The event args. + private void HandleInputCore(object state) + { + using var _ = Diagnostic.BeginLayoutInputPass(); + + var e = (RawInputEventArgs)state!; + if (e is RawPointerEventArgs pointerArgs) + { + var hitTestElement = RootElement.InputHitTest(pointerArgs.Position, enabledElementsOnly: false); + + pointerArgs.InputHitTestResult = (hitTestElement, FirstEnabledAncestor(hitTestElement)); + } + + _inputManager?.ProcessInput(e); + } + + private SendOrPostCallback _handleInputCore; + + private void HandleInput(RawInputEventArgs e) + { + if (PlatformImpl != null) + { + Dispatcher.UIThread.Send(_handleInputCore, e); + } + else + { + Logger.TryGet(LogEventLevel.Warning, LogArea.Control)?.Log( + this, + "PlatformImpl is null, couldn't handle input."); + } + } + + + private static IInputElement? FirstEnabledAncestor(IInputElement? hitTestElement) + { + var candidate = hitTestElement; + while (candidate?.IsEffectivelyEnabled == false) + { + candidate = (candidate as Visual)?.VisualParent as IInputElement; + } + return candidate; + } +} \ No newline at end of file diff --git a/src/Avalonia.Controls/PresentationSource/PresentationSource.cs b/src/Avalonia.Controls/PresentationSource/PresentationSource.cs index 5a01cb2d8e..ca9f6a8b92 100644 --- a/src/Avalonia.Controls/PresentationSource/PresentationSource.cs +++ b/src/Avalonia.Controls/PresentationSource/PresentationSource.cs @@ -9,7 +9,7 @@ namespace Avalonia.Controls; internal partial class PresentationSource : IPresentationSource, IDisposable { - public ITopLevelImpl PlatformImpl { get; } + public ITopLevelImpl? PlatformImpl { get; private set; } private readonly PointerOverPreProcessor? _pointerOverPreProcessor; private readonly IDisposable? _pointerOverPreProcessorSubscription; private readonly IInputManager? _inputManager; @@ -21,9 +21,14 @@ internal partial class PresentationSource : IPresentationSource, IDisposable { RootVisual = rootVisual; PlatformImpl = platformImpl; - + _inputManager = TryGetService(dependencyResolver); + _handleInputCore = HandleInputCore; + + PlatformImpl.SetInputRoot(this); + PlatformImpl.Input = HandleInput; + _pointerOverPreProcessor = new PointerOverPreProcessor(this); _pointerOverPreProcessorSubscription = _inputManager?.PreProcess.Subscribe(_pointerOverPreProcessor); } @@ -63,6 +68,7 @@ internal partial class PresentationSource : IPresentationSource, IDisposable public void Dispose() { + PlatformImpl = null; _pointerOverPreProcessor?.OnCompleted(); _pointerOverPreProcessorSubscription?.Dispose(); } @@ -96,7 +102,7 @@ internal partial class PresentationSource : IPresentationSource, IDisposable } // TODO: Make popup positioner to use PresentationSource internally rather than TopLevel - public PixelPoint? GetLastPointerPosition(TopLevel topLevel) + public PixelPoint? GetLastPointerPosition(Visual topLevel) { return _pointerOverPreProcessor?.LastPosition; } diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index b0be6ad2f3..ac7d629cba 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -212,11 +212,9 @@ namespace Avalonia.Controls Renderer = new CompositingRenderer(this, impl.Compositor, () => PlatformImpl.Surfaces ?? []); Renderer.SceneInvalidated += SceneInvalidated; - - impl.SetInputRoot(_source); + impl.Closed = HandleClosed; - impl.Input = HandleInput; impl.Paint = HandlePaint; impl.Resized = HandleResized; impl.ScalingChanged = HandleScalingChanged; @@ -815,48 +813,6 @@ namespace Avalonia.Controls return result; } - /// - /// Handles input from . - /// - /// The event args. - private void HandleInput(RawInputEventArgs e) - { - if (PlatformImpl != null) - { - Dispatcher.UIThread.Send(static state => - { - using var _ = Diagnostic.BeginLayoutInputPass(); - - var (topLevel, e) = (ValueTuple)state!; - if (e is RawPointerEventArgs pointerArgs) - { - var hitTestElement = topLevel.InputHitTest(pointerArgs.Position, enabledElementsOnly: false); - - pointerArgs.InputHitTestResult = (hitTestElement, FirstEnabledAncestor(hitTestElement)); - } - - topLevel._inputManager?.ProcessInput(e); - }, (this, e)); - } - else - { - Logger.TryGet(LogEventLevel.Warning, LogArea.Control)?.Log( - this, - "PlatformImpl is null, couldn't handle input."); - } - } - - private static IInputElement? FirstEnabledAncestor(IInputElement? hitTestElement) - { - var candidate = hitTestElement; - while (candidate?.IsEffectivelyEnabled == false) - { - candidate = (candidate as Visual)?.VisualParent as IInputElement; - } - - return candidate; - } - private void GlobalActualThemeVariantChanged(object? sender, EventArgs e) { SetValue(ActualThemeVariantProperty, ((IThemeVariantHost)sender!).ActualThemeVariant, BindingPriority.Template);