diff --git a/.editorconfig b/.editorconfig index b4c617e0bb..9ae52b8bbd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -139,10 +139,12 @@ dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomme # CA1802: Use literals where appropriate dotnet_diagnostic.CA1802.severity = warning -# CA1825: Avoid zero-length array allocations -dotnet_diagnostic.CA1825.severity = warning +# CA1820: Test for empty strings using string length +dotnet_diagnostic.CA1820.severity = warning # CA1821: Remove empty finalizers dotnet_diagnostic.CA1821.severity = warning +# CA1825: Avoid zero-length array allocations +dotnet_diagnostic.CA1825.severity = warning #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters dotnet_diagnostic.CA1847.severity = warning diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c5a719ce90..df070c35cf 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ +github: avaloniaui open_collective: avalonia diff --git a/src/Avalonia.Base/Input/DragDrop.cs b/src/Avalonia.Base/Input/DragDrop.cs index 723d577964..fe75f678e1 100644 --- a/src/Avalonia.Base/Input/DragDrop.cs +++ b/src/Avalonia.Base/Input/DragDrop.cs @@ -13,7 +13,7 @@ namespace Avalonia.Input /// /// Event which is raised, when a drag-and-drop operation leaves the element. /// - public static readonly RoutedEvent DragLeaveEvent = RoutedEvent.Register("DragLeave", RoutingStrategies.Bubble, typeof(DragDrop)); + public static readonly RoutedEvent DragLeaveEvent = RoutedEvent.Register("DragLeave", RoutingStrategies.Bubble, typeof(DragDrop)); /// /// Event which is raised, when a drag-and-drop operation is updated while over the element. /// diff --git a/src/Avalonia.Base/Input/DragDropDevice.cs b/src/Avalonia.Base/Input/DragDropDevice.cs index 30a08eda17..3c91856dcd 100644 --- a/src/Avalonia.Base/Input/DragDropDevice.cs +++ b/src/Avalonia.Base/Input/DragDropDevice.cs @@ -54,7 +54,7 @@ namespace Avalonia.Input try { if (_lastTarget != null) - _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); + RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragLeaveEvent, effects, data, modifiers); return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } finally @@ -63,13 +63,13 @@ namespace Avalonia.Input } } - private void DragLeave(IInputElement inputRoot) + private void DragLeave(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, KeyModifiers modifiers) { if (_lastTarget == null) return; try { - _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); + RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragLeaveEvent, effects, data, modifiers); } finally { @@ -106,7 +106,7 @@ namespace Avalonia.Input e.Effects = DragOver(e.Root, e.Location, e.Data, e.Effects, e.KeyModifiers); break; case RawDragEventType.DragLeave: - DragLeave(e.Root); + DragLeave(e.Root, e.Location, e.Data, e.Effects, e.KeyModifiers); break; case RawDragEventType.Drop: e.Effects = Drop(e.Root, e.Location, e.Data, e.Effects, e.KeyModifiers); diff --git a/src/Avalonia.Base/Media/Color.cs b/src/Avalonia.Base/Media/Color.cs index cb90404f6d..5470a735b3 100644 --- a/src/Avalonia.Base/Media/Color.cs +++ b/src/Avalonia.Base/Media/Color.cs @@ -9,6 +9,7 @@ using System; using System.Globalization; #if !BUILDTASK using Avalonia.Animation.Animators; +using static Avalonia.Utilities.SpanHelpers; #endif namespace Avalonia.Media @@ -295,9 +296,7 @@ namespace Avalonia.Media return false; } - // TODO: (netstandard 2.1) Can use allocation free parsing. - if (!uint.TryParse(input.ToString(), NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out var parsed)) + if (!input.TryParseUInt(NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var parsed)) { return false; } @@ -382,9 +381,9 @@ namespace Avalonia.Media if (components.Length == 3) // RGB { - if (InternalTryParseByte(components[0], out byte red) && - InternalTryParseByte(components[1], out byte green) && - InternalTryParseByte(components[2], out byte blue)) + if (InternalTryParseByte(components[0].AsSpan(), out byte red) && + InternalTryParseByte(components[1].AsSpan(), out byte green) && + InternalTryParseByte(components[2].AsSpan(), out byte blue)) { color = new Color(0xFF, red, green, blue); return true; @@ -392,10 +391,10 @@ namespace Avalonia.Media } else if (components.Length == 4) // RGBA { - if (InternalTryParseByte(components[0], out byte red) && - InternalTryParseByte(components[1], out byte green) && - InternalTryParseByte(components[2], out byte blue) && - InternalTryParseDouble(components[3], out double alpha)) + if (InternalTryParseByte(components[0].AsSpan(), out byte red) && + InternalTryParseByte(components[1].AsSpan(), out byte green) && + InternalTryParseByte(components[2].AsSpan(), out byte blue) && + InternalTryParseDouble(components[3].AsSpan(), out double alpha)) { color = new Color((byte)Math.Round(alpha * 255.0), red, green, blue); return true; @@ -403,17 +402,14 @@ namespace Avalonia.Media } // Local function to specially parse a byte value with an optional percentage sign - bool InternalTryParseByte(string inString, out byte outByte) + bool InternalTryParseByte(ReadOnlySpan inString, out byte outByte) { // The percent sign, if it exists, must be at the end of the number - int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); + int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal); if (percentIndex >= 0) { - var result = double.TryParse( - inString.Substring(0, percentIndex), - NumberStyles.Number, - CultureInfo.InvariantCulture, + var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double percentage); outByte = (byte)Math.Round((percentage / 100.0) * 255.0); @@ -421,37 +417,28 @@ namespace Avalonia.Media } else { - return byte.TryParse( - inString, - NumberStyles.Number, - CultureInfo.InvariantCulture, + return inString.TryParseByte(NumberStyles.Number, CultureInfo.InvariantCulture, out outByte); } } // Local function to specially parse a double value with an optional percentage sign - bool InternalTryParseDouble(string inString, out double outDouble) + bool InternalTryParseDouble(ReadOnlySpan inString, out double outDouble) { // The percent sign, if it exists, must be at the end of the number - int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); + int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal); if (percentIndex >= 0) { - var result = double.TryParse( - inString.Substring(0, percentIndex), - NumberStyles.Number, - CultureInfo.InvariantCulture, - out double percentage); + var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, + out double percentage); outDouble = percentage / 100.0; return result; } else { - return double.TryParse( - inString, - NumberStyles.Number, - CultureInfo.InvariantCulture, + return inString.TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out outDouble); } } diff --git a/src/Avalonia.Base/Media/HslColor.cs b/src/Avalonia.Base/Media/HslColor.cs index 485bb1db16..425a3138c3 100644 --- a/src/Avalonia.Base/Media/HslColor.cs +++ b/src/Avalonia.Base/Media/HslColor.cs @@ -302,9 +302,9 @@ namespace Avalonia.Media if (components.Length == 3) // HSL { - if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && - TryInternalParse(components[1], out double saturation) && - TryInternalParse(components[2], out double lightness)) + if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && + TryInternalParse(components[1].AsSpan(), out double saturation) && + TryInternalParse(components[2].AsSpan(), out double lightness)) { hslColor = new HslColor(1.0, hue, saturation, lightness); return true; @@ -312,10 +312,10 @@ namespace Avalonia.Media } else if (components.Length == 4) // HSLA { - if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && - TryInternalParse(components[1], out double saturation) && - TryInternalParse(components[2], out double lightness) && - TryInternalParse(components[3], out double alpha)) + if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && + TryInternalParse(components[1].AsSpan(), out double saturation) && + TryInternalParse(components[2].AsSpan(), out double lightness) && + TryInternalParse(components[3].AsSpan(), out double alpha)) { hslColor = new HslColor(alpha, hue, saturation, lightness); return true; @@ -323,28 +323,22 @@ namespace Avalonia.Media } // Local function to specially parse a double value with an optional percentage sign - bool TryInternalParse(string inString, out double outDouble) + bool TryInternalParse(ReadOnlySpan inString, out double outDouble) { // The percent sign, if it exists, must be at the end of the number - int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); + int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal); if (percentIndex >= 0) { - var result = double.TryParse( - inString.Substring(0, percentIndex), - NumberStyles.Number, - CultureInfo.InvariantCulture, - out double percentage); + var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, + out double percentage); outDouble = percentage / 100.0; return result; } else { - return double.TryParse( - inString, - NumberStyles.Number, - CultureInfo.InvariantCulture, + return inString.TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out outDouble); } } diff --git a/src/Avalonia.Base/Media/HsvColor.cs b/src/Avalonia.Base/Media/HsvColor.cs index 512e57ae07..9f95b31518 100644 --- a/src/Avalonia.Base/Media/HsvColor.cs +++ b/src/Avalonia.Base/Media/HsvColor.cs @@ -302,9 +302,9 @@ namespace Avalonia.Media if (components.Length == 3) // HSV { - if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && - TryInternalParse(components[1], out double saturation) && - TryInternalParse(components[2], out double value)) + if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && + TryInternalParse(components[1].AsSpan(), out double saturation) && + TryInternalParse(components[2].AsSpan(), out double value)) { hsvColor = new HsvColor(1.0, hue, saturation, value); return true; @@ -312,10 +312,10 @@ namespace Avalonia.Media } else if (components.Length == 4) // HSVA { - if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && - TryInternalParse(components[1], out double saturation) && - TryInternalParse(components[2], out double value) && - TryInternalParse(components[3], out double alpha)) + if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && + TryInternalParse(components[1].AsSpan(), out double saturation) && + TryInternalParse(components[2].AsSpan(), out double value) && + TryInternalParse(components[3].AsSpan(), out double alpha)) { hsvColor = new HsvColor(alpha, hue, saturation, value); return true; @@ -323,28 +323,22 @@ namespace Avalonia.Media } // Local function to specially parse a double value with an optional percentage sign - bool TryInternalParse(string inString, out double outDouble) + bool TryInternalParse(ReadOnlySpan inString, out double outDouble) { // The percent sign, if it exists, must be at the end of the number - int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); + int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal); if (percentIndex >= 0) { - var result = double.TryParse( - inString.Substring(0, percentIndex), - NumberStyles.Number, - CultureInfo.InvariantCulture, - out double percentage); + var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, + out double percentage); outDouble = percentage / 100.0; return result; } else { - return double.TryParse( - inString, - NumberStyles.Number, - CultureInfo.InvariantCulture, + return inString.TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out outDouble); } } diff --git a/src/Avalonia.Base/Utilities/SpanHelpers.cs b/src/Avalonia.Base/Utilities/SpanHelpers.cs new file mode 100644 index 0000000000..9a5dce9798 --- /dev/null +++ b/src/Avalonia.Base/Utilities/SpanHelpers.cs @@ -0,0 +1,49 @@ +using System; +using System.Globalization; +using System.Runtime.CompilerServices; + +namespace Avalonia.Utilities +{ + public static class SpanHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryParseUInt(this ReadOnlySpan span, NumberStyles style, IFormatProvider provider, out uint value) + { +#if NETSTANDARD2_0 + return uint.TryParse(span.ToString(), style, provider, out value); +#else + return uint.TryParse(span, style, provider, out value); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryParseInt(this ReadOnlySpan span, out int value) + { +#if NETSTANDARD2_0 + return int.TryParse(span.ToString(), out value); +#else + return int.TryParse(span, out value); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryParseDouble(this ReadOnlySpan span, NumberStyles style, IFormatProvider provider, out double value) + { +#if NETSTANDARD2_0 + return double.TryParse(span.ToString(), style, provider, out value); +#else + return double.TryParse(span, style, provider, out value); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryParseByte(this ReadOnlySpan span, NumberStyles style, IFormatProvider provider, out byte value) + { +#if NETSTANDARD2_0 + return byte.TryParse(span.ToString(), style, provider, out value); +#else + return byte.TryParse(span, style, provider, out value); +#endif + } + } +} diff --git a/src/Avalonia.Build.Tasks/SpanCompat.cs b/src/Avalonia.Build.Tasks/SpanCompat.cs index 25f8d0175a..be59ff8b6c 100644 --- a/src/Avalonia.Build.Tasks/SpanCompat.cs +++ b/src/Avalonia.Build.Tasks/SpanCompat.cs @@ -1,4 +1,7 @@ #if !NETCOREAPP3_1_OR_GREATER +using System.Globalization; +using System.Runtime.CompilerServices; + namespace System { // This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory @@ -9,6 +12,8 @@ namespace System private int _length; public int Length => _length; + public static implicit operator ReadOnlySpan(string s) => new ReadOnlySpan(s); + public ReadOnlySpan(string s) : this(s, 0, s.Length) { @@ -63,8 +68,75 @@ namespace System return Slice(start); } + public ReadOnlySpan TrimEnd() + { + int end = Length - 1; + for (; end >= 0; end--) + { + if (!char.IsWhiteSpace(this[end])) + { + break; + } + } + return Slice(0, end + 1); + } + + public ReadOnlySpan Trim() + { + return TrimStart().TrimEnd(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryParseUInt(NumberStyles style, IFormatProvider provider, out uint value) + { + return uint.TryParse(ToString(), style, provider, out value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryParseInt(out int value) + { + return int.TryParse(ToString(), out value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryParseDouble(NumberStyles style, IFormatProvider provider, out double value) + { + return double.TryParse(ToString(), style, provider, out value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryParseByte(NumberStyles style, IFormatProvider provider, out byte value) + { + return byte.TryParse(ToString(), style, provider, out value); + } + public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length); + internal int IndexOf(ReadOnlySpan v, StringComparison ordinal, int start = 0) + { + if(Length == 0 || v.IsEmpty) + { + return -1; + } + + for (var c = start; c < _length; c++) + { + if (this[c] == v[0]) + { + for(var i = 0; i < v.Length; i++) + { + if (this[c + i] != v[i]) + { + break; + } + } + return c; + } + } + + return -1; + } + public static implicit operator ReadOnlySpan(char[] arr) => new ReadOnlySpan(new string(arr)); } diff --git a/src/Avalonia.Controls.DataGrid/DataGridValueConverter.cs b/src/Avalonia.Controls.DataGrid/DataGridValueConverter.cs index 82670bf989..6144679b60 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridValueConverter.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridValueConverter.cs @@ -28,8 +28,8 @@ namespace Avalonia.Controls { if (targetType != null && targetType.IsNullableType()) { - String strValue = value as String; - if (strValue == String.Empty) + var strValue = value as string; + if (string.IsNullOrEmpty(strValue)) { return null; } diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 6b7101cd49..1dfad7dcc5 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -210,9 +210,9 @@ namespace Avalonia.Controls { var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies() from attribute in assembly.GetCustomAttributes() - where attribute.ForWindowingSubsystem == "" + where string.IsNullOrEmpty(attribute.ForWindowingSubsystem) || attribute.ForWindowingSubsystem == WindowingSubsystemName - where attribute.ForRenderingSubsystem == "" + where string.IsNullOrEmpty(attribute.ForRenderingSubsystem) || attribute.ForRenderingSubsystem == RenderingSubsystemName group attribute by attribute.Name into exports select (from export in exports diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index 228b9ae205..a7a6881fe5 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -99,7 +99,7 @@ namespace Avalonia.Controls get => _clockIdentifier; set { - if (!(string.IsNullOrEmpty(value) || value == "" || value == "12HourClock" || value == "24HourClock")) + if (!(string.IsNullOrEmpty(value) || value == "12HourClock" || value == "24HourClock")) throw new ArgumentException("Invalid ClockIdentifier"); SetAndRaise(ClockIdentifierProperty, ref _clockIdentifier, value); SetGrid(); diff --git a/src/Avalonia.Controls/DefinitionBase.cs b/src/Avalonia.Controls/DefinitionBase.cs index eb09ff397a..64a02ccb46 100644 --- a/src/Avalonia.Controls/DefinitionBase.cs +++ b/src/Avalonia.Controls/DefinitionBase.cs @@ -366,7 +366,7 @@ namespace Avalonia.Controls string id = (string)value; - if (id != string.Empty) + if (!string.IsNullOrEmpty(id)) { int i = -1; while (++i < id.Length) diff --git a/src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs b/src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs index 9a872df960..6bfae536c9 100644 --- a/src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs +++ b/src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs @@ -72,7 +72,7 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport while (true) { line = await ReadLineAsync(); - if (line == "") + if (string.IsNullOrEmpty(line)) break; sp = line.Split(new[] {':'}, 2); headers[sp[0]] = sp[1].TrimStart(); diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index b16ee84b4d..fe694b5730 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -19,7 +19,8 @@ - + + diff --git a/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj b/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj index 599d95e67a..e784bda105 100644 --- a/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj +++ b/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj @@ -4,6 +4,7 @@ true + false all diff --git a/src/Avalonia.MicroCom/CallbackBase.cs b/src/Avalonia.MicroCom/CallbackBase.cs index 6783ebe3dc..49d589a5fc 100644 --- a/src/Avalonia.MicroCom/CallbackBase.cs +++ b/src/Avalonia.MicroCom/CallbackBase.cs @@ -1,4 +1,6 @@ -namespace Avalonia.MicroCom +using MicroCom.Runtime; + +namespace Avalonia.MicroCom { public abstract class CallbackBase : IUnknown, IMicroComShadowContainer { diff --git a/src/Avalonia.MicroCom/IMicroComExceptionCallback.cs b/src/Avalonia.MicroCom/IMicroComExceptionCallback.cs deleted file mode 100644 index 08f20339ec..0000000000 --- a/src/Avalonia.MicroCom/IMicroComExceptionCallback.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Avalonia.MicroCom -{ - public interface IMicroComExceptionCallback - { - void RaiseException(Exception e); - } -} diff --git a/src/Avalonia.MicroCom/IMicroComShadowContainer.cs b/src/Avalonia.MicroCom/IMicroComShadowContainer.cs deleted file mode 100644 index a33d3a9811..0000000000 --- a/src/Avalonia.MicroCom/IMicroComShadowContainer.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Avalonia.MicroCom -{ - public interface IMicroComShadowContainer - { - MicroComShadow Shadow { get; set; } - void OnReferencedFromNative(); - void OnUnreferencedFromNative(); - } -} diff --git a/src/Avalonia.MicroCom/IUnknown.cs b/src/Avalonia.MicroCom/IUnknown.cs deleted file mode 100644 index 0dc4106423..0000000000 --- a/src/Avalonia.MicroCom/IUnknown.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Avalonia.MicroCom -{ - public interface IUnknown : IDisposable - { - } -} diff --git a/src/Avalonia.MicroCom/LocalInterop.cs b/src/Avalonia.MicroCom/LocalInterop.cs deleted file mode 100644 index 785f4e03a5..0000000000 --- a/src/Avalonia.MicroCom/LocalInterop.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Avalonia.MicroCom -{ - unsafe class LocalInterop - { - public static unsafe void CalliStdCallvoid(void* thisObject, void* methodPtr) - { - throw null; - } - - public static unsafe int CalliStdCallint(void* thisObject, Guid* guid, IntPtr* ppv, void* methodPtr) - { - throw null; - } - } -} diff --git a/src/Avalonia.MicroCom/MicroComProxyBase.cs b/src/Avalonia.MicroCom/MicroComProxyBase.cs deleted file mode 100644 index fe8a2bf9cf..0000000000 --- a/src/Avalonia.MicroCom/MicroComProxyBase.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Avalonia.MicroCom -{ - public unsafe class MicroComProxyBase : CriticalFinalizerObject, IUnknown - { - private IntPtr _nativePointer; - private bool _ownsHandle; - private SynchronizationContext _synchronizationContext; - - public IntPtr NativePointer - { - get - { - if (_nativePointer == IntPtr.Zero) - throw new ObjectDisposedException(this.GetType().FullName); - return _nativePointer; - } - } - - public void*** PPV => (void***)NativePointer; - - public MicroComProxyBase(IntPtr nativePointer, bool ownsHandle) - { - _nativePointer = nativePointer; - _ownsHandle = ownsHandle; - _synchronizationContext = SynchronizationContext.Current; - if(!_ownsHandle) - GC.SuppressFinalize(this); - } - - protected virtual int VTableSize => 3; - - public void AddRef() - { - LocalInterop.CalliStdCallvoid(PPV, (*PPV)[1]); - } - - public void Release() - { - LocalInterop.CalliStdCallvoid(PPV, (*PPV)[2]); - } - - public int QueryInterface(Guid guid, out IntPtr ppv) - { - IntPtr r = default; - var rv = LocalInterop.CalliStdCallint(PPV, &guid, &r, (*PPV)[0]); - ppv = r; - return rv; - } - - public T QueryInterface() where T : IUnknown - { - var guid = MicroComRuntime.GetGuidFor(typeof(T)); - var rv = QueryInterface(guid, out var ppv); - if (rv == 0) - return (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true); - throw new COMException("QueryInterface failed", rv); - } - - public bool IsDisposed => _nativePointer == IntPtr.Zero; - - protected virtual void Dispose(bool disposing) - { - if(_nativePointer == IntPtr.Zero) - return; - if (_ownsHandle) - { - Release(); - _ownsHandle = false; - } - _nativePointer = IntPtr.Zero; - GC.SuppressFinalize(this); - } - - public void Dispose() => Dispose(true); - - public bool OwnsHandle => _ownsHandle; - - public void EnsureOwned() - { - if (!_ownsHandle) - { - GC.ReRegisterForFinalize(true); - AddRef(); - _ownsHandle = true; - } - } - - private static readonly SendOrPostCallback _disposeDelegate = DisposeOnContext; - - private static void DisposeOnContext(object state) - { - (state as MicroComProxyBase)?.Dispose(false); - } - - ~MicroComProxyBase() - { - if(!_ownsHandle) - return; - if (_synchronizationContext == null) - Dispose(); - else - _synchronizationContext.Post(_disposeDelegate, this); - } - } -} diff --git a/src/Avalonia.MicroCom/MicroComRuntime.cs b/src/Avalonia.MicroCom/MicroComRuntime.cs deleted file mode 100644 index b9a56a69ba..0000000000 --- a/src/Avalonia.MicroCom/MicroComRuntime.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Runtime.InteropServices; - -namespace Avalonia.MicroCom -{ - public static unsafe class MicroComRuntime - { - private static ConcurrentDictionary _vtables = new ConcurrentDictionary(); - - private static ConcurrentDictionary> _factories = - new ConcurrentDictionary>(); - private static ConcurrentDictionary _guids = new ConcurrentDictionary(); - private static ConcurrentDictionary _guidsToTypes = new ConcurrentDictionary(); - - internal static readonly Guid ManagedObjectInterfaceGuid = Guid.Parse("cd7687c0-a9c2-4563-b08e-a399df50c633"); - - static MicroComRuntime() - { - Register(typeof(IUnknown), new Guid("00000000-0000-0000-C000-000000000046"), - (ppv, owns) => new MicroComProxyBase(ppv, owns)); - RegisterVTable(typeof(IUnknown), MicroComVtblBase.Vtable); - } - - public static void RegisterVTable(Type t, IntPtr vtable) - { - _vtables[t] = vtable; - } - - public static void Register(Type t, Guid guid, Func proxyFactory) - { - _factories[t] = proxyFactory; - _guids[t] = guid; - _guidsToTypes[guid] = t; - } - - public static Guid GetGuidFor(Type type) => _guids[type]; - - public static T CreateProxyFor(void* pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle); - public static T CreateProxyFor(IntPtr pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), pObject, ownsHandle); - - public static T CreateProxyOrNullFor(void* pObject, bool ownsHandle) where T : class => - pObject == null ? null : (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle); - - public static T CreateProxyOrNullFor(IntPtr pObject, bool ownsHandle) where T : class => - pObject == IntPtr.Zero ? null : (T)CreateProxyFor(typeof(T), pObject, ownsHandle); - - public static object CreateProxyFor(Type type, IntPtr pObject, bool ownsHandle) => _factories[type](pObject, ownsHandle); - - public static IntPtr GetNativeIntPtr(this T obj, bool owned = false) where T : IUnknown - => new IntPtr(GetNativePointer(obj, owned)); - public static void* GetNativePointer(T obj, bool owned = false) where T : IUnknown - { - if (obj == null) - return null; - if (obj is MicroComProxyBase proxy) - { - if(owned) - proxy.AddRef(); - return (void*)proxy.NativePointer; - } - - if (obj is IMicroComShadowContainer container) - { - container.Shadow ??= new MicroComShadow(container); - void* ptr = null; - var res = container.Shadow.GetOrCreateNativePointer(typeof(T), &ptr); - if (res != 0) - throw new COMException( - "Unable to create native callable wrapper for type " + typeof(T) + " for instance of type " + - obj.GetType(), - res); - if (owned) - container.Shadow.AddRef((Ccw*)ptr); - return ptr; - } - throw new ArgumentException("Unable to get a native pointer for " + obj); - } - - public static object GetObjectFromCcw(IntPtr ccw) - { - var ptr = (Ccw*)ccw; - var shadow = (MicroComShadow)GCHandle.FromIntPtr(ptr->GcShadowHandle).Target; - return shadow.Target; - } - - public static bool IsComWrapper(IUnknown obj) => obj is MicroComProxyBase; - - public static object TryUnwrapManagedObject(IUnknown obj) - { - if (obj is not MicroComProxyBase proxy) - return null; - if (proxy.QueryInterface(ManagedObjectInterfaceGuid, out _) != 0) - return null; - // Successful QueryInterface always increments ref counter - proxy.Release(); - return GetObjectFromCcw(proxy.NativePointer); - } - - public static bool TryGetTypeForGuid(Guid guid, out Type t) => _guidsToTypes.TryGetValue(guid, out t); - - public static bool GetVtableFor(Type type, out IntPtr ptr) => _vtables.TryGetValue(type, out ptr); - - public static void UnhandledException(object target, Exception e) - { - if (target is IMicroComExceptionCallback cb) - { - try - { - cb.RaiseException(e); - } - catch - { - // We've tried - } - } - - } - - public static T CloneReference(this T iface) where T : IUnknown - { - var proxy = (MicroComProxyBase)(object)iface; - var ownedPointer = GetNativePointer(iface, true); - return CreateProxyFor(ownedPointer, true); - } - - public static T QueryInterface(this IUnknown unknown) where T : IUnknown - { - var proxy = (MicroComProxyBase)unknown; - return proxy.QueryInterface(); - } - - public static void UnsafeAddRef(this IUnknown unknown) - { - ((MicroComProxyBase)unknown).AddRef(); - } - - public static void UnsafeRelease(this IUnknown unknown) - { - ((MicroComProxyBase)unknown).Release(); - } - } -} diff --git a/src/Avalonia.MicroCom/MicroComShadow.cs b/src/Avalonia.MicroCom/MicroComShadow.cs deleted file mode 100644 index 765ff3b9ad..0000000000 --- a/src/Avalonia.MicroCom/MicroComShadow.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Avalonia.MicroCom -{ - public unsafe class MicroComShadow : IDisposable - { - private readonly object _lock = new object(); - private readonly Dictionary _shadows = new Dictionary(); - private readonly Dictionary _backShadows = new Dictionary(); - private GCHandle? _handle; - private volatile int _refCount; - internal IMicroComShadowContainer Target { get; } - internal MicroComShadow(IMicroComShadowContainer target) - { - Target = target; - Target.Shadow = this; - } - - internal int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) - { - if (MicroComRuntime.TryGetTypeForGuid(*guid, out var type)) - return QueryInterface(type, ppv); - else if (*guid == MicroComRuntime.ManagedObjectInterfaceGuid) - { - ccw->RefCount++; - *ppv = ccw; - return 0; - } - else - return unchecked((int)0x80004002u); - } - - internal int QueryInterface(Type type, void** ppv) - { - if (!type.IsInstanceOfType(Target)) - return unchecked((int)0x80004002u); - - var rv = GetOrCreateNativePointer(type, ppv); - if (rv == 0) - AddRef((Ccw*)*ppv); - return rv; - } - - internal int GetOrCreateNativePointer(Type type, void** ppv) - { - if (!MicroComRuntime.GetVtableFor(type, out var vtable)) - return unchecked((int)0x80004002u); - lock (_lock) - { - - if (_shadows.TryGetValue(type, out var shadow)) - { - var targetCcw = (Ccw*)shadow; - AddRef(targetCcw); - *ppv = targetCcw; - return 0; - } - else - { - var intPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); - var targetCcw = (Ccw*)intPtr; - *targetCcw = default; - targetCcw->RefCount = 0; - targetCcw->VTable = vtable; - if (_handle == null) - _handle = GCHandle.Alloc(this); - targetCcw->GcShadowHandle = GCHandle.ToIntPtr(_handle.Value); - _shadows[type] = intPtr; - _backShadows[intPtr] = type; - *ppv = targetCcw; - - return 0; - } - } - } - - internal int AddRef(Ccw* ccw) - { - if (Interlocked.Increment(ref _refCount) == 1) - { - try - { - Target.OnReferencedFromNative(); - } - catch (Exception e) - { - MicroComRuntime.UnhandledException(Target, e); - } - } - - return Interlocked.Increment(ref ccw->RefCount); - } - - internal int Release(Ccw* ccw) - { - Interlocked.Decrement(ref _refCount); - var cnt = Interlocked.Decrement(ref ccw->RefCount); - if (cnt == 0) - return FreeCcw(ccw); - - return cnt; - } - - int FreeCcw(Ccw* ccw) - { - lock (_lock) - { - // Shadow got resurrected by a call to QueryInterface from another thread - if (ccw->RefCount != 0) - return ccw->RefCount; - - var intPtr = new IntPtr(ccw); - var type = _backShadows[intPtr]; - _backShadows.Remove(intPtr); - _shadows.Remove(type); - Marshal.FreeHGlobal(intPtr); - if (_shadows.Count == 0) - { - _handle?.Free(); - _handle = null; - try - { - Target.OnUnreferencedFromNative(); - } - catch(Exception e) - { - MicroComRuntime.UnhandledException(Target, e); - } - } - } - - return 0; - } - - /* - Needs to be called to support the following scenario: - 1) Object created - 2) Object passed to native code, shadow is created, CCW is created - 3) Native side has never called AddRef - - In that case the GC handle to the shadow object is still alive - */ - - public void Dispose() - { - lock (_lock) - { - List toRemove = null; - foreach (var kv in _backShadows) - { - var ccw = (Ccw*)kv.Key; - if (ccw->RefCount == 0) - { - toRemove ??= new List(); - toRemove.Add(kv.Key); - } - } - - if(toRemove != null) - foreach (var intPtr in toRemove) - FreeCcw((Ccw*)intPtr); - } - } - } - - [StructLayout(LayoutKind.Sequential)] - struct Ccw - { - public IntPtr VTable; - public IntPtr GcShadowHandle; - public volatile int RefCount; - public MicroComShadow GetShadow() => (MicroComShadow)GCHandle.FromIntPtr(GcShadowHandle).Target; - } -} diff --git a/src/Avalonia.MicroCom/MicroComVtblBase.cs b/src/Avalonia.MicroCom/MicroComVtblBase.cs deleted file mode 100644 index 7092f8131a..0000000000 --- a/src/Avalonia.MicroCom/MicroComVtblBase.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace Avalonia.MicroCom -{ - public unsafe class MicroComVtblBase - { - private List _methods = new List(); - [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] - private delegate int AddRefDelegate(Ccw* ccw); - - [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] - private delegate int QueryInterfaceDelegate(Ccw* ccw, Guid* guid, void** ppv); - - public static IntPtr Vtable { get; } = new MicroComVtblBase().CreateVTable(); - public MicroComVtblBase() - { - AddMethod((QueryInterfaceDelegate)QueryInterface); - AddMethod((AddRefDelegate)AddRef); - AddMethod((AddRefDelegate)Release); - } - - protected void AddMethod(void* f) - { - _methods.Add(new IntPtr(f)); - } - - protected void AddMethod(Delegate d) - { - GCHandle.Alloc(d); - _methods.Add(Marshal.GetFunctionPointerForDelegate(d)); - } - - protected unsafe IntPtr CreateVTable() - { - var ptr = (IntPtr*)Marshal.AllocHGlobal((IntPtr.Size + 1) * _methods.Count); - for (var c = 0; c < _methods.Count; c++) - ptr[c] = _methods[c]; - return new IntPtr(ptr); - } - - static int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) => ccw->GetShadow().QueryInterface(ccw, guid, ppv); - static int AddRef(Ccw* ccw) => ccw->GetShadow().AddRef(ccw); - static int Release(Ccw* ccw) => ccw->GetShadow().Release(ccw); - } -} diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 2001a2fcbc..4ceb1be340 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -6,7 +6,6 @@ true net6.0;netstandard2.0 true - Avalonia.MicroCom diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index b45fe5559b..532893884a 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -10,6 +10,7 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Composition; using JetBrains.Annotations; +using MicroCom.Runtime; namespace Avalonia.Native { diff --git a/src/Avalonia.Native/CallbackBase.cs b/src/Avalonia.Native/CallbackBase.cs index 56f9505cb4..2d875dbc0e 100644 --- a/src/Avalonia.Native/CallbackBase.cs +++ b/src/Avalonia.Native/CallbackBase.cs @@ -2,6 +2,7 @@ using System.Runtime.ExceptionServices; using Avalonia.MicroCom; using Avalonia.Platform; +using MicroCom.Runtime; namespace Avalonia.Native { diff --git a/src/Avalonia.Native/NativeControlHostImpl.cs b/src/Avalonia.Native/NativeControlHostImpl.cs index 2c9c1728d3..8a3488d95e 100644 --- a/src/Avalonia.Native/NativeControlHostImpl.cs +++ b/src/Avalonia.Native/NativeControlHostImpl.cs @@ -4,6 +4,7 @@ using Avalonia.MicroCom; using Avalonia.Native.Interop; using Avalonia.Platform; using Avalonia.VisualTree; +using MicroCom.Runtime; namespace Avalonia.Native { diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs index 23abd31b2c..3f0a6aeb67 100644 --- a/src/Avalonia.X11/X11Structs.cs +++ b/src/Avalonia.X11/X11Structs.cs @@ -661,7 +661,7 @@ namespace Avalonia.X11 { Type type = ev.GetType (); FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance); for (int i = 0; i < fields.Length; i++) { - if (result != string.Empty) { + if (!string.IsNullOrEmpty(result)) { result += ", "; } object value = fields [i].GetValue (ev); diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs index 16856e674d..4d6d16a3ce 100644 --- a/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs +++ b/src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs @@ -376,28 +376,28 @@ namespace Avalonia.Markup.Parsers if (r.Peek == 'o') { - var constArg = r.TakeUntil(')').ToString().Trim(); - if (constArg.Equals("odd", StringComparison.Ordinal)) + var constArg = r.TakeUntil(')').Trim(); + if (constArg.SequenceEqual("odd".AsSpan())) { step = 2; offset = 1; } else { - throw new ExpressionParseException(r.Position, $"Expected nth-child(odd). Actual '{constArg}'."); + throw new ExpressionParseException(r.Position, $"Expected nth-child(odd). Actual '{constArg.ToString()}'."); } } else if (r.Peek == 'e') { - var constArg = r.TakeUntil(')').ToString().Trim(); - if (constArg.Equals("even", StringComparison.Ordinal)) + var constArg = r.TakeUntil(')').Trim(); + if (constArg.SequenceEqual("even".AsSpan())) { step = 2; offset = 0; } else { - throw new ExpressionParseException(r.Position, $"Expected nth-child(even). Actual '{constArg}'."); + throw new ExpressionParseException(r.Position, $"Expected nth-child(even). Actual '{constArg.ToString()}'."); } } else @@ -405,7 +405,7 @@ namespace Avalonia.Markup.Parsers r.SkipWhitespace(); var stepOrOffset = 0; - var stepOrOffsetStr = r.TakeWhile(c => char.IsDigit(c) || c == '-' || c == '+').ToString(); + var stepOrOffsetStr = r.TakeWhile(c => char.IsDigit(c) || c == '-' || c == '+'); if (stepOrOffsetStr.Length == 0 || (stepOrOffsetStr.Length == 1 && stepOrOffsetStr[0] == '+')) @@ -417,7 +417,7 @@ namespace Avalonia.Markup.Parsers { stepOrOffset = -1; } - else if (!int.TryParse(stepOrOffsetStr.ToString(), out stepOrOffset)) + else if (!stepOrOffsetStr.TryParseInt(out stepOrOffset)) { throw new ExpressionParseException(r.Position, "Couldn't parse nth-child step or offset value. Integer was expected."); } @@ -462,7 +462,7 @@ namespace Avalonia.Markup.Parsers r.SkipWhitespace(); if (sign != 0 - && !int.TryParse(r.TakeUntil(')').ToString(), out offset)) + && !r.TakeUntil(')').TryParseInt(out offset)) { throw new ExpressionParseException(r.Position, "Couldn't parse nth-child offset value. Integer was expected."); } diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs index 3a31679424..12d31258b5 100644 --- a/src/Web/Avalonia.Web/AvaloniaView.cs +++ b/src/Web/Avalonia.Web/AvaloniaView.cs @@ -136,6 +136,8 @@ namespace Avalonia.Web DomHelper.ObserveSize(host, null, OnSizeChanged); CanvasHelper.RequestAnimationFrame(_canvas, true); + + InputHelper.FocusElement(_containerElement); } private static RawPointerPoint ExtractRawPointerFromJSArgs(JSObject args) diff --git a/src/Web/Avalonia.Web/webapp/build.js b/src/Web/Avalonia.Web/webapp/build.js index 6b6df4c300..81f863cac7 100644 --- a/src/Web/Avalonia.Web/webapp/build.js +++ b/src/Web/Avalonia.Web/webapp/build.js @@ -5,7 +5,7 @@ require("esbuild").build({ ], outdir: "../wwwroot", bundle: true, - minify: false, + minify: true, format: "esm", target: "es2016", platform: "browser", diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts index 2257d56a92..783710bb3e 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts @@ -11,6 +11,7 @@ export class AvaloniaDOM { host.tabIndex = 0; host.oncontextmenu = function () { return false; }; host.style.overflow = "hidden"; + host.style.touchAction = "none"; // Rendering target canvas const canvas = document.createElement("canvas"); diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index 1d265369fd..0d29bb91ea 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -3,7 +3,6 @@ net6.0;netstandard2.0 true Avalonia.Win32 - Avalonia.MicroCom diff --git a/src/Windows/Avalonia.Win32/ClipboardImpl.cs b/src/Windows/Avalonia.Win32/ClipboardImpl.cs index 7cf8b14bed..7e058cb052 100644 --- a/src/Windows/Avalonia.Win32/ClipboardImpl.cs +++ b/src/Windows/Avalonia.Win32/ClipboardImpl.cs @@ -7,6 +7,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Threading; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32 { @@ -83,7 +84,7 @@ namespace Avalonia.Win32 while (true) { - var ptr = MicroCom.MicroComRuntime.GetNativeIntPtr(wrapper); + var ptr = wrapper.GetNativeIntPtr(); var hr = UnmanagedMethods.OleSetClipboard(ptr); if (hr == 0) @@ -107,7 +108,7 @@ namespace Avalonia.Win32 if (hr == 0) { - using var proxy = MicroCom.MicroComRuntime.CreateProxyFor(dataObject, true); + using var proxy = MicroComRuntime.CreateProxyFor(dataObject, true); using var wrapper = new OleDataObject(proxy); var formats = wrapper.GetDataFormats().ToArray(); return formats; @@ -131,7 +132,7 @@ namespace Avalonia.Win32 if (hr == 0) { - using var proxy = MicroCom.MicroComRuntime.CreateProxyFor(dataObject, true); + using var proxy = MicroComRuntime.CreateProxyFor(dataObject, true); using var wrapper = new OleDataObject(proxy); var rv = wrapper.Get(format); return rv; diff --git a/src/Windows/Avalonia.Win32/DragSource.cs b/src/Windows/Avalonia.Win32/DragSource.cs index 1159c5bfc9..53d4345c5e 100644 --- a/src/Windows/Avalonia.Win32/DragSource.cs +++ b/src/Windows/Avalonia.Win32/DragSource.cs @@ -3,6 +3,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Threading; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32 { @@ -19,8 +20,8 @@ namespace Avalonia.Win32 using var src = new OleDragSource(); var allowed = OleDropTarget.ConvertDropEffect(allowedEffects); - var objPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(dataObject); - var srcPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(src); + var objPtr = MicroComRuntime.GetNativeIntPtr(dataObject); + var srcPtr = MicroComRuntime.GetNativeIntPtr(src); UnmanagedMethods.DoDragDrop(objPtr, srcPtr, (int)allowed, out var finalEffect); diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 9d1920498b..91e79c9670 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices.ComTypes; using System.Text; using Avalonia.MicroCom; +using MicroCom.Runtime; using Avalonia.Win32.Win32Com; // ReSharper disable InconsistentNaming diff --git a/src/Windows/Avalonia.Win32/OleContext.cs b/src/Windows/Avalonia.Win32/OleContext.cs index c025d06fe7..e41423a334 100644 --- a/src/Windows/Avalonia.Win32/OleContext.cs +++ b/src/Windows/Avalonia.Win32/OleContext.cs @@ -5,6 +5,7 @@ using Avalonia.Platform; using Avalonia.Threading; using Avalonia.Win32.Interop; using Avalonia.Win32.Win32Com; +using MicroCom.Runtime; namespace Avalonia.Win32 { @@ -47,7 +48,7 @@ namespace Avalonia.Win32 return false; } - var trgPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(target); + var trgPtr = target.GetNativeIntPtr(); return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK; } diff --git a/src/Windows/Avalonia.Win32/OleDataObject.cs b/src/Windows/Avalonia.Win32/OleDataObject.cs index f7345b3ff7..90992d803f 100644 --- a/src/Windows/Avalonia.Win32/OleDataObject.cs +++ b/src/Windows/Avalonia.Win32/OleDataObject.cs @@ -10,7 +10,7 @@ using Avalonia.Input; using Avalonia.MicroCom; using Avalonia.Utilities; using Avalonia.Win32.Interop; - +using MicroCom.Runtime; using IDataObject = Avalonia.Input.IDataObject; namespace Avalonia.Win32 diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index 3d0d35228c..1c22fd025d 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -5,6 +5,7 @@ using Avalonia.Input.Raw; using Avalonia.MicroCom; using Avalonia.Platform; using Avalonia.Win32.Interop; +using MicroCom.Runtime; using DropEffect = Avalonia.Win32.Win32Com.DropEffect; namespace Avalonia.Win32 diff --git a/src/Windows/Avalonia.Win32/Win32StorageProvider.cs b/src/Windows/Avalonia.Win32/Win32StorageProvider.cs index bb1de56f2b..8cc0a380f9 100644 --- a/src/Windows/Avalonia.Win32/Win32StorageProvider.cs +++ b/src/Windows/Avalonia.Win32/Win32StorageProvider.cs @@ -12,6 +12,7 @@ using Avalonia.Platform.Storage; using Avalonia.Platform.Storage.FileIO; using Avalonia.Win32.Interop; using Avalonia.Win32.Win32Com; +using MicroCom.Runtime; namespace Avalonia.Win32 { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs index a09918a3a6..ef3de9fbe1 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs @@ -6,6 +6,7 @@ using Avalonia.MicroCom; using Avalonia.OpenGL; using Avalonia.OpenGL.Egl; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs index 9a6bd9572a..8a41c00add 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs @@ -12,6 +12,7 @@ using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; using Avalonia.Rendering; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs index ea75a2f311..32f44842f8 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Runtime.InteropServices; using Avalonia.MicroCom; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs index 4ed882552b..fc04dcda26 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs @@ -6,6 +6,7 @@ using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Surfaces; using Avalonia.Utilities; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs index 89cde01ff4..1794b022fe 100644 --- a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs +++ b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using System.Threading; using Avalonia.MicroCom; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT { diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs index d2ec957b8e..1fde57fe38 100644 --- a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs +++ b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Avalonia.MicroCom; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT { diff --git a/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs b/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs index f6616d74a2..029f8e236c 100644 --- a/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs +++ b/tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs @@ -80,7 +80,7 @@ namespace Avalonia.Visuals.UnitTests.Media.TextFormatting var remaining = remainingChars.Where(x => x != "" && x != "×").Select(x => Convert.ToInt32(x, 16)).ToArray(); codepoints.AddRange(remaining); - } + } var data = new GraphemeBreakData { diff --git a/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj b/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj index 3f4978f544..754a1d6a24 100644 --- a/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj +++ b/tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj @@ -1,6 +1,5 @@  - Exe net6.0 Exe false diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props new file mode 100644 index 0000000000..52af0f5ab2 --- /dev/null +++ b/tests/Directory.Build.props @@ -0,0 +1,6 @@ + + + + false + +