From 2033a43b9b904573483173b97d7b8956a4d47eed Mon Sep 17 00:00:00 2001 From: ahopper Date: Fri, 13 Sep 2019 11:16:36 +0100 Subject: [PATCH 0001/1512] fix pointerover on mouse leaving window --- src/Windows/Avalonia.Win32/WindowImpl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9bd58c10bc..45daeaaef9 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -619,7 +619,7 @@ namespace Avalonia.Win32 timestamp, _owner, RawPointerEventType.LeaveWindow, - new Point(), WindowsKeyboardDevice.Instance.Modifiers); + new Point(-1,-1), WindowsKeyboardDevice.Instance.Modifiers); break; case UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN: @@ -634,7 +634,7 @@ namespace Avalonia.Win32 : msg == (int)UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN ? RawPointerEventType.RightButtonDown : RawPointerEventType.MiddleButtonDown, - new Point(0, 0), GetMouseModifiers(wParam)); + PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam)); break; case WindowsMessage.WM_TOUCH: var touchInputs = new TOUCHINPUT[wParam.ToInt32()]; From f29aeffecd7e95d2d63669b648c7a8580c58ffaa Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 3 Oct 2019 18:01:04 +0200 Subject: [PATCH 0002/1512] Avoid boxing mouse modifiers. --- src/Avalonia.Base/EnumExtensions.cs | 23 +++++++++++++++++++++++ src/Windows/Avalonia.Win32/WindowImpl.cs | 12 ++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 src/Avalonia.Base/EnumExtensions.cs diff --git a/src/Avalonia.Base/EnumExtensions.cs b/src/Avalonia.Base/EnumExtensions.cs new file mode 100644 index 0000000000..a8306c2d69 --- /dev/null +++ b/src/Avalonia.Base/EnumExtensions.cs @@ -0,0 +1,23 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; + +namespace Avalonia +{ + /// + /// Provides extension methods for enums. + /// + public static class EnumExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool HasFlagCustom(this T value, T flag) where T : unmanaged, Enum + { + var intValue = *(int*)&value; + var intFlag = *(int*)&flag; + + return (intValue & intFlag) == intFlag; + } + } +} diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index e8c3177ec5..6a733356b8 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -646,9 +646,9 @@ namespace Avalonia.Win32 { Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time, _owner, - touchInput.Flags.HasFlag(TouchInputFlags.TOUCHEVENTF_UP) ? + touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_UP) ? RawPointerEventType.TouchEnd : - touchInput.Flags.HasFlag(TouchInputFlags.TOUCHEVENTF_DOWN) ? + touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_DOWN) ? RawPointerEventType.TouchBegin : RawPointerEventType.TouchUpdate, PointToClient(new PixelPoint(touchInput.X / 100, touchInput.Y / 100)), @@ -768,11 +768,11 @@ namespace Avalonia.Win32 { var keys = (UnmanagedMethods.ModifierKeys)ToInt32(wParam); var modifiers = WindowsKeyboardDevice.Instance.Modifiers; - if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) + if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) modifiers |= RawInputModifiers.LeftMouseButton; - if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) + if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) modifiers |= RawInputModifiers.RightMouseButton; - if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) + if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) modifiers |= RawInputModifiers.MiddleMouseButton; return modifiers; } @@ -782,7 +782,7 @@ namespace Avalonia.Win32 // Ensure that the delegate doesn't get garbage collected by storing it as a field. _wndProcDelegate = new UnmanagedMethods.WndProc(WndProc); - _className = "Avalonia-" + Guid.NewGuid(); + _className = $"Avalonia-{Guid.NewGuid().ToString()}"; UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX { From 09e76184631125508d834b04f45e0c707a709ce5 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 3 Oct 2019 18:24:28 +0200 Subject: [PATCH 0003/1512] Remove boxing from PointerPointProperties. --- src/Avalonia.Input/PointerPoint.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Input/PointerPoint.cs b/src/Avalonia.Input/PointerPoint.cs index d823a78090..55c1889e58 100644 --- a/src/Avalonia.Input/PointerPoint.cs +++ b/src/Avalonia.Input/PointerPoint.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + namespace Avalonia.Input { public sealed class PointerPoint @@ -27,9 +30,9 @@ namespace Avalonia.Input public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind) { PointerUpdateKind = kind; - IsLeftButtonPressed = modifiers.HasFlag(RawInputModifiers.LeftMouseButton); - IsMiddleButtonPressed = modifiers.HasFlag(RawInputModifiers.MiddleMouseButton); - IsRightButtonPressed = modifiers.HasFlag(RawInputModifiers.RightMouseButton); + IsLeftButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.LeftMouseButton); + IsMiddleButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.MiddleMouseButton); + IsRightButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.RightMouseButton); // The underlying input source might be reporting the previous state, // so make sure that we reflect the current state From e1bfdf03246a8fe2df2fb443eb6226e17ef1940d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 10 Oct 2019 23:01:30 +0200 Subject: [PATCH 0004/1512] Added failing test for #3094. --- .../Primitives/SelectingItemsControlTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index d5237e2aca..17f0e609a5 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -1000,6 +1000,26 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.Equal(new[] { "Bar" }, selectedItems); } + [Fact] + public void MoveSelection_Wrap_Does_Not_Hang_With_No_Focusable_Controls() + { + // Issue #3094. + var target = new TestSelector + { + Template = Template(), + Items = new[] + { + new ListBoxItem { Focusable = false }, + new ListBoxItem { Focusable = false }, + }, + SelectedIndex = 0, + }; + + target.Measure(new Size(100, 100)); + target.Arrange(new Rect(0, 0, 100, 100)); + target.MoveSelection(NavigationDirection.Next, true); + } + private FuncControlTemplate Template() { return new FuncControlTemplate((control, scope) => @@ -1044,5 +1064,13 @@ namespace Avalonia.Controls.UnitTests.Primitives public List Items { get; set; } = new List() { "a", "b", "c", "d", "e" }; public string Selected { get; set; } = "b"; } + + private class TestSelector : SelectingItemsControl + { + public new bool MoveSelection(NavigationDirection direction, bool wrap) + { + return base.MoveSelection(direction, wrap); + } + } } } From 60c9015a7fd42a5cc13d156fd70c0c3f5444ceda Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 10 Oct 2019 23:03:12 +0200 Subject: [PATCH 0005/1512] Prevent hang in ItemsControl with no focusable controls. --- src/Avalonia.Controls/ItemsControl.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 0fe7291835..6b81237e6f 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -489,18 +489,20 @@ namespace Avalonia.Controls bool wrap) { IInputElement result; + var c = from; do { - result = container.GetControl(direction, from, wrap); + result = container.GetControl(direction, c, wrap); + from ??= result; if (result?.Focusable == true) { return result; } - from = result; - } while (from != null); + c = result; + } while (c != null && c != from); return null; } From adb65f14b1e0fdb86889d2038c5f4dcdf18a312c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 11 Oct 2019 15:13:48 +0200 Subject: [PATCH 0006/1512] Don't use C#8 features yet. --- src/Avalonia.Controls/ItemsControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 6b81237e6f..11fdd0457d 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -494,7 +494,7 @@ namespace Avalonia.Controls do { result = container.GetControl(direction, c, wrap); - from ??= result; + from = from ?? result; if (result?.Focusable == true) { From 88446b1e9ead00ad4a8178981e3670d7100eeebc Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Mon, 14 Oct 2019 17:33:14 +0800 Subject: [PATCH 0007/1512] Pass PointerPressed event to BeginModeDrag and BeginResizeDrag. --- samples/ControlCatalog/DecoratedWindow.xaml.cs | 11 ++++++----- src/Avalonia.Controls/Platform/IWindowImpl.cs | 13 +++++++------ src/Avalonia.Controls/Window.cs | 4 ++-- .../Remote/PreviewerWindowImpl.cs | 5 +++-- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 14 +++++++------- src/Avalonia.Native/WindowImplBase.cs | 4 ++-- src/Avalonia.X11/X11Window.cs | 12 +++++++----- src/Windows/Avalonia.Win32/WindowImpl.cs | 4 ++-- 8 files changed, 36 insertions(+), 31 deletions(-) diff --git a/samples/ControlCatalog/DecoratedWindow.xaml.cs b/samples/ControlCatalog/DecoratedWindow.xaml.cs index 2e7218b956..d76ef0a7bf 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml.cs +++ b/samples/ControlCatalog/DecoratedWindow.xaml.cs @@ -18,18 +18,18 @@ namespace ControlCatalog { var ctl = this.FindControl(name); ctl.Cursor = new Cursor(cursor); - ctl.PointerPressed += delegate + ctl.PointerPressed += (i, e) => { - PlatformImpl?.BeginResizeDrag(edge); + PlatformImpl?.BeginResizeDrag(edge, e); }; } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); - this.FindControl("TitleBar").PointerPressed += delegate + this.FindControl("TitleBar").PointerPressed += (i, e) => { - PlatformImpl?.BeginMoveDrag(); + PlatformImpl?.BeginMoveDrag(e); }; SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West); SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East); @@ -39,7 +39,8 @@ namespace ControlCatalog SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast); SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest); SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast); - this.FindControl