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
+
+