Browse Source

Move some input handling out of TopLevel

feature/presentation-source-2
Nikita Tsukanov 2 months ago
parent
commit
14dcc3a275
  1. 59
      src/Avalonia.Controls/PresentationSource/PresentationSource.Input.cs
  2. 12
      src/Avalonia.Controls/PresentationSource/PresentationSource.cs
  3. 46
      src/Avalonia.Controls/TopLevel.cs

59
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
{
/// <summary>
/// Handles input from <see cref="ITopLevelImpl.Input"/>.
/// </summary>
/// <param name="e">The event args.</param>
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;
}
}

12
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<IInputManager>(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;
}

46
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;
}
/// <summary>
/// Handles input from <see cref="ITopLevelImpl.Input"/>.
/// </summary>
/// <param name="e">The event args.</param>
private void HandleInput(RawInputEventArgs e)
{
if (PlatformImpl != null)
{
Dispatcher.UIThread.Send(static state =>
{
using var _ = Diagnostic.BeginLayoutInputPass();
var (topLevel, e) = (ValueTuple<TopLevel, RawInputEventArgs>)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);

Loading…
Cancel
Save