From 1eb3d875108cdf366487461ec85fe6e21322e876 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 7 Feb 2020 11:40:48 -0300 Subject: [PATCH 01/11] remove nullable directive. --- src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index bf811ad008..31c62dec28 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -6,8 +6,6 @@ using Avalonia.LogicalTree; using Avalonia.Rendering; using Avalonia.Threading; -#nullable enable - namespace Avalonia.Controls.Platform { /// From a3ab1578cd8806151bf52a078027f0fe56135740 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 7 Feb 2020 18:00:03 +0300 Subject: [PATCH 02/11] Removed C# 8.0 feature usage --- .../Platform/DefaultMenuInteractionHandler.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index 31c62dec28..8af71a6c1f 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -14,8 +14,8 @@ namespace Avalonia.Controls.Platform public class DefaultMenuInteractionHandler : IMenuInteractionHandler { private readonly bool _isContextMenu; - private IDisposable? _inputManagerSubscription; - private IRenderRoot? _root; + private IDisposable _inputManagerSubscription; + private IRenderRoot _root; public DefaultMenuInteractionHandler(bool isContextMenu) : this(isContextMenu, Input.InputManager.Instance, DefaultDelayRun) @@ -24,7 +24,7 @@ namespace Avalonia.Controls.Platform public DefaultMenuInteractionHandler( bool isContextMenu, - IInputManager? inputManager, + IInputManager inputManager, Action delayRun) { delayRun = delayRun ?? throw new ArgumentNullException(nameof(delayRun)); @@ -94,7 +94,7 @@ namespace Avalonia.Controls.Platform root.Deactivated -= WindowDeactivated; } - _inputManagerSubscription!.Dispose(); + _inputManagerSubscription.Dispose(); Menu = null; _root = null; @@ -102,9 +102,9 @@ namespace Avalonia.Controls.Platform protected Action DelayRun { get; } - protected IInputManager? InputManager { get; } + protected IInputManager InputManager { get; } - protected IMenu? Menu { get; private set; } + protected IMenu Menu { get; private set; } protected static TimeSpan MenuShowDelay { get; } = TimeSpan.FromMilliseconds(400); @@ -133,7 +133,7 @@ namespace Avalonia.Controls.Platform KeyDown(GetMenuItem(e.Source as IControl), e); } - protected internal virtual void KeyDown(IMenuItem? item, KeyEventArgs e) + protected internal virtual void KeyDown(IMenuItem item, KeyEventArgs e) { switch (e.Key) { @@ -202,7 +202,7 @@ namespace Avalonia.Controls.Platform } else { - Menu!.Close(); + Menu.Close(); } e.Handled = true; @@ -215,7 +215,7 @@ namespace Avalonia.Controls.Platform { if (item == null && _isContextMenu) { - if (Menu!.MoveSelection(direction.Value, true) == true) + if (Menu.MoveSelection(direction.Value, true) == true) { e.Handled = true; } @@ -410,7 +410,7 @@ namespace Avalonia.Controls.Platform protected void CloseMenu(IMenuItem item) { - var current = (IMenuElement?)item; + var current = (IMenuElement)item; while (current != null && !(current is IMenu)) { @@ -458,7 +458,7 @@ namespace Avalonia.Controls.Platform protected void SelectItemAndAncestors(IMenuItem item) { - var current = (IMenuItem?)item; + var current = item; while (current?.Parent != null) { @@ -467,7 +467,7 @@ namespace Avalonia.Controls.Platform } } - protected static IMenuItem? GetMenuItem(IControl? item) + protected static IMenuItem GetMenuItem(IControl item) { while (true) { From 82a0f0e476a6c0e5bee816b68832d2cc12322572 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 10 Feb 2020 12:44:30 +0100 Subject: [PATCH 03/11] Merge pull request #3537 from MarchingCube/fix-weak-event-manager-compact WeakEventHandlerManager: Ensure that weak refs with collected refs are compacted as well. --- src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs index 37e25d0fac..aca08f5259 100644 --- a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs +++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs @@ -183,11 +183,16 @@ namespace Avalonia.Utilities for (int c = 0; c < _count; c++) { var r = _data[c]; + + TSubscriber target = null; + + r.Subscriber?.TryGetTarget(out target); + //Mark current index as first empty - if (r.Subscriber == null && empty == -1) + if (target == null && empty == -1) empty = c; //If current element isn't null and we have an empty one - if (r.Subscriber != null && empty != -1) + if (target != null && empty != -1) { _data[c] = default; _data[empty] = r; From 8e452a1e4fa87154c1c5567c3cd5dd9793471387 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 12 Feb 2020 14:45:17 +0100 Subject: [PATCH 04/11] Merge pull request #3557 from AvaloniaUI/fixes/3426-selecting-disabled-control Don't select disabled controls with keyboard --- src/Avalonia.Controls/ItemsControl.cs | 5 ++++- .../Primitives/SelectingItemsControlTests.cs | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index bf22f0a08a..5f7a36f2f9 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -504,7 +504,10 @@ namespace Avalonia.Controls result = container.GetControl(direction, c, wrap); from = from ?? result; - if (result?.Focusable == true) + if (result != null && + result.Focusable && + result.IsEffectivelyEnabled && + result.IsEffectivelyVisible) { return result; } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index 696c0dbf46..004cf009fc 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -1202,6 +1202,28 @@ namespace Avalonia.Controls.UnitTests.Primitives target.MoveSelection(NavigationDirection.Next, true); } + [Fact] + public void MoveSelection_Does_Select_Disabled_Controls() + { + // Issue #3426. + var target = new TestSelector + { + Template = Template(), + Items = new[] + { + new ListBoxItem(), + new ListBoxItem { IsEnabled = false }, + }, + SelectedIndex = 0, + }; + + target.Measure(new Size(100, 100)); + target.Arrange(new Rect(0, 0, 100, 100)); + target.MoveSelection(NavigationDirection.Next, true); + + Assert.Equal(0, target.SelectedIndex); + } + [Fact] public void Pre_Selecting_Item_Should_Set_Selection_After_It_Was_Added_When_AlwaysSelected() { From ff868c8e1e19dd59617c2c75b3adac252e449db7 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 12 Feb 2020 18:55:23 +0100 Subject: [PATCH 05/11] Merge pull request #3558 from AvaloniaUI/fixes/3365-icon-null Allow assigning null to Window.Icon. --- src/Avalonia.Controls/Window.cs | 2 +- src/Avalonia.X11/X11Window.cs | 17 ++++++++++++----- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index f66a248aaf..0c37858223 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -129,7 +129,7 @@ namespace Avalonia.Controls ShowInTaskbarProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue)); - IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); + IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue)?.PlatformImpl)); CanResizeProperty.Changed.AddClassHandler((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue)); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 81d8424f76..5a01d86de4 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -977,11 +977,18 @@ namespace Avalonia.X11 public void SetIcon(IWindowIconImpl icon) { - var data = ((X11IconData)icon).Data; - fixed (void* pdata = data) - XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON, - new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace, - pdata, data.Length); + if (icon != null) + { + var data = ((X11IconData)icon).Data; + fixed (void* pdata = data) + XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON, + new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace, + pdata, data.Length); + } + else + { + XDeleteProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON); + } } public void ShowTaskbarIcon(bool value) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 4d936cc871..1594a1f467 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -926,7 +926,7 @@ namespace Avalonia.Win32 public void SetIcon(IWindowIconImpl icon) { var impl = (IconImpl)icon; - var hIcon = impl.HIcon; + var hIcon = impl?.HIcon ?? IntPtr.Zero; UnmanagedMethods.PostMessage(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_SETICON, new IntPtr((int)UnmanagedMethods.Icons.ICON_BIG), hIcon); } From bebe0ca88e0f65cc612c4da8e8cc191a3adf061e Mon Sep 17 00:00:00 2001 From: Jumar Macato <16554748+jmacato@users.noreply.github.com> Date: Mon, 17 Feb 2020 01:16:03 +0800 Subject: [PATCH 06/11] Merge pull request #3581 from AvaloniaUI/fixes/3544-osx-window-close-crash Fix: dont crash when closing window on OSX. --- src/Avalonia.Native/WindowImplBase.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 64cea1c430..331f083e8b 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -162,9 +162,12 @@ namespace Avalonia.Native void IAvnWindowBaseEvents.Resized(AvnSize size) { - var s = new Size(size.Width, size.Height); - _parent._savedLogicalSize = s; - _parent.Resized?.Invoke(s); + if (_parent._native != null) + { + var s = new Size(size.Width, size.Height); + _parent._savedLogicalSize = s; + _parent.Resized?.Invoke(s); + } } void IAvnWindowBaseEvents.PositionChanged(AvnPoint position) @@ -317,7 +320,7 @@ namespace Avalonia.Native _native.SetTopMost(value); } - public double Scaling => _native.GetScaling(); + public double Scaling => _native?.GetScaling() ?? 1; public Action Deactivated { get; set; } public Action Activated { get; set; } From fc3278d171e6bd76b05ec9ef994181faf02ef66b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 12 Feb 2020 09:17:33 +0100 Subject: [PATCH 07/11] Merge pull request #3553 from AvaloniaUI/fixes/3550-menu-sizing Prevent reentrancy in LayoutManager.ExecuteInitialLayoutPass --- src/Avalonia.Layout/LayoutManager.cs | 12 +++++-- .../LayoutManagerTests.cs | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Layout/LayoutManager.cs b/src/Avalonia.Layout/LayoutManager.cs index 855f123748..917f5408d9 100644 --- a/src/Avalonia.Layout/LayoutManager.cs +++ b/src/Avalonia.Layout/LayoutManager.cs @@ -126,8 +126,16 @@ namespace Avalonia.Layout /// public void ExecuteInitialLayoutPass(ILayoutRoot root) { - Measure(root); - Arrange(root); + try + { + _running = true; + Measure(root); + Arrange(root); + } + finally + { + _running = false; + } // Running the initial layout pass may have caused some control to be invalidated // so run a full layout pass now (this usually due to scrollbars; its not known diff --git a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs index 3f20c9a76a..0165b91844 100644 --- a/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs +++ b/tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs @@ -374,5 +374,38 @@ namespace Avalonia.Layout.UnitTests Assert.True(control.Measured); Assert.True(control.IsMeasureValid); } + + [Fact] + public void Calling_ExecuteLayoutPass_From_ExecuteInitialLayoutPass_Does_Not_Break_Measure() + { + // Test for issue #3550. + var control = new LayoutTestControl(); + var root = new LayoutTestRoot { Child = control }; + var count = 0; + + root.LayoutManager.ExecuteInitialLayoutPass(root); + control.Measured = false; + + control.DoMeasureOverride = (l, s) => + { + if (count++ == 0) + { + control.InvalidateMeasure(); + root.LayoutManager.ExecuteLayoutPass(); + return new Size(100, 100); + } + else + { + return new Size(200, 200); + } + }; + + root.InvalidateMeasure(); + control.InvalidateMeasure(); + root.LayoutManager.ExecuteInitialLayoutPass(root); + + Assert.Equal(new Size(200, 200), control.Bounds.Size); + Assert.Equal(new Size(200, 200), control.DesiredSize); + } } } From 4f84e0741801c2c7a2b3fc5d545a536f3eee6a5c Mon Sep 17 00:00:00 2001 From: Jumar Macato <16554748+jmacato@users.noreply.github.com> Date: Fri, 14 Feb 2020 17:39:14 +0800 Subject: [PATCH 08/11] Merge pull request #3570 from AvaloniaUI/fixes/3569-window-sizing Fix window sizing --- src/Avalonia.Controls/Window.cs | 2 +- .../WindowTests.cs | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 0c37858223..6554237b3a 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -529,7 +529,7 @@ namespace Avalonia.Controls { var sizeToContent = SizeToContent; var clientSize = ClientSize; - Size constraint = clientSize; + var constraint = availableSize; if ((sizeToContent & SizeToContent.Width) != 0) { diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index 0508edd92f..81699b075c 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -341,11 +341,62 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Child_Should_Be_Measured_With_Width_And_Height_If_SizeToContent_Is_Manual() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var child = new ChildControl(); + var target = new Window + { + Width = 100, + Height = 50, + SizeToContent = SizeToContent.Manual, + Content = child + }; + + target.Show(); + + Assert.Equal(new Size(100, 50), child.MeasureSize); + } + } + + [Fact] + public void Child_Should_Be_Measured_With_Infinity_If_SizeToContent_Is_WidthAndHeight() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var child = new ChildControl(); + var target = new Window + { + Width = 100, + Height = 50, + SizeToContent = SizeToContent.WidthAndHeight, + Content = child + }; + + target.Show(); + + Assert.Equal(Size.Infinity, child.MeasureSize); + } + } + private IWindowImpl CreateImpl(Mock renderer) { return Mock.Of(x => x.Scaling == 1 && x.CreateRenderer(It.IsAny()) == renderer.Object); } + + private class ChildControl : Control + { + public Size MeasureSize { get; private set; } + + protected override Size MeasureOverride(Size availableSize) + { + MeasureSize = availableSize; + return base.MeasureOverride(availableSize); + } + } } } From c030e8a980a43a68fda8c1a7dca633826d414e3b Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 20 Feb 2020 14:53:47 +0300 Subject: [PATCH 09/11] Fix inertial scrolling --- src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs b/src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs index 4f3c7c0bba..a582fae8b5 100644 --- a/src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs +++ b/src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs @@ -148,6 +148,7 @@ namespace Avalonia.Input.GestureRecognizers EndGesture(); else { + _tracking = null; var savedGestureId = _gestureId; var st = Stopwatch.StartNew(); var lastTime = TimeSpan.Zero; From a819eff46cee0ca08050b472ab28e7dc95aba777 Mon Sep 17 00:00:00 2001 From: Jumar Macato <16554748+jmacato@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:14:40 +0800 Subject: [PATCH 10/11] Merge pull request #3585 from AvaloniaUI/fixes/3584-convert-timespan Use TypeConverters in TypeUtilities.TryConvert --- src/Avalonia.Base/Utilities/TypeUtilities.cs | 9 +++++++++ .../Data/DefaultValueConverterTests.cs | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs index d85eb4cd76..39736ab389 100644 --- a/src/Avalonia.Base/Utilities/TypeUtilities.cs +++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.ComponentModel; using System.Globalization; using System.Linq; using System.Reflection; @@ -188,6 +189,14 @@ namespace Avalonia.Utilities } } + var typeConverter = TypeDescriptor.GetConverter(to); + + if (typeConverter.CanConvertFrom(from) == true) + { + result = typeConverter.ConvertFrom(null, culture, value); + return true; + } + var cast = FindTypeConversionOperatorMethod(from, to, OperatorType.Implicit | OperatorType.Explicit); if (cast != null) diff --git a/tests/Avalonia.Base.UnitTests/Data/DefaultValueConverterTests.cs b/tests/Avalonia.Base.UnitTests/Data/DefaultValueConverterTests.cs index ecf559951a..f29dabb6bf 100644 --- a/tests/Avalonia.Base.UnitTests/Data/DefaultValueConverterTests.cs +++ b/tests/Avalonia.Base.UnitTests/Data/DefaultValueConverterTests.cs @@ -50,6 +50,18 @@ namespace Avalonia.Base.UnitTests.Data.Converters Assert.Equal(TestEnum.Bar, result); } + [Fact] + public void Can_Convert_String_To_TimeSpan() + { + var result = DefaultValueConverter.Instance.Convert( + "00:00:10", + typeof(TimeSpan), + null, + CultureInfo.InvariantCulture); + + Assert.Equal(TimeSpan.FromSeconds(10), result); + } + [Fact] public void Can_Convert_Int_To_Enum() { From b996d06522490f3329249f2d0efb284a46240a69 Mon Sep 17 00:00:00 2001 From: danwalmsley Date: Wed, 26 Feb 2020 07:57:28 -0300 Subject: [PATCH 11/11] Merge pull request #3613 from AvaloniaUI/osx-potential-deadlock-in-user-code OSX - fix potential deadlock with user code --- native/Avalonia.Native/src/OSX/platformthreading.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/platformthreading.mm b/native/Avalonia.Native/src/OSX/platformthreading.mm index e7abedae51..ed00f8c5e1 100644 --- a/native/Avalonia.Native/src/OSX/platformthreading.mm +++ b/native/Avalonia.Native/src/OSX/platformthreading.mm @@ -157,11 +157,14 @@ NSArray* _modes; -(void) perform { + ComPtr cb; @synchronized (self) { _signaled = false; - if(_parent != NULL && _parent->SignaledCallback != NULL) - _parent->SignaledCallback->Signaled(0, false); + if(_parent != NULL) + cb = _parent->SignaledCallback; } + if(cb != nullptr) + cb->Signaled(0, false); } -(void) setParent:(PlatformThreadingInterface *)parent