From 94ecd84c8f24d210f537c495e044ded266f1147b Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 18 Jul 2022 11:25:13 +0200 Subject: [PATCH 01/13] feat(LibInputBackend): minimal linux boot with no input --- .../Input/LibInput/LibInputBackend.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 15d42789d4..6e26794b24 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -1,16 +1,15 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using System.Threading; using Avalonia.Input; using Avalonia.Input.Raw; -using Avalonia.Threading; using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; namespace Avalonia.LinuxFramebuffer.Input.LibInput { public class LibInputBackend : IInputBackend { + private const string LibInput = nameof(Logging.LogArea.X11Platform) + "/" + nameof(LibInput); private IScreenInfoProvider _screen; private IInputRoot _inputRoot; private readonly Queue _inputThreadActions = new Queue(); @@ -29,15 +28,21 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput new Thread(()=>InputThread(ctx)).Start(); } - - private unsafe void InputThread(IntPtr ctx) { var fd = libinput_get_fd(ctx); var timeval = stackalloc IntPtr[2]; - + if (!Directory.Exists("/dev/input")) + { + if (Logging.Logger.IsEnabled(Logging.LogEventLevel.Warning,LibInput)) + { + Logging.Logger.TryGet(Logging.LogEventLevel.Warning, LibInput) + ?.Log(this, "Not connect any input device."); + } + return; + } foreach (var f in Directory.GetFiles("/dev/input", "event*")) libinput_path_add_device(ctx, f); while (true) From ef7ecb7c065719349f9c38b29001c29005f4d86f Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 2 Aug 2022 10:35:53 +0200 Subject: [PATCH 02/13] Revert "feat(LibInputBackend): minimal linux boot with no input" This reverts commit 94ecd84c8f24d210f537c495e044ded266f1147b. --- .../Input/LibInput/LibInputBackend.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 6e26794b24..15d42789d4 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -1,15 +1,16 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Threading; using Avalonia.Input; using Avalonia.Input.Raw; +using Avalonia.Threading; using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; namespace Avalonia.LinuxFramebuffer.Input.LibInput { public class LibInputBackend : IInputBackend { - private const string LibInput = nameof(Logging.LogArea.X11Platform) + "/" + nameof(LibInput); private IScreenInfoProvider _screen; private IInputRoot _inputRoot; private readonly Queue _inputThreadActions = new Queue(); @@ -28,21 +29,15 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput new Thread(()=>InputThread(ctx)).Start(); } + + private unsafe void InputThread(IntPtr ctx) { var fd = libinput_get_fd(ctx); var timeval = stackalloc IntPtr[2]; - if (!Directory.Exists("/dev/input")) - { - if (Logging.Logger.IsEnabled(Logging.LogEventLevel.Warning,LibInput)) - { - Logging.Logger.TryGet(Logging.LogEventLevel.Warning, LibInput) - ?.Log(this, "Not connect any input device."); - } - return; - } + foreach (var f in Directory.GetFiles("/dev/input", "event*")) libinput_path_add_device(ctx, f); while (true) From 197f514ae7fbb94849ce048c28434de4f1f2aee0 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 2 Aug 2022 10:47:11 +0200 Subject: [PATCH 03/13] feat(X11): NullInputBackend --- .../Input/LibInput/LibInputBackend.cs | 6 ------ .../Input/NullInput/NullInputBackend.cs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 15d42789d4..702ae3f8e5 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using System.Threading; using Avalonia.Input; using Avalonia.Input.Raw; -using Avalonia.Threading; using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; namespace Avalonia.LinuxFramebuffer.Input.LibInput { @@ -29,8 +27,6 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput new Thread(()=>InputThread(ctx)).Start(); } - - private unsafe void InputThread(IntPtr ctx) { var fd = libinput_get_fd(ctx); @@ -143,8 +139,6 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput } } - - public void Initialize(IScreenInfoProvider screen, Action onInput) { diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs new file mode 100644 index 0000000000..551c0995a2 --- /dev/null +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs @@ -0,0 +1,17 @@ +using System; +using Avalonia.Input; +using Avalonia.Input.Raw; + +namespace Avalonia.LinuxFramebuffer.Input.NullInput; + +internal class NullInputBackend : IInputBackend +{ + + public void Initialize(IScreenInfoProvider screen, Action onInput) + { + } + + public void SetInputRoot(IInputRoot root) + { + } +} From 46185b6a6eb78a887567dc483c5a1351fab61e30 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 2 Aug 2022 10:59:33 +0200 Subject: [PATCH 04/13] feat: add overload thath accept IInputBackend to Linux AppBuilder --- .../LinuxFramebufferPlatform.cs | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index a642766809..c819407cc9 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -15,7 +15,6 @@ using Avalonia.LinuxFramebuffer.Output; using Avalonia.OpenGL; using Avalonia.Platform; using Avalonia.Rendering; -using Avalonia.Threading; using JetBrains.Annotations; namespace Avalonia.LinuxFramebuffer @@ -37,9 +36,9 @@ namespace Avalonia.LinuxFramebuffer Threading = new InternalPlatformThreadingInterface(); if (_fb is IGlOutputBackend gl) AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl.PlatformOpenGlInterface); - + var opts = AvaloniaLocator.Current.GetService() ?? new LinuxFramebufferPlatformOptions(); - + AvaloniaLocator.CurrentMutable .Bind().ToConstant(Threading) .Bind().ToConstant(new DefaultRenderTimer(opts.Fps)) @@ -50,12 +49,12 @@ namespace Avalonia.LinuxFramebuffer .Bind().ToSingleton(); } - - internal static LinuxFramebufferLifetime Initialize(T builder, IOutputBackend outputBackend) where T : AppBuilderBase, new() + + internal static LinuxFramebufferLifetime Initialize(T builder, IOutputBackend outputBackend, IInputBackend inputBackend) where T : AppBuilderBase, new() { var platform = new LinuxFramebufferPlatform(outputBackend); builder.UseSkia().UseWindowingSubsystem(platform.Initialize, "fbdev"); - return new LinuxFramebufferLifetime(platform._fb); + return new LinuxFramebufferLifetime(platform._fb, inputBackend); } } @@ -71,13 +70,13 @@ namespace Avalonia.LinuxFramebuffer { _fb = fb; } - + public LinuxFramebufferLifetime(IOutputBackend fb, IInputBackend input) { _fb = fb; _inputBackend = input; } - + public Control MainView { get => (Control)_topLevel?.Content; @@ -117,7 +116,7 @@ namespace Avalonia.LinuxFramebuffer { Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args)); } - + public void Shutdown(int exitCode) { ExitCode = exitCode; @@ -131,22 +130,22 @@ namespace Avalonia.LinuxFramebuffer public static class LinuxFramebufferPlatformExtensions { - public static int StartLinuxFbDev(this T builder, string[] args, string fbdev = null, double scaling = 1) + public static int StartLinuxFbDev(this T builder, string[] args, string fbdev = null, double scaling = 1, IInputBackend inputBackend = default) where T : AppBuilderBase, new() => - StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: null) { Scaling = scaling }); - public static int StartLinuxFbDev(this T builder, string[] args, string fbdev, PixelFormat? format, double scaling) + StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: null) { Scaling = scaling }, inputBackend); + public static int StartLinuxFbDev(this T builder, string[] args, string fbdev, PixelFormat? format, double scaling, IInputBackend inputBackend = default) where T : AppBuilderBase, new() => - StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: format) { Scaling = scaling }); - - public static int StartLinuxDrm(this T builder, string[] args, string card = null, double scaling = 1) - where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card) {Scaling = scaling}); - public static int StartLinuxDrm(this T builder, string[] args, string card = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null) - where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options)); - - public static int StartLinuxDirect(this T builder, string[] args, IOutputBackend backend) + StartLinuxDirect(builder, args, new FbdevOutput(fileName: fbdev, format: format) { Scaling = scaling }, inputBackend); + + public static int StartLinuxDrm(this T builder, string[] args, string card = null, double scaling = 1, IInputBackend inputBackend = default) + where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card) { Scaling = scaling }, inputBackend); + public static int StartLinuxDrm(this T builder, string[] args, string card = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null, IInputBackend inputBackend = default) + where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options), inputBackend); + + public static int StartLinuxDirect(this T builder, string[] args, IOutputBackend outputBackend, IInputBackend inputBackend = default) where T : AppBuilderBase, new() { - var lifetime = LinuxFramebufferPlatform.Initialize(builder, backend); + var lifetime = LinuxFramebufferPlatform.Initialize(builder, outputBackend, inputBackend); builder.SetupWithLifetime(lifetime); lifetime.Start(args); builder.Instance.Run(lifetime.Token); From 64c94ca3415e3c5f9961c62eb6ca090ee7ab5c0a Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 3 Aug 2022 09:24:17 +0200 Subject: [PATCH 05/13] fix: NullInputBackend visibility --- .../Input/NullInput/NullInputBackend.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs index 551c0995a2..05dd0195b1 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/NullInput/NullInputBackend.cs @@ -4,9 +4,8 @@ using Avalonia.Input.Raw; namespace Avalonia.LinuxFramebuffer.Input.NullInput; -internal class NullInputBackend : IInputBackend +public class NullInputBackend : IInputBackend { - public void Initialize(IScreenInfoProvider screen, Action onInput) { } From 2dad5591382ab3ee9abeb8a10105cc11b1516a2c Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 8 Sep 2022 21:06:29 +0200 Subject: [PATCH 06/13] Transform screen position for the point args from another visual root --- src/Avalonia.Base/Input/PointerEventArgs.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Input/PointerEventArgs.cs b/src/Avalonia.Base/Input/PointerEventArgs.cs index 1f3c726e7b..5cc572198a 100644 --- a/src/Avalonia.Base/Input/PointerEventArgs.cs +++ b/src/Avalonia.Base/Input/PointerEventArgs.cs @@ -65,7 +65,17 @@ namespace Avalonia.Input return default; if (relativeTo == null) return pt; - return pt * _rootVisual.TransformToVisual(relativeTo) ?? default; + + var pointRootVisual = _rootVisual; + if (relativeTo.VisualRoot is { } root + && _rootVisual != root) + { + var screenPoint = _rootVisual.PointToScreen(pt); + pt = relativeTo.VisualRoot.PointToClient(screenPoint); + pointRootVisual = root; + } + + return pt * pointRootVisual.TransformToVisual(relativeTo) ?? default; } /// From 46bf9e26023d37ebd9808819a354410a8418ab96 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 8 Sep 2022 21:06:53 +0200 Subject: [PATCH 07/13] Fix issue with 0,0 position when pointerover was cleaned up --- src/Avalonia.Base/Input/PointerEventArgs.cs | 1 + .../Input/PointerOverPreProcessor.cs | 17 +++--- .../Input/PointerOverTests.cs | 58 ++++++++++++++++++- .../Input/PointerTests.cs | 2 +- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Base/Input/PointerEventArgs.cs b/src/Avalonia.Base/Input/PointerEventArgs.cs index 5cc572198a..d54d0be903 100644 --- a/src/Avalonia.Base/Input/PointerEventArgs.cs +++ b/src/Avalonia.Base/Input/PointerEventArgs.cs @@ -66,6 +66,7 @@ namespace Avalonia.Input if (relativeTo == null) return pt; + // If relativeTo visual is from another visual tree and possibly window, translate position first. var pointRootVisual = _rootVisual; if (relativeTo.VisualRoot is { } root && _rootVisual != root) diff --git a/src/Avalonia.Base/Input/PointerOverPreProcessor.cs b/src/Avalonia.Base/Input/PointerOverPreProcessor.cs index 2ebf01bcf6..e367f9f74f 100644 --- a/src/Avalonia.Base/Input/PointerOverPreProcessor.cs +++ b/src/Avalonia.Base/Input/PointerOverPreProcessor.cs @@ -68,27 +68,29 @@ namespace Avalonia.Input if (dirtyRect.Contains(clientPoint)) { - SetPointerOver(pointer, _inputRoot, _inputRoot.InputHitTest(clientPoint), 0, clientPoint, PointerPointProperties.None, KeyModifiers.None); + var element = pointer.Captured ?? _inputRoot.InputHitTest(clientPoint); + SetPointerOver(pointer, _inputRoot, element, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None); } else if (!_inputRoot.Bounds.Contains(clientPoint)) { - ClearPointerOver(pointer, _inputRoot, 0, new Point(-1, -1), PointerPointProperties.None, KeyModifiers.None); + ClearPointerOver(pointer, _inputRoot, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None); } } } private void ClearPointerOver() { - if (_lastPointer is (var pointer, var _)) + if (_lastPointer is (var pointer, var position)) { - ClearPointerOver(pointer, _inputRoot, 0, new Point(-1, -1), PointerPointProperties.None, KeyModifiers.None); + var clientPoint = _inputRoot.PointToClient(position); + ClearPointerOver(pointer, _inputRoot, 0, clientPoint, PointerPointProperties.None, KeyModifiers.None); } _lastPointer = null; _lastActivePointerDevice = null; } private void ClearPointerOver(IPointer pointer, IInputRoot root, - ulong timestamp, Point position, PointerPointProperties properties, KeyModifiers inputModifiers) + ulong timestamp, Point? position, PointerPointProperties properties, KeyModifiers inputModifiers) { var element = root.PointerOverElement; if (element is null) @@ -96,11 +98,10 @@ namespace Avalonia.Input return; } - // Do not pass rootVisual, when we have unknown (negative) position, + // Do not pass rootVisual, when we have unknown position, // so GetPosition won't return invalid values. - var hasPosition = position.X >= 0 && position.Y >= 0; var e = new PointerEventArgs(InputElement.PointerExitedEvent, element, pointer, - hasPosition ? root : null, hasPosition ? position : default, + position.HasValue ? root : null, position.HasValue ? position.Value : default, timestamp, properties, inputModifiers); if (element != null && !element.IsAttachedToVisualTree) diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs b/tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs index a83b176484..1ac50446c0 100644 --- a/tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs +++ b/tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs @@ -356,20 +356,28 @@ namespace Avalonia.Base.UnitTests.Input var impl = CreateTopLevelImplMock(renderer.Object); var invalidateRect = new Rect(0, 0, 15, 15); + var lastClientPosition = new Point(1, 5); + + var result = new List<(object?, string, Point)>(); + void HandleEvent(object? sender, PointerEventArgs e) + { + result.Add((sender, e.RoutedEvent!.Name, e.GetPosition(null))); + } Canvas canvas; - var root = CreateInputRoot(impl.Object, new Panel + var root = (Window)CreateInputRoot(impl.Object, new Panel { Children = { (canvas = new Canvas()) } }); + AddEnteredExitedHandlers(HandleEvent, root, canvas); // Let input know about latest device. SetHit(renderer, canvas); - impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root)); + impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root, lastClientPosition)); Assert.True(canvas.IsPointerOver); SetHit(renderer, canvas); @@ -380,6 +388,52 @@ namespace Avalonia.Base.UnitTests.Input SetHit(renderer, null); renderer.Raise(r => r.SceneInvalidated += null, new SceneInvalidatedEventArgs((IRenderRoot)root, invalidateRect)); Assert.False(canvas.IsPointerOver); + + Assert.Equal( + new[] + { + ((object?)canvas, nameof(InputElement.PointerEntered), lastClientPosition), + (root, nameof(InputElement.PointerEntered), lastClientPosition), + (canvas, nameof(InputElement.PointerExited), lastClientPosition), + (root, nameof(InputElement.PointerExited), lastClientPosition), + }, + result); + } + + [Fact] + public void PointerOver_Invalidation_Should_Use_Previously_Captured_Element() + { + using var app = UnitTestApplication.Start(new TestServices(inputManager: new InputManager())); + + var renderer = new Mock(); + var deviceMock = CreatePointerDeviceMock(); + var impl = CreateTopLevelImplMock(renderer.Object); + + var invalidateRect = new Rect(0, 0, 15, 15); + + Canvas canvas1, canvas2; + + var root = CreateInputRoot(impl.Object, new Panel + { + Children = + { + (canvas1 = new Canvas()), + (canvas2 = new Canvas()) + } + }); + + canvas1.PointerMoved += (s, a) => a.Pointer.Capture(canvas1); + + // Let input know about latest device. + SetHit(renderer, canvas1); + impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root)); + Assert.True(canvas1.IsPointerOver); + Assert.False(canvas2.IsPointerOver); + + SetHit(renderer, canvas2); + renderer.Raise(r => r.SceneInvalidated += null, new SceneInvalidatedEventArgs((IRenderRoot)root, invalidateRect)); + Assert.False(canvas1.IsPointerOver); + Assert.True(canvas2.IsPointerOver); } // https://github.com/AvaloniaUI/Avalonia/issues/7748 diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs b/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs index e25ef0a9b8..0bd23d64a9 100644 --- a/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs +++ b/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs @@ -8,7 +8,7 @@ using Xunit; namespace Avalonia.Base.UnitTests.Input { - public class PointerTests + public class PointerTests : PointerTestsBase { [Fact] public void On_Capture_Transfer_PointerCaptureLost_Should_Propagate_Up_To_The_Common_Parent() From 71a79c6e90ec536f941da44278b8814d13a4f21d Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 12 Sep 2022 12:24:54 +0200 Subject: [PATCH 08/13] fix: XML Comment --- src/Avalonia.Base/Utilities/IWeakSubscriber.cs | 2 +- src/Avalonia.Controls/Window.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Avalonia.Base/Utilities/IWeakSubscriber.cs b/src/Avalonia.Base/Utilities/IWeakSubscriber.cs index 613c931165..2a5b8d39c5 100644 --- a/src/Avalonia.Base/Utilities/IWeakSubscriber.cs +++ b/src/Avalonia.Base/Utilities/IWeakSubscriber.cs @@ -3,7 +3,7 @@ using System; namespace Avalonia.Utilities { /// - /// Defines a listener to a event subscribed vis the . + /// Defines a listener to a event subscribed vis the . /// /// The type of the event arguments. public interface IWeakSubscriber where T : EventArgs diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 1f3b10c0cc..03c66aff2b 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -378,8 +378,6 @@ namespace Avalonia.Controls /// /// Enables or disables resizing of the window. - /// Note that if is set to False then this property - /// has no effect and should be treated as a recommendation for the user setting HasSystemDecorations. /// public bool CanResize { From 913fa7978a46568c6b57f707c9466fe14fd81683 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 12 Sep 2022 14:40:46 +0200 Subject: [PATCH 09/13] fix: empty statment --- src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs | 2 +- .../Input/GestureRecognizers/ScrollGestureRecognizer.cs | 2 +- src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs index 0288dbce91..6232fa39a1 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/ObservableStreamPlugin.cs @@ -42,7 +42,7 @@ namespace Avalonia.Data.Core.Plugins if (target is IObservable result) { return result; - }; + } // If the observable returns a value type then we need to call Observable.Select on it. // First get the type of T in `IObservable`. diff --git a/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs b/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs index 889b7e3b82..4f5585ab6c 100644 --- a/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs +++ b/src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs @@ -71,7 +71,7 @@ namespace Avalonia.Input.GestureRecognizers { EndGesture(); _tracking = e.Pointer; - _gestureId = ScrollGestureEventArgs.GetNextFreeId();; + _gestureId = ScrollGestureEventArgs.GetNextFreeId(); _trackedRootPoint = e.GetPosition(_target); } } diff --git a/src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs b/src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs index 3e516b4f97..e6a95d1ffb 100644 --- a/src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs +++ b/src/Avalonia.Base/Layout/FlowLayoutAlgorithm.cs @@ -523,7 +523,7 @@ namespace Avalonia.Layout { firstRealizedElement = _elementManager.GetAt(0); firstBounds = _elementManager.GetLayoutBoundsForRealizedIndex(0); - firstDataIndex = _elementManager.GetDataIndexFromRealizedRangeIndex(0);; + firstDataIndex = _elementManager.GetDataIndexFromRealizedRangeIndex(0); int last = _elementManager.GetRealizedElementCount() - 1; lastRealizedElement = _elementManager.GetAt(last); From 220bb0774efed416f8606131014c9090af4ab45d Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 13 Sep 2022 09:11:24 +0200 Subject: [PATCH 10/13] fix: static field visibility --- src/Avalonia.Base/Media/TextTrimming.cs | 10 +++++----- src/Avalonia.Base/Media/UnicodeRange.cs | 2 +- .../Media/TextFormatting/TextFormatterTests.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Base/Media/TextTrimming.cs b/src/Avalonia.Base/Media/TextTrimming.cs index b6f5be496f..e2737210be 100644 --- a/src/Avalonia.Base/Media/TextTrimming.cs +++ b/src/Avalonia.Base/Media/TextTrimming.cs @@ -8,7 +8,7 @@ namespace Avalonia.Media /// public abstract class TextTrimming { - public static char s_defaultEllipsisChar = '\u2026'; + internal const char DefaultEllipsisChar = '\u2026'; /// /// Text is not trimmed. @@ -18,22 +18,22 @@ namespace Avalonia.Media /// /// Text is trimmed at a character boundary. An ellipsis (...) is drawn in place of remaining text. /// - public static TextTrimming CharacterEllipsis { get; } = new TextTrailingTrimming(s_defaultEllipsisChar, false); + public static TextTrimming CharacterEllipsis { get; } = new TextTrailingTrimming(DefaultEllipsisChar, false); /// /// Text is trimmed at a word boundary. An ellipsis (...) is drawn in place of remaining text. /// - public static TextTrimming WordEllipsis { get; } = new TextTrailingTrimming(s_defaultEllipsisChar, true); + public static TextTrimming WordEllipsis { get; } = new TextTrailingTrimming(DefaultEllipsisChar, true); /// /// Text is trimmed after a given prefix length. An ellipsis (...) is drawn in between prefix and suffix and represents remaining text. /// - public static TextTrimming PrefixCharacterEllipsis { get; } = new TextLeadingPrefixTrimming(s_defaultEllipsisChar, 8); + public static TextTrimming PrefixCharacterEllipsis { get; } = new TextLeadingPrefixTrimming(DefaultEllipsisChar, 8); /// /// Text is trimmed at a character boundary starting from the beginning. An ellipsis (...) is drawn in place of remaining text. /// - public static TextTrimming LeadingCharacterEllipsis { get; } = new TextLeadingPrefixTrimming(s_defaultEllipsisChar, 0); + public static TextTrimming LeadingCharacterEllipsis { get; } = new TextLeadingPrefixTrimming(DefaultEllipsisChar, 0); /// /// Creates properties that will be used for collapsing lines of text. diff --git a/src/Avalonia.Base/Media/UnicodeRange.cs b/src/Avalonia.Base/Media/UnicodeRange.cs index 0077dd64ac..e2338b9b26 100644 --- a/src/Avalonia.Base/Media/UnicodeRange.cs +++ b/src/Avalonia.Base/Media/UnicodeRange.cs @@ -9,7 +9,7 @@ namespace Avalonia.Media /// public readonly struct UnicodeRange { - public static UnicodeRange Default = Parse("0-10FFFD"); + public readonly static UnicodeRange Default = Parse("0-10FFFD"); private readonly UnicodeRangeSegment _single; private readonly IReadOnlyList? _segments = null; diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 48dbfa5985..960c409058 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs @@ -389,7 +389,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting if (textLine.Width > 300 || currentHeight + textLine.Height > 240) { - textLine = textLine.Collapse(new TextTrailingWordEllipsis(new ReadOnlySlice(new[] { TextTrimming.s_defaultEllipsisChar }), 300, defaultProperties)); + textLine = textLine.Collapse(new TextTrailingWordEllipsis(new ReadOnlySlice(new[] { TextTrimming.DefaultEllipsisChar }), 300, defaultProperties)); } currentHeight += textLine.Height; From 1151f6de25c5a3fb59db3740ef6ccc92f4e741fd Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 13 Sep 2022 09:16:29 +0200 Subject: [PATCH 11/13] fix(DevGenerator): The variable 'changesVar' is assigned but its value is never used --- src/tools/DevGenerators/CompositionGenerator/Generator.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tools/DevGenerators/CompositionGenerator/Generator.cs b/src/tools/DevGenerators/CompositionGenerator/Generator.cs index cbcc55ada0..5c4af5de2e 100644 --- a/src/tools/DevGenerators/CompositionGenerator/Generator.cs +++ b/src/tools/DevGenerators/CompositionGenerator/Generator.cs @@ -133,10 +133,6 @@ namespace Avalonia.SourceGenerator.CompositionGenerator MethodDeclaration(ParseTypeName("void"), "Initialize") .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon())); - - var changesVarName = "c"; - var changesVar = IdentifierName(changesVarName); - server = server.AddMembers( MethodDeclaration(ParseTypeName("void"), "DeserializeChangesExtra") .AddParameterListParameters(Parameter(Identifier("c")).WithType(ParseTypeName("BatchStreamReader"))) From 0f6523ec813f322a301ea945f8ee565a3799ed83 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 13 Sep 2022 16:48:05 +0200 Subject: [PATCH 12/13] fix(MicroComProxyBase): CS8073 The result of the expression is always 'false' since a value of type 'IntPtr' is never equal to 'null' --- src/Avalonia.MicroCom/MicroComProxyBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.MicroCom/MicroComProxyBase.cs b/src/Avalonia.MicroCom/MicroComProxyBase.cs index 140af3e4ef..fe8a2bf9cf 100644 --- a/src/Avalonia.MicroCom/MicroComProxyBase.cs +++ b/src/Avalonia.MicroCom/MicroComProxyBase.cs @@ -65,7 +65,7 @@ namespace Avalonia.MicroCom protected virtual void Dispose(bool disposing) { - if(_nativePointer == null) + if(_nativePointer == IntPtr.Zero) return; if (_ownsHandle) { From 5a12a036d96e758a640c905b0cd295f9ea75bc1b Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 13 Sep 2022 18:50:23 +0200 Subject: [PATCH 13/13] Undo pointer transformation changes --- src/Avalonia.Base/Input/PointerEventArgs.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Avalonia.Base/Input/PointerEventArgs.cs b/src/Avalonia.Base/Input/PointerEventArgs.cs index d54d0be903..a0e8d4a074 100644 --- a/src/Avalonia.Base/Input/PointerEventArgs.cs +++ b/src/Avalonia.Base/Input/PointerEventArgs.cs @@ -66,17 +66,7 @@ namespace Avalonia.Input if (relativeTo == null) return pt; - // If relativeTo visual is from another visual tree and possibly window, translate position first. - var pointRootVisual = _rootVisual; - if (relativeTo.VisualRoot is { } root - && _rootVisual != root) - { - var screenPoint = _rootVisual.PointToScreen(pt); - pt = relativeTo.VisualRoot.PointToClient(screenPoint); - pointRootVisual = root; - } - - return pt * pointRootVisual.TransformToVisual(relativeTo) ?? default; + return pt * _rootVisual.TransformToVisual(relativeTo) ?? default; } ///