diff --git a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs index bf18a7da5b..3dbc7c1bb2 100644 --- a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs +++ b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs @@ -26,6 +26,6 @@ namespace Avalonia.Platform bool CurrentThreadIsLoopThread { get; } - event Action Signaled; + event Action? Signaled; } } diff --git a/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs b/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs index 75076e2bb8..f9c7f9685d 100644 --- a/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs +++ b/src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs @@ -7,9 +7,9 @@ namespace Avalonia.Platform.Storage; /// public sealed class FilePickerFileType { - public FilePickerFileType(string name) + public FilePickerFileType(string? name) { - Name = name; + Name = name ?? string.Empty; } /// diff --git a/src/Avalonia.Base/Rendering/IRenderTimer.cs b/src/Avalonia.Base/Rendering/IRenderTimer.cs index 07af7eeec8..14fcffd6a9 100644 --- a/src/Avalonia.Base/Rendering/IRenderTimer.cs +++ b/src/Avalonia.Base/Rendering/IRenderTimer.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using Avalonia.Metadata; namespace Avalonia.Rendering diff --git a/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs b/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs index 0658f9211c..d609dd94c8 100644 --- a/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs +++ b/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs @@ -13,6 +13,6 @@ namespace Avalonia.Platform /// /// Raised on on OSX via the Quit menu or right-clicking on the application icon and selecting Quit. /// - event EventHandler ShutdownRequested; + event EventHandler? ShutdownRequested; } } diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index 8d9d8e0e7b..31b144ce00 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -19,7 +19,7 @@ namespace Avalonia.Platform /// /// Gets or sets a method called when the minimized/maximized state of the window changes. /// - Action WindowStateChanged { get; set; } + Action? WindowStateChanged { get; set; } /// /// Sets the title of the window. @@ -42,7 +42,7 @@ namespace Avalonia.Platform /// /// Called when a disabled window received input. Can be used to activate child windows. /// - Action GotInputWhenDisabled { get; set; } + Action? GotInputWhenDisabled { get; set; } /// /// Enables or disables system window decorations (title bar, buttons, etc) @@ -68,7 +68,7 @@ namespace Avalonia.Platform /// Gets or sets a method called before the underlying implementation is destroyed. /// Return true to prevent the underlying implementation from closing. /// - Func Closing { get; set; } + Func? Closing { get; set; } /// /// Gets a value to indicate if the platform was able to extend client area to non-client area. @@ -78,7 +78,7 @@ namespace Avalonia.Platform /// /// Gets or Sets an action that is called whenever one of the extend client area properties changed. /// - Action ExtendClientAreaToDecorationsChanged { get; set; } + Action? ExtendClientAreaToDecorationsChanged { get; set; } /// /// Gets a flag that indicates if Managed decorations i.e. caption buttons are required. diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 0c9a91148b..26e11f0d4a 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -94,7 +94,7 @@ namespace Avalonia.Controls private set { SetAndRaise(IsActiveProperty, ref _isActive, value); } } - public Screens Screens { get; private set; } + public Screens Screens { get; } /// /// Gets or sets the owner of the window. diff --git a/src/Windows/Avalonia.Win32/AngleOptions.cs b/src/Windows/Avalonia.Win32/AngleOptions.cs index 076ddd2a5d..94c67120df 100644 --- a/src/Windows/Avalonia.Win32/AngleOptions.cs +++ b/src/Windows/Avalonia.Win32/AngleOptions.cs @@ -17,6 +17,6 @@ namespace Avalonia.Win32 new GlVersion(GlProfileType.OpenGLES, 2, 0) }; - public IList AllowedPlatformApis { get; set; } = null; + public IList? AllowedPlatformApis { get; set; } = null; } } diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs index 5f3f863493..aaad9cb3ba 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs @@ -2,8 +2,6 @@ using Avalonia.Automation.Provider; using UIA = Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IExpandCollapseProvider diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs index b91cb76888..518c945aa9 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs @@ -1,8 +1,6 @@ using Avalonia.Automation.Provider; using UIA = Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IRangeValueProvider diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs index 4f2d4ae269..0248a8d6a7 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs @@ -1,8 +1,6 @@ using Avalonia.Automation.Provider; using UIA = Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IScrollProvider, UIA.IScrollItemProvider diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs index 61903ab5b0..3751bb6476 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Avalonia.Automation.Peers; using Avalonia.Automation.Provider; using UIA = Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.ISelectionProvider, UIA.ISelectionItemProvider @@ -27,8 +24,7 @@ namespace Avalonia.Win32.Automation UIA.IRawElementProviderSimple[] UIA.ISelectionProvider.GetSelection() { var peers = InvokeSync>(x => x.GetSelection()); - return peers?.Select(x => (UIA.IRawElementProviderSimple)GetOrCreate(x)!).ToArray() ?? - Array.Empty(); + return peers.Select(x => (UIA.IRawElementProviderSimple)GetOrCreate(x)).ToArray(); } void UIA.ISelectionItemProvider.AddToSelection() => InvokeSync(x => x.AddToSelection()); diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs index 38f4d80946..08f4b62d83 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs @@ -1,8 +1,6 @@ using Avalonia.Automation.Provider; using UIA = Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IToggleProvider diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs index 34f5dfe0b9..204e159049 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs @@ -2,8 +2,6 @@ using Avalonia.Automation.Provider; using UIA = Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { internal partial class AutomationNode : UIA.IValueProvider diff --git a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs index 29ab2cea3a..5ca4ef63bf 100644 --- a/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs +++ b/src/Windows/Avalonia.Win32/Automation/AutomationNode.cs @@ -12,8 +12,6 @@ using Avalonia.Threading; using Avalonia.Win32.Interop.Automation; using AAP = Avalonia.Automation.Provider; -#nullable enable - namespace Avalonia.Win32.Automation { [ComVisible(true)] @@ -25,7 +23,7 @@ namespace Avalonia.Win32.Automation IRawElementProviderAdviseEvents, IInvokeProvider { - private static Dictionary s_propertyMap = new Dictionary() + private static Dictionary s_propertyMap = new() { { AutomationElementIdentifiers.BoundingRectangleProperty, UiaPropertyId.BoundingRectangle }, { AutomationElementIdentifiers.ClassNameProperty, UiaPropertyId.ClassName }, @@ -46,8 +44,7 @@ namespace Avalonia.Win32.Automation { SelectionPatternIdentifiers.SelectionProperty, UiaPropertyId.SelectionSelection }, }; - private static ConditionalWeakTable s_nodes = - new ConditionalWeakTable(); + private static ConditionalWeakTable s_nodes = new(); private readonly int[] _runtimeId; private int _raiseFocusChanged; @@ -174,11 +171,12 @@ namespace Avalonia.Win32.Automation NavigateDirection.LastChild => GetOrCreate(Peer.GetChildren().LastOrDefault()), _ => null, }; - }) as IRawElementProviderFragment; + }); } public void SetFocus() => InvokeSync(() => Peer.SetFocus()); + [return: NotNullIfNotNull(nameof(peer))] public static AutomationNode? GetOrCreate(AutomationPeer? peer) { return peer is null ? null : s_nodes.GetValue(peer, Create); diff --git a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs index b732c4169f..3d8b4995ad 100644 --- a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs +++ b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs @@ -6,8 +6,6 @@ using Avalonia.Automation.Provider; using Avalonia.Platform; using Avalonia.Win32.Interop.Automation; -#nullable enable - namespace Avalonia.Win32.Automation { [RequiresUnreferencedCode("Requires .NET COM interop")] diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index a24fe31df8..754e883c2f 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -6,7 +6,6 @@ - @@ -16,7 +15,8 @@ - + + diff --git a/src/Windows/Avalonia.Win32/ClipboardFormats.cs b/src/Windows/Avalonia.Win32/ClipboardFormats.cs index 7bd7765f8c..5fc4f21b2e 100644 --- a/src/Windows/Avalonia.Win32/ClipboardFormats.cs +++ b/src/Windows/Avalonia.Win32/ClipboardFormats.cs @@ -8,15 +8,15 @@ using Avalonia.Utilities; namespace Avalonia.Win32 { - static class ClipboardFormats + internal static class ClipboardFormats { private const int MAX_FORMAT_NAME_LENGTH = 260; - class ClipboardFormat + private class ClipboardFormat { - public ushort Format { get; private set; } - public string Name { get; private set; } - public ushort[] Synthesized { get; private set; } + public ushort Format { get; } + public string Name { get; } + public ushort[] Synthesized { get; } public ClipboardFormat(string name, ushort format, params ushort[] synthesized) { @@ -26,14 +26,14 @@ namespace Avalonia.Win32 } } - private static readonly List FormatList = new List() + private static readonly List s_formatList = new() { new ClipboardFormat(DataFormats.Text, (ushort)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, (ushort)UnmanagedMethods.ClipboardFormat.CF_TEXT), new ClipboardFormat(DataFormats.FileNames, (ushort)UnmanagedMethods.ClipboardFormat.CF_HDROP), }; - private static string QueryFormatName(ushort format) + private static string? QueryFormatName(ushort format) { var sb = StringBuilderCache.Acquire(MAX_FORMAT_NAME_LENGTH); if (UnmanagedMethods.GetClipboardFormatName(format, sb, sb.Capacity) > 0) @@ -43,16 +43,16 @@ namespace Avalonia.Win32 public static string GetFormat(ushort format) { - lock (FormatList) + lock (s_formatList) { - var pd = FormatList.FirstOrDefault(f => f.Format == format || Array.IndexOf(f.Synthesized, format) >= 0); + var pd = s_formatList.FirstOrDefault(f => f.Format == format || Array.IndexOf(f.Synthesized, format) >= 0); if (pd == null) { - string name = QueryFormatName(format); + string? name = QueryFormatName(format); if (string.IsNullOrEmpty(name)) - name = string.Format("Unknown_Format_{0}", format); + name = $"Unknown_Format_{format}"; pd = new ClipboardFormat(name, format); - FormatList.Add(pd); + s_formatList.Add(pd); } return pd.Name; } @@ -60,16 +60,16 @@ namespace Avalonia.Win32 public static ushort GetFormat(string format) { - lock (FormatList) + lock (s_formatList) { - var pd = FormatList.FirstOrDefault(f => StringComparer.OrdinalIgnoreCase.Equals(f.Name, format)); + var pd = s_formatList.FirstOrDefault(f => StringComparer.OrdinalIgnoreCase.Equals(f.Name, format)); if (pd == null) { int id = UnmanagedMethods.RegisterClipboardFormat(format); if (id == 0) throw new Win32Exception(); pd = new ClipboardFormat(format, (ushort)id); - FormatList.Add(pd); + s_formatList.Add(pd); } return pd.Format; } diff --git a/src/Windows/Avalonia.Win32/ClipboardImpl.cs b/src/Windows/Avalonia.Win32/ClipboardImpl.cs index 82fd1109f4..1a760aeab8 100644 --- a/src/Windows/Avalonia.Win32/ClipboardImpl.cs +++ b/src/Windows/Avalonia.Win32/ClipboardImpl.cs @@ -30,7 +30,7 @@ namespace Avalonia.Win32 return Disposable.Create(() => UnmanagedMethods.CloseClipboard()); } - public async Task GetTextAsync() + public async Task GetTextAsync() { using(await OpenClipboard()) { @@ -52,19 +52,17 @@ namespace Avalonia.Win32 } } - public async Task SetTextAsync(string text) + public async Task SetTextAsync(string? text) { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } - using(await OpenClipboard()) { UnmanagedMethods.EmptyClipboard(); - var hGlobal = Marshal.StringToHGlobalUni(text); - UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal); + if (text is not null) + { + var hGlobal = Marshal.StringToHGlobalUni(text); + UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal); + } } } @@ -121,7 +119,7 @@ namespace Avalonia.Win32 } } - public async Task GetDataAsync(string format) + public async Task GetDataAsync(string format) { Dispatcher.UIThread.VerifyAccess(); var i = OleRetryCount; diff --git a/src/Windows/Avalonia.Win32/DataObject.cs b/src/Windows/Avalonia.Win32/DataObject.cs index 7d22e57a30..272300cbf3 100644 --- a/src/Windows/Avalonia.Win32/DataObject.cs +++ b/src/Windows/Avalonia.Win32/DataObject.cs @@ -22,9 +22,9 @@ namespace Avalonia.Win32 // Compatibility with WinForms + WPF... internal static readonly byte[] SerializedObjectGUID = new Guid("FD9EA796-3B13-4370-A679-56106BB288FB").ToByteArray(); - class FormatEnumerator : CallbackBase, Win32Com.IEnumFORMATETC + private class FormatEnumerator : CallbackBase, Win32Com.IEnumFORMATETC { - private FORMATETC[] _formats; + private readonly FORMATETC[] _formats; private uint _current; private FormatEnumerator(FORMATETC[] formats, uint current) @@ -105,16 +105,12 @@ namespace Avalonia.Win32 public DataObject(IDataObject wrapped) { - if (wrapped == null) + _wrapped = wrapped switch { - throw new ArgumentNullException(nameof(wrapped)); - } - if (_wrapped is DataObject || _wrapped is OleDataObject) - { - throw new InvalidOperationException(); - } - - _wrapped = wrapped; + null => throw new ArgumentNullException(nameof(wrapped)), + DataObject or OleDataObject => throw new ArgumentException($"Cannot wrap a {wrapped.GetType()}"), + _ => wrapped + }; } #region IDataObject @@ -128,17 +124,17 @@ namespace Avalonia.Win32 return _wrapped.GetDataFormats(); } - IEnumerable IDataObject.GetFileNames() + IEnumerable? IDataObject.GetFileNames() { return _wrapped.GetFileNames(); } - string IDataObject.GetText() + string? IDataObject.GetText() { return _wrapped.GetText(); } - object IDataObject.Get(string dataFormat) + object? IDataObject.Get(string dataFormat) { return _wrapped.Get(dataFormat); } @@ -182,9 +178,6 @@ namespace Avalonia.Win32 if (_wrapped is Win32Com.IDataObject ole) return ole.GetCanonicalFormatEtc(formatIn); - var formatOut = new FORMATETC(); - formatOut.ptd = IntPtr.Zero; - throw new COMException(nameof(UnmanagedMethods.HRESULT.E_NOTIMPL), unchecked((int)UnmanagedMethods.HRESULT.E_NOTIMPL)); } @@ -264,9 +257,9 @@ namespace Avalonia.Win32 private uint WriteDataToHGlobal(string dataFormat, ref IntPtr hGlobal) { - object data = _wrapped.Get(dataFormat); + object data = _wrapped.Get(dataFormat)!; if (dataFormat == DataFormats.Text || data is string) - return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data)); + return WriteStringToHGlobal(ref hGlobal, Convert.ToString(data) ?? string.Empty); if (dataFormat == DataFormats.FileNames && data is IEnumerable files) return WriteFileListToHGlobal(ref hGlobal, files); if (data is Stream stream) @@ -286,7 +279,7 @@ namespace Avalonia.Win32 } if (data is IEnumerable bytes) { - var byteArr = bytes is byte[] ? (byte[])bytes : bytes.ToArray(); + var byteArr = bytes as byte[] ?? bytes.ToArray(); return WriteBytesToHGlobal(ref hGlobal, byteArr); } return WriteBytesToHGlobal(ref hGlobal, SerializeObject(data)); @@ -332,7 +325,7 @@ namespace Avalonia.Win32 private static uint WriteFileListToHGlobal(ref IntPtr hGlobal, IEnumerable files) { - if (!files?.Any() ?? false) + if (!files.Any()) return unchecked((int)UnmanagedMethods.HRESULT.S_OK); char[] filesStr = (string.Join("\0", files) + "\0\0").ToCharArray(); @@ -392,7 +385,7 @@ namespace Avalonia.Win32 public void ReleaseWrapped() { - _wrapped = null; + _wrapped = null!; } #endregion } diff --git a/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs b/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs index c11a6026e7..e59eb98c6c 100644 --- a/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs +++ b/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs @@ -1,17 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using static Avalonia.Win32.Interop.UnmanagedMethods; // ReSharper disable InconsistentNaming #pragma warning disable CS0649 namespace Avalonia.Win32.DirectX { -#nullable enable public unsafe struct HANDLE { public readonly void* Value; @@ -288,5 +281,4 @@ namespace Avalonia.Win32.DirectX public D3D11_RESOURCE_MISC_FLAG MiscFlags; } -#nullable restore } diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs index e82f7633be..26696ef903 100644 --- a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs +++ b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs @@ -1,24 +1,14 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; using System.Threading.Tasks; using Avalonia.Logging; -using Avalonia.OpenGL.Angle; -using Avalonia.OpenGL.Egl; using Avalonia.Rendering; -using Avalonia.Win32.OpenGl.Angle; using static Avalonia.Win32.Interop.UnmanagedMethods; using static Avalonia.Win32.DirectX.DirectXUnmanagedMethods; using MicroCom.Runtime; namespace Avalonia.Win32.DirectX { -#pragma warning disable CA1416 // This should only be reachable on Windows -#nullable enable public unsafe class DxgiConnection : IRenderTimer { public const uint ENUM_CURRENT_SETTINGS = unchecked((uint)(-1)); @@ -26,11 +16,11 @@ namespace Avalonia.Win32.DirectX public bool RunsInBackground => true; public event Action? Tick; - private object _syncLock; + private readonly object _syncLock; - private IDXGIOutput? _output = null; + private IDXGIOutput? _output; - private Stopwatch? _stopwatch = null; + private Stopwatch? _stopwatch; private const string LogArea = "DXGI"; public DxgiConnection(object syncLock) @@ -51,9 +41,9 @@ namespace Avalonia.Win32.DirectX } } - private unsafe void RunLoop() + private void RunLoop() { - _stopwatch = System.Diagnostics.Stopwatch.StartNew(); + _stopwatch = Stopwatch.StartNew(); try { GetBestOutputToVWaitOn(); @@ -162,7 +152,7 @@ namespace Avalonia.Win32.DirectX } // Used the windows composition as a blueprint for this startup/creation - static private bool TryCreateAndRegisterCore() + private static bool TryCreateAndRegisterCore() { var tcs = new TaskCompletionSource(); var pumpLock = new object(); @@ -170,9 +160,7 @@ namespace Avalonia.Win32.DirectX { try { - DxgiConnection connection; - - connection = new DxgiConnection(pumpLock); + var connection = new DxgiConnection(pumpLock); AvaloniaLocator.CurrentMutable.BindToSelf(connection); AvaloniaLocator.CurrentMutable.Bind().ToConstant(connection); @@ -191,6 +179,4 @@ namespace Avalonia.Win32.DirectX return tcs.Task.Result; } } -#nullable restore -#pragma warning restore CA1416 // Validate platform compatibility } diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs index cb7826e185..065386b401 100644 --- a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs +++ b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs @@ -1,40 +1,28 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Surfaces; using Avalonia.Win32.OpenGl.Angle; using MicroCom.Runtime; -using static Avalonia.OpenGL.Egl.EglGlPlatformSurfaceBase; using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32.DirectX { -#pragma warning disable CA1416 // Validate platform compatibility, if you enter this not on windows you have messed up badly -#nullable enable public unsafe class DxgiRenderTarget : EglPlatformSurfaceRenderTargetBase { // DXGI_FORMAT_B8G8R8A8_UNORM is target texture format as per ANGLE documentation public const uint DXGI_USAGE_RENDER_TARGET_OUTPUT = 0x00000020U; + private readonly Guid ID3D11Texture2DGuid = Guid.Parse("6F15AAF2-D208-4E89-9AB4-489535D34F9C"); - private EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _window; - private DxgiConnection _connection; - private IDXGIDevice? _dxgiDevice = null; - private IDXGIFactory2? _dxgiFactory = null; - private IDXGISwapChain1? _swapChain = null; - private IUnknown? _renderTexture = null; + private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _window; + private readonly DxgiConnection _connection; + private readonly IDXGIDevice? _dxgiDevice; + private readonly IDXGIFactory2? _dxgiFactory; + private readonly IDXGISwapChain1? _swapChain; + private readonly uint _flagsUsed; - private Interop.UnmanagedMethods.RECT _clientRect = default; - - private uint _flagsUsed; - - private Guid ID3D11Texture2DGuid = Guid.Parse("6F15AAF2-D208-4E89-9AB4-489535D34F9C"); + private IUnknown? _renderTexture; + private RECT _clientRect; public DxgiRenderTarget(EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo window, EglContext context, DxgiConnection connection) : base(context) { @@ -80,11 +68,11 @@ namespace Avalonia.Win32.DirectX null ); - Interop.UnmanagedMethods.RECT pClientRect; - GetClientRect(_window.Handle, out pClientRect); + GetClientRect(_window.Handle, out var pClientRect); _clientRect = pClientRect; } + /// public override IGlPlatformSurfaceRenderingSession BeginDrawCore() { if (_swapChain is null) @@ -98,8 +86,7 @@ namespace Avalonia.Win32.DirectX var success = false; try { - Interop.UnmanagedMethods.RECT pClientRect; - GetClientRect(_window.Handle, out pClientRect); + GetClientRect(_window.Handle, out var pClientRect); if (!RectsEqual(pClientRect, _clientRect)) { // we gotta resize @@ -137,7 +124,7 @@ namespace Avalonia.Win32.DirectX var res = base.BeginDraw(surface, _window.Size, _window.Scaling, () => { _swapChain.Present((ushort)0U, (ushort)0U); - surface?.Dispose(); + surface.Dispose(); transaction?.Dispose(); contextLock?.Dispose(); }, true); @@ -178,6 +165,4 @@ namespace Avalonia.Win32.DirectX } } -#pragma warning restore CA1416 // Validate platform compatibility -#nullable restore } diff --git a/src/Windows/Avalonia.Win32/FramebufferManager.cs b/src/Windows/Avalonia.Win32/FramebufferManager.cs index 8feecab4dd..cba4879f5b 100644 --- a/src/Windows/Avalonia.Win32/FramebufferManager.cs +++ b/src/Windows/Avalonia.Win32/FramebufferManager.cs @@ -4,8 +4,6 @@ using Avalonia.Controls.Platform.Surfaces; using Avalonia.Platform; using Avalonia.Win32.Interop; -#nullable enable - namespace Avalonia.Win32 { internal class FramebufferManager : IFramebufferPlatformSurface, IDisposable diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs index 7ef1cb1d1c..41417dd950 100644 --- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs +++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Text; using Avalonia.Input.TextInput; using Avalonia.Threading; @@ -10,21 +11,21 @@ namespace Avalonia.Win32.Input /// /// A Windows input method editor based on Windows Input Method Manager (IMM32). /// - class Imm32InputMethod : ITextInputMethodImpl + internal class Imm32InputMethod : ITextInputMethodImpl { - public IntPtr HWND { get; private set; } + public IntPtr Hwnd { get; private set; } private IntPtr _currentHimc; - private WindowImpl _parent; - private ITextInputMethodClient _client; + private WindowImpl? _parent; - private Imm32CaretManager _caretManager = new(); + private Imm32CaretManager _caretManager; private ushort _langId; - private const int _caretMargin = 1; + private const int CaretMargin = 1; - public ITextInputMethodClient Client => _client; + public ITextInputMethodClient? Client { get; private set; } - public bool IsActive => _client != null; + [MemberNotNullWhen(true, nameof(Client))] + public bool IsActive => Client != null; public bool IsComposing { get; set; } @@ -32,12 +33,12 @@ namespace Avalonia.Win32.Input public void CreateCaret() { - _caretManager.TryCreate(HWND); + _caretManager.TryCreate(Hwnd); } public void EnableImm() { - var himc = ImmGetContext(HWND); + var himc = ImmGetContext(Hwnd); if(himc == IntPtr.Zero) { @@ -51,13 +52,13 @@ namespace Avalonia.Win32.Input DisableImm(); } - ImmAssociateContext(HWND, himc); + ImmAssociateContext(Hwnd, himc); - ImmReleaseContext(HWND, himc); + ImmReleaseContext(Hwnd, himc); _currentHimc = himc; - _caretManager.TryCreate(HWND); + _caretManager.TryCreate(Hwnd); } } @@ -67,7 +68,7 @@ namespace Avalonia.Win32.Input Reset(); - ImmAssociateContext(HWND, IntPtr.Zero); + ImmAssociateContext(Hwnd, IntPtr.Zero); _caretManager.TryDestroy(); @@ -76,7 +77,7 @@ namespace Avalonia.Win32.Input public void SetLanguageAndWindow(WindowImpl parent, IntPtr hwnd, IntPtr HKL) { - HWND = hwnd; + Hwnd = hwnd; _parent = parent; _langId = PRIMARYLANGID(LGID(HKL)); @@ -98,9 +99,9 @@ namespace Avalonia.Win32.Input { DisableImm(); - HWND = IntPtr.Zero; + Hwnd = IntPtr.Zero; _parent = null; - _client = null; + Client = null; _langId = 0; IsComposing = false; @@ -108,13 +109,13 @@ namespace Avalonia.Win32.Input //Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers - //every Dispatcher should have their own InputMethod. - public static Imm32InputMethod Current { get; } = new Imm32InputMethod(); + public static Imm32InputMethod Current { get; } = new(); public void Reset() { Dispatcher.UIThread.Post(() => { - var himc = ImmGetContext(HWND); + var himc = ImmGetContext(Hwnd); if (IsComposing) { @@ -123,13 +124,13 @@ namespace Avalonia.Win32.Input IsComposing = false; } - ImmReleaseContext(HWND, himc); + ImmReleaseContext(Hwnd, himc); }); } - public void SetClient(ITextInputMethodClient client) + public void SetClient(ITextInputMethodClient? client) { - _client = client; + Client = client; Dispatcher.UIThread.Post(() => { @@ -152,7 +153,7 @@ namespace Avalonia.Win32.Input public void SetCursorRect(Rect rect) { - var focused = GetActiveWindow() == HWND; + var focused = GetActiveWindow() == Hwnd; if (!focused) { @@ -161,7 +162,7 @@ namespace Avalonia.Win32.Input Dispatcher.UIThread.Post(() => { - var himc = ImmGetContext(HWND); + var himc = ImmGetContext(Hwnd); if (himc == IntPtr.Zero) { @@ -170,7 +171,7 @@ namespace Avalonia.Win32.Input MoveImeWindow(rect, himc); - ImmReleaseContext(HWND, himc); + ImmReleaseContext(Hwnd, himc); }); } @@ -219,7 +220,7 @@ namespace Avalonia.Win32.Input // the caret to move the position of their candidate windows. // On the other hand, Korean IMEs require the lower-left corner of the // caret to move their candidate windows. - y2 += _caretMargin; + y2 += CaretMargin; } // Need to return here since some Chinese IMEs would stuck if set @@ -238,7 +239,7 @@ namespace Avalonia.Win32.Input dwIndex = 0, dwStyle = CFS_EXCLUDE, ptCurrentPos = new POINT {X = x1, Y = y1}, - rcArea = new RECT {left = x1, top = y1, right = x2, bottom = y2 + _caretMargin} + rcArea = new RECT {left = x1, top = y1, right = x2, bottom = y2 + CaretMargin} }; ImmSetCandidateWindow(himc, ref excludeRectangle); @@ -275,34 +276,21 @@ namespace Avalonia.Win32.Input return; } - if(!IsActive || !_client.SupportsPreedit) + if(!IsActive || !Client.SupportsPreedit) { return; } var composition = GetCompositionString(); - _client.SetPreeditText(composition); + Client.SetPreeditText(composition); } - private string GetCompositionString() + private string? GetCompositionString() { - var himc = ImmGetContext(HWND); + var himc = ImmGetContext(Hwnd); - var length = ImmGetCompositionString(himc, GCS.GCS_COMPSTR, IntPtr.Zero, 0); - - var buffer = new byte[length]; - - unsafe - { - fixed (byte* bufferPtr = buffer) - { - var error = ImmGetCompositionString(himc, GCS.GCS_COMPSTR, (IntPtr)bufferPtr, (uint)length); - - return Encoding.Unicode.GetString(buffer, 0, buffer.Length); - } - } - + return ImmGetCompositionString(himc, GCS.GCS_COMPSTR); } ~Imm32InputMethod() diff --git a/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs b/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs index 998ff4a427..c7bc511b99 100644 --- a/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs +++ b/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs @@ -5,9 +5,10 @@ using Avalonia.Win32.Interop; namespace Avalonia.Win32.Input { - class WindowsMouseDevice : MouseDevice + internal class WindowsMouseDevice : MouseDevice { private readonly IPointer _pointer; + public WindowsMouseDevice() : base(WindowsMousePointer.CreatePointer(out var pointer)) { _pointer = pointer; @@ -15,14 +16,14 @@ namespace Avalonia.Win32.Input // Normally user should use IPointer.Capture instead of MouseDevice.Capture, // But on Windows we need to handle WM_MOUSE capture manually without having access to the Pointer. - internal void Capture(IInputElement control) + internal void Capture(IInputElement? control) { _pointer.Capture(control); } internal class WindowsMousePointer : Pointer { - private WindowsMousePointer() : base(Pointer.GetNextFreeId(),PointerType.Mouse, true) + private WindowsMousePointer() : base(GetNextFreeId(),PointerType.Mouse, true) { } @@ -31,7 +32,7 @@ namespace Avalonia.Win32.Input return pointer = new WindowsMousePointer(); } - protected override void PlatformCapture(IInputElement element) + protected override void PlatformCapture(IInputElement? element) { var hwnd = (TopLevel.GetTopLevel(element as Visual)?.PlatformImpl as WindowImpl) ?.Handle.Handle; diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs index a8caf26524..be8b998a9e 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.InteropServices; namespace Avalonia.Win32.Interop.Automation @@ -8,7 +7,7 @@ namespace Avalonia.Win32.Interop.Automation [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IGridProvider { - IRawElementProviderSimple GetItem(int row, int column); + IRawElementProviderSimple? GetItem(int row, int column); int RowCount { get; } int ColumnCount { get; } } diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs index a62aa842cb..46d8dc6cdb 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs @@ -1,8 +1,6 @@ using System; using System.Runtime.InteropServices; -#nullable enable - namespace Avalonia.Win32.Interop.Automation { [ComVisible(true)] diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs index 71d1bdce60..1fd0cb13ba 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.InteropServices; namespace Avalonia.Win32.Interop.Automation @@ -8,7 +7,7 @@ namespace Avalonia.Win32.Interop.Automation [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IRawElementProviderFragmentRoot : IRawElementProviderFragment { - IRawElementProviderFragment ElementProviderFromPoint(double x, double y); - IRawElementProviderFragment GetFocus(); + IRawElementProviderFragment? ElementProviderFromPoint(double x, double y); + IRawElementProviderFragment? GetFocus(); } } diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs index 439036290e..5b67d10206 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs @@ -1,8 +1,6 @@ using System; using System.Runtime.InteropServices; -#nullable enable - namespace Avalonia.Win32.Interop.Automation { [Flags] diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs index f3504b8d77..c2e8a42f87 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs @@ -1,7 +1,4 @@ -using System; -using System.Runtime.InteropServices; - -#nullable enable +using System.Runtime.InteropServices; namespace Avalonia.Win32.Interop.Automation { diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs index 8d6677315c..072e210027 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs @@ -1,5 +1,3 @@ -#nullable enable -using System; using System.Runtime.InteropServices; namespace Avalonia.Win32.Interop.Automation diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs index 919be647f8..0356f93ab8 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs @@ -1,8 +1,5 @@ -using System; using System.Runtime.InteropServices; -#nullable enable - namespace Avalonia.Win32.Interop.Automation { [ComVisible(true)] diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs index 4ba7a710d4..bd939c56b7 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs @@ -71,21 +71,21 @@ namespace Avalonia.Win32.Interop.Automation public static extern bool UiaClientsAreListening(); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple el); + public static extern IntPtr UiaReturnRawElementProvider(IntPtr hwnd, IntPtr wParam, IntPtr lParam, IRawElementProviderSimple? el); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] public static extern int UiaHostProviderFromHwnd(IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] out IRawElementProviderSimple provider); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaRaiseAutomationEvent(IRawElementProviderSimple provider, int id); + public static extern int UiaRaiseAutomationEvent(IRawElementProviderSimple? provider, int id); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple provider, int id, object oldValue, object newValue); + public static extern int UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple? provider, int id, object? oldValue, object? newValue); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaRaiseStructureChangedEvent(IRawElementProviderSimple provider, StructureChangeType structureChangeType, int[] runtimeId, int runtimeIdLen); + public static extern int UiaRaiseStructureChangedEvent(IRawElementProviderSimple? provider, StructureChangeType structureChangeType, int[]? runtimeId, int runtimeIdLen); [DllImport("UIAutomationCore.dll", CharSet = CharSet.Unicode)] - public static extern int UiaDisconnectProvider(IRawElementProviderSimple provider); + public static extern int UiaDisconnectProvider(IRawElementProviderSimple? provider); } } diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs index 08b3ee32fa..b6b069ac37 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs @@ -63,8 +63,8 @@ namespace Avalonia.Win32.Interop.Automation } #endif - var comConfig = AppContext.GetData("System.Runtime.InteropServices.BuiltInComInterop.IsSupported"); - return comConfig == null || bool.Parse(comConfig.ToString()); + var comConfig = AppContext.GetData("System.Runtime.InteropServices.BuiltInComInterop.IsSupported") as string; + return comConfig == null || bool.Parse(comConfig); } [DllImport("UIAutomationCore.dll", EntryPoint = "UiaLookupId", CharSet = CharSet.Unicode)] diff --git a/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs b/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs index 88b907aeec..7eb457480b 100644 --- a/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs +++ b/src/Windows/Avalonia.Win32/Interop/TaskBarList.cs @@ -7,8 +7,8 @@ namespace Avalonia.Win32.Interop internal class TaskBarList { private static IntPtr s_taskBarList; - private static HrInit s_hrInitDelegate; - private static MarkFullscreenWindow s_markFullscreenWindowDelegate; + private static HrInit? s_hrInitDelegate; + private static MarkFullscreenWindow? s_markFullscreenWindowDelegate; /// /// Ported from https://github.com/chromium/chromium/blob/master/ui/views/win/fullscreen_handler.cc @@ -28,10 +28,7 @@ namespace Avalonia.Win32.Interop { var ptr = (ITaskBarList2VTable**)s_taskBarList.ToPointer(); - if (s_hrInitDelegate is null) - { - s_hrInitDelegate = Marshal.GetDelegateForFunctionPointer((*ptr)->HrInit); - } + s_hrInitDelegate ??= Marshal.GetDelegateForFunctionPointer((*ptr)->HrInit); if (s_hrInitDelegate(s_taskBarList) != HRESULT.S_OK) { @@ -44,10 +41,8 @@ namespace Avalonia.Win32.Interop { var ptr = (ITaskBarList2VTable**)s_taskBarList.ToPointer(); - if (s_markFullscreenWindowDelegate is null) - { - s_markFullscreenWindowDelegate = Marshal.GetDelegateForFunctionPointer((*ptr)->MarkFullscreenWindow); - } + s_markFullscreenWindowDelegate ??= + Marshal.GetDelegateForFunctionPointer((*ptr)->MarkFullscreenWindow); s_markFullscreenWindowDelegate(s_taskBarList, hwnd, fullscreen); } diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 672f3a781a..1dd2ef20c7 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1,14 +1,12 @@ +#nullable enable + using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text; - -using Avalonia.MicroCom; using MicroCom.Runtime; -using Avalonia.Win32.Win32Com; // ReSharper disable InconsistentNaming #pragma warning disable 169, 649 @@ -1092,7 +1090,7 @@ namespace Avalonia.Win32.Interop public const int SizeOf_BITMAPINFOHEADER = 40; [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)] - unsafe internal static extern int GetMouseMovePointsEx( + internal static extern int GetMouseMovePointsEx( uint cbSize, MOUSEMOVEPOINT* pointsIn, MOUSEMOVEPOINT* pointsBufferOut, int nBufPoints, uint resolution); @@ -1167,7 +1165,7 @@ namespace Avalonia.Win32.Interop public static extern IntPtr CreateWindowEx( int dwExStyle, uint lpClassName, - string lpWindowName, + string? lpWindowName, uint dwStyle, int x, int y, @@ -1218,7 +1216,7 @@ namespace Avalonia.Win32.Interop public static extern int GetMessageTime(); [DllImport("kernel32.dll")] - public static extern IntPtr GetModuleHandle(string lpModuleName); + public static extern IntPtr GetModuleHandle(string? lpModuleName); [DllImport("user32.dll")] public static extern int GetSystemMetrics(SystemMetric smIndex); @@ -1255,7 +1253,7 @@ namespace Avalonia.Win32.Interop } else { - return (uint)SetWindowLong64b(hWnd, nIndex, new IntPtr((uint)value)).ToInt32(); + return (uint)SetWindowLong64b(hWnd, nIndex, new IntPtr(value)).ToInt32(); } } @@ -1421,7 +1419,7 @@ namespace Avalonia.Win32.Interop public static extern bool UnregisterClass(string lpClassName, IntPtr hInstance); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SetWindowTextW")] - public static extern bool SetWindowText(IntPtr hwnd, string lpString); + public static extern bool SetWindowText(IntPtr hwnd, string? lpString); public enum ClassLongIndex : int { @@ -1482,7 +1480,7 @@ namespace Avalonia.Win32.Interop internal static extern int CoCreateInstance(ref Guid clsid, IntPtr ignore1, int ignore2, ref Guid iid, [Out] out IntPtr pUnkOuter); - internal unsafe static T CreateInstance(ref Guid clsid, ref Guid iid) where T : IUnknown + internal static T CreateInstance(ref Guid clsid, ref Guid iid) where T : IUnknown { var hresult = CoCreateInstance(ref clsid, IntPtr.Zero, 1, ref iid, out IntPtr pUnk); if (hresult != 0) @@ -1490,7 +1488,7 @@ namespace Avalonia.Win32.Interop throw new COMException("CreateInstance", hresult); } using var unk = MicroComRuntime.CreateProxyFor(pUnk, true); - return MicroComRuntime.QueryInterface(unk); + return unk.QueryInterface(); } [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] @@ -1581,7 +1579,7 @@ namespace Avalonia.Win32.Interop public static extern bool GetMonitorInfo([In] IntPtr hMonitor, ref MONITORINFO lpmi); [DllImport("user32")] - public static extern unsafe bool GetTouchInputInfo( + public static extern bool GetTouchInputInfo( IntPtr hTouchInput, uint cInputs, TOUCHINPUT* pInputs, @@ -1680,7 +1678,7 @@ namespace Avalonia.Win32.Interop public static extern IntPtr GlobalSize(IntPtr hGlobal); [DllImport("shell32.dll", BestFitMapping = false, CharSet = CharSet.Auto)] - public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch); + public static extern int DragQueryFile(IntPtr hDrop, int iFile, StringBuilder? lpszFile, int cch); [DllImport("ole32.dll", CharSet = CharSet.Auto, ExactSpelling = true, PreserveSig = false)] internal static extern void DoDragDrop(IntPtr dataObject, IntPtr dropSource, int allowedEffects, [Out] out int finalEffect); @@ -1734,7 +1732,7 @@ namespace Avalonia.Win32.Interop public DWM_BLURBEHIND(bool enabled) { - fEnable = enabled ? true : false; + fEnable = enabled; hRgnBlur = IntPtr.Zero; fTransitionOnMaximized = false; dwFlags = DWM_BB.Enable; @@ -1855,20 +1853,22 @@ namespace Avalonia.Win32.Interop [DllImport("imm32.dll", SetLastError = false, CharSet = CharSet.Unicode)] public static extern int ImmGetCompositionString(IntPtr hIMC, GCS dwIndex, [Out, Optional] IntPtr lpBuf, uint dwBufLen); - public static string ImmGetCompositionString(IntPtr hIMC, GCS dwIndex) + public static string? ImmGetCompositionString(IntPtr hIMC, GCS dwIndex) { int bufferLength = ImmGetCompositionString(hIMC, dwIndex, IntPtr.Zero, 0); if (bufferLength > 0) { - var buffer = new byte[bufferLength]; + var buffer = bufferLength <= 64 ? stackalloc byte[bufferLength] : new byte[bufferLength]; - fixed(byte* bufferPtr = buffer) + fixed (byte* bufferPtr = buffer) { - var error = ImmGetCompositionString(hIMC, dwIndex, (IntPtr)bufferPtr, (uint)bufferLength); - - return Marshal.PtrToStringUni((IntPtr)bufferPtr); - } + var result = ImmGetCompositionString(hIMC, dwIndex, (IntPtr)bufferPtr, (uint)bufferLength); + if (result >= 0) + { + return Marshal.PtrToStringUni((IntPtr)bufferPtr); + } + } } return null; @@ -2380,7 +2380,7 @@ namespace Avalonia.Win32.Interop } } - [StructLayoutAttribute(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential)] internal struct _DROPFILES { public Int32 pFiles; @@ -2390,7 +2390,7 @@ namespace Avalonia.Win32.Interop public bool fWide; } - [StructLayoutAttribute(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential)] internal struct STGMEDIUM { public TYMED tymed; @@ -2398,7 +2398,7 @@ namespace Avalonia.Win32.Interop public IntPtr pUnkForRelease; } - [StructLayoutAttribute(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Sequential)] internal struct FORMATETC { public ushort cfFormat; @@ -2507,14 +2507,14 @@ namespace Avalonia.Win32.Interop public int uCallbackMessage; public IntPtr hIcon; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] - public string szTip; + public string? szTip; public int dwState = 0; public int dwStateMask = 0; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string szInfo; + public string? szInfo; public int uTimeoutOrVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] - public string szInfoTitle; + public string? szInfoTitle; public NIIF dwInfoFlags; } } diff --git a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs index f295dd7394..0c02f643b2 100644 --- a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs +++ b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.ConstrainedExecution; using System.Threading; -using Avalonia.Threading; using Avalonia.Utilities; using Avalonia.Win32.Interop; @@ -18,8 +17,8 @@ namespace Avalonia.Win32 SetSynchronizationContext(this); } - public override void Post(SendOrPostCallback d, object state) => _inner.Post(d, state); - public override void Send(SendOrPostCallback d, object state) => _inner.Send(d, state); + public override void Post(SendOrPostCallback d, object? state) => _inner.Post(d, state); + public override void Send(SendOrPostCallback d, object? state) => _inner.Send(d, state); #if !NET6_0_OR_GREATER [PrePrepareMethod] @@ -32,23 +31,15 @@ namespace Avalonia.Win32 public void Dispose() => SetSynchronizationContext(_inner); - public static IDisposable Use() + public static IDisposable? Use() { var current = Current; - if (current == null) - { - if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) - return null; - } - if (current is NonPumpingSyncContext) - return null; - - return new NonPumpingSyncContext(current); + return current is null or NonPumpingSyncContext ? null : new NonPumpingSyncContext(current); } internal class HelperImpl : NonPumpingLockHelper.IHelperImpl { - IDisposable NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use(); + IDisposable? NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use(); } } } diff --git a/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs b/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs index 9de105a3d5..7253b3c0ed 100644 --- a/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs +++ b/src/Windows/Avalonia.Win32/OffscreenParentWindow.cs @@ -1,17 +1,18 @@ using System; using System.ComponentModel; using System.Runtime.InteropServices; -using Avalonia.Platform; using Avalonia.Win32.Interop; namespace Avalonia.Win32 { - class OffscreenParentWindow + internal class OffscreenParentWindow { public static IntPtr Handle { get; } = CreateParentWindow(); - private static UnmanagedMethods.WndProc s_wndProcDelegate; + + private static UnmanagedMethods.WndProc? s_wndProcDelegate; + private static IntPtr CreateParentWindow() { - s_wndProcDelegate = new UnmanagedMethods.WndProc(ParentWndProc); + s_wndProcDelegate = ParentWndProc; var wndClassEx = new UnmanagedMethods.WNDCLASSEX { diff --git a/src/Windows/Avalonia.Win32/OleContext.cs b/src/Windows/Avalonia.Win32/OleContext.cs index e41423a334..897033e835 100644 --- a/src/Windows/Avalonia.Win32/OleContext.cs +++ b/src/Windows/Avalonia.Win32/OleContext.cs @@ -11,18 +11,16 @@ namespace Avalonia.Win32 { internal class OleContext { - private static OleContext s_current; + private static OleContext? s_current; - internal static OleContext Current + internal static OleContext? Current { get { if (!IsValidOleThread()) return null; - if (s_current == null) - s_current = new OleContext(); - return s_current; + return s_current ??= new OleContext(); } } @@ -41,7 +39,7 @@ namespace Avalonia.Win32 Thread.CurrentThread.GetApartmentState() == ApartmentState.STA; } - internal bool RegisterDragDrop(IPlatformHandle hwnd, IDropTarget target) + internal bool RegisterDragDrop(IPlatformHandle? hwnd, IDropTarget? target) { if (hwnd?.HandleDescriptor != "HWND" || target == null) { @@ -52,7 +50,7 @@ namespace Avalonia.Win32 return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK; } - internal bool UnregisterDragDrop(IPlatformHandle hwnd) + internal bool UnregisterDragDrop(IPlatformHandle? hwnd) { if (hwnd?.HandleDescriptor != "HWND") { diff --git a/src/Windows/Avalonia.Win32/OleDataObject.cs b/src/Windows/Avalonia.Win32/OleDataObject.cs index 79b55e4f77..247d0340c3 100644 --- a/src/Windows/Avalonia.Win32/OleDataObject.cs +++ b/src/Windows/Avalonia.Win32/OleDataObject.cs @@ -8,7 +8,6 @@ using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Runtime.Serialization.Formatters.Binary; using Avalonia.Input; -using Avalonia.MicroCom; using Avalonia.Utilities; using Avalonia.Win32.Interop; using MicroCom.Runtime; @@ -35,23 +34,23 @@ namespace Avalonia.Win32 return GetDataFormatsCore().Distinct(); } - public string GetText() + public string? GetText() { - return (string)GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT); + return (string?)GetDataFromOleHGLOBAL(DataFormats.Text, DVASPECT.DVASPECT_CONTENT); } - public IEnumerable GetFileNames() + public IEnumerable? GetFileNames() { - return (IEnumerable)GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT); + return (IEnumerable?)GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT); } - public object Get(string dataFormat) + public object? Get(string dataFormat) { return GetDataFromOleHGLOBAL(dataFormat, DVASPECT.DVASPECT_CONTENT); } [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We still use BinaryFormatter for WinForms dragndrop compatability")] - private unsafe object GetDataFromOleHGLOBAL(string format, DVASPECT aspect) + private unsafe object? GetDataFromOleHGLOBAL(string format, DVASPECT aspect) { var formatEtc = new Interop.FORMATETC(); formatEtc.cfFormat = ClipboardFormats.GetFormat(format); @@ -100,7 +99,7 @@ namespace Avalonia.Win32 private static IEnumerable ReadFileNamesFromHGlobal(IntPtr hGlobal) { - List files = new List(); + var files = new List(); int fileCount = UnmanagedMethods.DragQueryFile(hGlobal, -1, null, 0); if (fileCount > 0) { @@ -118,7 +117,7 @@ namespace Avalonia.Win32 return files; } - private static string ReadStringFromHGlobal(IntPtr hGlobal) + private static string? ReadStringFromHGlobal(IntPtr hGlobal) { IntPtr ptr = UnmanagedMethods.GlobalLock(hGlobal); try diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index 8bbdfe5fd9..a81652ffc2 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -1,5 +1,5 @@ using System; - +using System.Diagnostics.CodeAnalysis; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.MicroCom; @@ -13,16 +13,16 @@ namespace Avalonia.Win32 internal class OleDropTarget : CallbackBase, Win32Com.IDropTarget { private readonly IInputRoot _target; - private readonly ITopLevelImpl _tl; + private readonly ITopLevelImpl _topLevel; private readonly IDragDropDevice _dragDevice; - private IDataObject _currentDrag = null; + private IDataObject? _currentDrag; - public OleDropTarget(ITopLevelImpl tl, IInputRoot target) + public OleDropTarget(ITopLevelImpl topLevel, IInputRoot target, IDragDropDevice dragDevice) { - _dragDevice = AvaloniaLocator.Current.GetService(); - _tl = tl; + _topLevel = topLevel; _target = target; + _dragDevice = dragDevice; } public static DropEffect ConvertDropEffect(DragDropEffects operation) @@ -71,10 +71,11 @@ namespace Avalonia.Win32 unsafe void Win32Com.IDropTarget.DragEnter(Win32Com.IDataObject pDataObj, int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect) { - var dispatch = _tl?.Input; + var dispatch = _topLevel.Input; if (dispatch == null) { *pdwEffect= (int)DropEffect.None; + return; } SetDataObject(pDataObj); @@ -94,10 +95,11 @@ namespace Avalonia.Win32 unsafe void Win32Com.IDropTarget.DragOver(int grfKeyState, UnmanagedMethods.POINT pt, DropEffect* pdwEffect) { - var dispatch = _tl?.Input; - if (dispatch == null) + var dispatch = _topLevel.Input; + if (dispatch == null || _currentDrag is null) { *pdwEffect = (int)DropEffect.None; + return; } var args = new RawDragEvent( @@ -115,14 +117,20 @@ namespace Avalonia.Win32 void Win32Com.IDropTarget.DragLeave() { + var dispatch = _topLevel.Input; + if (dispatch == null || _currentDrag is null) + { + return; + } + try { - _tl?.Input(new RawDragEvent( + dispatch(new RawDragEvent( _dragDevice, RawDragEventType.DragLeave, _target, default, - null, + _currentDrag, DragDropEffects.None, RawInputModifiers.None )); @@ -137,10 +145,11 @@ namespace Avalonia.Win32 { try { - var dispatch = _tl?.Input; + var dispatch = _topLevel.Input; if (dispatch == null) { *pdwEffect = (int)DropEffect.None; + return; } SetDataObject(pDataObj); @@ -163,6 +172,7 @@ namespace Avalonia.Win32 } } + [MemberNotNull(nameof(_currentDrag))] private void SetDataObject(Win32Com.IDataObject pDataObj) { var newDrag = GetAvaloniaObjectFromCOM(pDataObj); @@ -178,9 +188,9 @@ namespace Avalonia.Win32 // OleDataObject keeps COM reference, so it should be disposed. if (_currentDrag is OleDataObject oleDragSource) { - oleDragSource?.Dispose(); - _currentDrag = null; + oleDragSource.Dispose(); } + _currentDrag = null; } private Point GetDragLocation(UnmanagedMethods.POINT dragPoint) @@ -194,7 +204,7 @@ namespace Avalonia.Win32 ReleaseDataObject(); } - public static unsafe IDataObject GetAvaloniaObjectFromCOM(Win32Com.IDataObject pDataObj) + public static IDataObject GetAvaloniaObjectFromCOM(Win32Com.IDataObject pDataObj) { if (pDataObj is null) { @@ -205,8 +215,7 @@ namespace Avalonia.Win32 return disposableDataObject; } - var dataObject = MicroComRuntime.TryUnwrapManagedObject(pDataObj) as DataObject; - if (dataObject is not null) + if (MicroComRuntime.TryUnwrapManagedObject(pDataObj) is DataObject dataObject) { return dataObject; } diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs index 6c951010c8..ffdd4fdfd6 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs @@ -14,7 +14,7 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory Display: AngleWin32EglDisplay { PlatformApi: AngleOptions.PlatformApi.DirectX11 } } && surface is IDirect3D11TexturePlatformSurface; - class RenderTargetWrapper : EglPlatformSurfaceRenderTargetBase + private class RenderTargetWrapper : EglPlatformSurfaceRenderTargetBase { private readonly AngleWin32EglDisplay _angle; private readonly IDirect3D11TextureRenderTarget _target; @@ -31,8 +31,8 @@ internal class AngleD3DTextureFeature : IGlPlatformSurfaceRenderTargetFactory { var success = false; var contextLock = Context.EnsureCurrent(); - IDirect3D11TextureRenderTargetRenderSession session = null; - EglSurface surface = null; + IDirect3D11TextureRenderTargetRenderSession? session = null; + EglSurface? surface = null; try { try diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs index 4e00bc2c72..2fd2e0f33c 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs @@ -22,7 +22,7 @@ namespace Avalonia.OpenGL.Angle } [GetProcAddress("eglCreateDeviceANGLE", true)] - public partial IntPtr CreateDeviceANGLE(int deviceType, IntPtr nativeDevice, int[] attribs); + public partial IntPtr CreateDeviceANGLE(int deviceType, IntPtr nativeDevice, int[]? attribs); [GetProcAddress("eglReleaseDeviceANGLE", true)] public partial void ReleaseDeviceANGLE(IntPtr device); diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs index b0fa76fda2..6bbfde35e1 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs @@ -1,8 +1,5 @@ -#nullable enable using System; -using System.Threading; using Avalonia.OpenGL; -using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; using Avalonia.Platform; using Avalonia.Win32.DirectX; @@ -15,9 +12,12 @@ namespace Avalonia.Win32.OpenGl.Angle; internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture { private readonly EglContext _context; - private ID3D11Texture2D _texture2D; - private EglSurface _eglSurface; - private IDXGIKeyedMutex _mutex; + private ID3D11Texture2D? _texture2D; + private EglSurface? _eglSurface; + private IDXGIKeyedMutex? _mutex; + + private IDXGIKeyedMutex Mutex + => _mutex ?? throw new ObjectDisposedException(nameof(AngleExternalMemoryD3D11Texture2D)); public unsafe AngleExternalMemoryD3D11Texture2D(EglContext context, ID3D11Texture2D texture2D, PlatformGraphicsExternalImageProperties props) { @@ -40,14 +40,14 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture int temp = 0; gl.GenTextures(1, &temp); TextureId = temp; - gl.BindTexture(GlConsts.GL_TEXTURE_2D, TextureId); + gl.BindTexture(GL_TEXTURE_2D, TextureId); if (_context.Display.EglInterface.BindTexImage(_context.Display.Handle, _eglSurface.DangerousGetHandle(), EGL_BACK_BUFFER) == 0) throw OpenGlException.GetFormattedException("eglBindTexImage", _context.Display.EglInterface); } - + public void Dispose() { @@ -56,17 +56,15 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture _context.GlInterface.DeleteTexture(TextureId); TextureId = 0; _eglSurface?.Dispose(); - _eglSurface = null!; + _eglSurface = null; _texture2D?.Dispose(); - _texture2D = null!; + _texture2D = null; _mutex?.Dispose(); - _mutex = null!; + _mutex = null; } - - public void AcquireKeyedMutex(uint key) => _mutex.AcquireSync(key, int.MaxValue); - - public void ReleaseKeyedMutex(uint key) => _mutex.ReleaseSync(key); + public void AcquireKeyedMutex(uint key) => Mutex.AcquireSync(key, int.MaxValue); + public void ReleaseKeyedMutex(uint key) => Mutex.ReleaseSync(key); public int TextureId { get; private set; } public int InternalFormat { get; } @@ -75,7 +73,7 @@ internal class AngleExternalMemoryD3D11Texture2D : IGlExternalImageTexture internal class AngleExternalMemoryD3D11ExportedTexture2D : AngleExternalMemoryD3D11Texture2D, IGlExportableExternalImageTexture { - static IPlatformHandle GetHandle(ID3D11Texture2D texture2D) + private static IPlatformHandle GetHandle(ID3D11Texture2D texture2D) { using var resource = texture2D.QueryInterface(); return new PlatformHandle(resource.SharedHandle, diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs index a7b52e953e..cad43e5d45 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Avalonia.Controls.Documents; using Avalonia.OpenGL; using Avalonia.OpenGL.Egl; using Avalonia.Platform; @@ -93,8 +91,8 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I return default; } - public byte[] DeviceLuid { get; } - public byte[] DeviceUuid { get; } + public byte[]? DeviceLuid { get; } + public byte[]? DeviceUuid => null; public void Dispose() { diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs index 53bf2fb8b1..770a27386f 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs @@ -1,4 +1,3 @@ -#nullable enable annotations using System; using System.Collections.Generic; using System.ComponentModel; @@ -97,7 +96,7 @@ namespace Avalonia.Win32.OpenGl.Angle DirectXUnmanagedMethods.D3D11CreateDevice(chosenAdapter?.GetNativeIntPtr() ?? IntPtr.Zero, D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_UNKNOWN, IntPtr.Zero, 0, featureLevels, (uint)featureLevels.Length, - 7, out pD3dDevice, out var featureLevel, null); + 7, out pD3dDevice, out _, null); if (pD3dDevice == IntPtr.Zero) diff --git a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs index a4d1ea457a..8ee6d286d1 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Avalonia.Logging; using Avalonia.OpenGL; @@ -12,11 +13,14 @@ namespace Avalonia.Win32.OpenGl.Angle; internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphicsOpenGlContextFactory { private readonly Win32AngleEglInterface _egl; - private AngleWin32EglDisplay _sharedDisplay; - private EglContext _sharedContext; - public bool UsesSharedContext => PlatformApi == AngleOptions.PlatformApi.DirectX9; + private readonly AngleWin32EglDisplay? _sharedDisplay; + private EglContext? _sharedContext; + + [MemberNotNullWhen(true, nameof(_sharedDisplay))] + public bool UsesSharedContext => _sharedDisplay is not null; + + public AngleOptions.PlatformApi PlatformApi { get; } - public AngleOptions.PlatformApi PlatformApi { get; } = AngleOptions.PlatformApi.DirectX11; public IPlatformGraphicsContext CreateContext() { if (UsesSharedContext) @@ -72,7 +76,7 @@ internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphics } - public static AngleWin32PlatformGraphics TryCreate(AngleOptions options) + public static AngleWin32PlatformGraphics? TryCreate(AngleOptions? options) { Win32AngleEglInterface egl; try @@ -109,7 +113,7 @@ internal class AngleWin32PlatformGraphics : IPlatformGraphics, IPlatformGraphics } else { - AngleWin32EglDisplay sharedDisplay = null; + AngleWin32EglDisplay? sharedDisplay = null; try { sharedDisplay = AngleWin32EglDisplay.CreateD3D9Display(egl); diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs b/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs index b4002d8bc7..999818d709 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglContext.cs @@ -7,22 +7,22 @@ using Avalonia.Platform; using Avalonia.Reactive; using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; -using static Avalonia.Win32.OpenGl.WglConsts; namespace Avalonia.Win32.OpenGl { - class WglContext : IGlContext + internal class WglContext : IGlContext { - private object _lock = new object(); - private readonly WglContext _sharedWith; + private readonly object _lock = new(); + private readonly WglContext? _sharedWith; private readonly IntPtr _context; private readonly IntPtr _hWnd; private readonly IntPtr _dc; private readonly int _pixelFormat; private readonly PixelFormatDescriptor _formatDescriptor; + public IntPtr Handle => _context; - public WglContext(WglContext sharedWith, GlVersion version, IntPtr context, IntPtr hWnd, IntPtr dc, int pixelFormat, + public WglContext(WglContext? sharedWith, GlVersion version, IntPtr context, IntPtr hWnd, IntPtr dc, int pixelFormat, PixelFormatDescriptor formatDescriptor) { Version = version; @@ -54,7 +54,7 @@ namespace Avalonia.Win32.OpenGl public GlVersion Version { get; } public GlInterface GlInterface { get; } - public int SampleCount { get; } + public int SampleCount => 0; public int StencilSize { get; } private bool IsCurrent => wglGetCurrentContext() == _context && wglGetCurrentDC() == _dc; @@ -97,12 +97,12 @@ namespace Avalonia.Win32.OpenGl } public bool CanCreateSharedContext => true; - public IGlContext CreateSharedContext(IEnumerable preferredVersions = null) + public IGlContext? CreateSharedContext(IEnumerable? preferredVersions = null) { var versions = preferredVersions?.Append(Version).ToArray() ?? new[] { Version }; return WglDisplay.CreateContext(versions, _sharedWith ?? this); } - public object TryGetFeature(Type featureType) => null; + public object? TryGetFeature(Type featureType) => null; } } diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs index 9a1963a97a..e207bc23ab 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Avalonia.OpenGL; using Avalonia.Threading; @@ -19,29 +20,31 @@ namespace Avalonia.Win32.OpenGl private static int _defaultPixelFormat; public static IntPtr OpenGl32Handle = LoadLibrary("opengl32"); - private delegate bool WglChoosePixelFormatARBDelegate(IntPtr hdc, int[] piAttribIList, float[] pfAttribFList, + private delegate bool WglChoosePixelFormatARBDelegate(IntPtr hdc, int[]? piAttribIList, float[]? pfAttribFList, int nMaxFormats, int[] piFormats, out int nNumFormats); - private static WglChoosePixelFormatARBDelegate WglChoosePixelFormatArb; + private static WglChoosePixelFormatARBDelegate? s_wglChoosePixelFormatArb; - private delegate IntPtr WglCreateContextAttribsARBDelegate(IntPtr hDC, IntPtr hShareContext, int[] attribList); + private delegate IntPtr WglCreateContextAttribsARBDelegate(IntPtr hDC, IntPtr hShareContext, int[]? attribList); - private static WglCreateContextAttribsARBDelegate WglCreateContextAttribsArb; + private static WglCreateContextAttribsARBDelegate? s_wglCreateContextAttribsArb; private delegate void GlDebugMessageCallbackDelegate(IntPtr callback, IntPtr userParam); - private static GlDebugMessageCallbackDelegate GlDebugMessageCallback; + private static GlDebugMessageCallbackDelegate? s_glDebugMessageCallback; private delegate void DebugCallbackDelegate(int source, int type, int id, int severity, int len, IntPtr message, IntPtr userParam); - - static bool Initialize() - { - if (!_initialized.HasValue) - _initialized = InitializeCore(); - return _initialized.Value; - } - static bool InitializeCore() + + [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))] + [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))] + [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))] + private static bool Initialize() => _initialized ??= InitializeCore(); + + [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))] + [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))] + [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))] + private static bool InitializeCore() { Dispatcher.UIThread.VerifyAccess(); _bootstrapWindow = WglGdiResourceManager.CreateOffscreenWindow(); @@ -64,20 +67,20 @@ namespace Avalonia.Win32.OpenGl return false; wglMakeCurrent(_bootstrapDc, _bootstrapContext); - WglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer( + s_wglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer( wglGetProcAddress("wglCreateContextAttribsARB")); - WglChoosePixelFormatArb = + s_wglChoosePixelFormatArb = Marshal.GetDelegateForFunctionPointer( wglGetProcAddress("wglChoosePixelFormatARB")); - GlDebugMessageCallback = + s_glDebugMessageCallback = Marshal.GetDelegateForFunctionPointer( wglGetProcAddress("glDebugMessageCallback")); var formats = new int[1]; - WglChoosePixelFormatArb(_bootstrapDc, new int[] + s_wglChoosePixelFormatArb(_bootstrapDc, new int[] { WGL_DRAW_TO_WINDOW_ARB, 1, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, @@ -106,12 +109,12 @@ namespace Avalonia.Win32.OpenGl Console.Error.WriteLine(err); } - public static WglContext CreateContext(GlVersion[] versions, IGlContext share) + public static WglContext? CreateContext(GlVersion[] versions, IGlContext? share) { if (!Initialize()) return null; - var shareContext = (WglContext)share; + var shareContext = share as WglContext; using (new WglRestoreContext(_bootstrapDc, _bootstrapContext, null)) { @@ -125,7 +128,7 @@ namespace Avalonia.Win32.OpenGl IntPtr context; using (shareContext?.Lock()) { - context = WglCreateContextAttribsArb(dc, shareContext?.Handle ?? IntPtr.Zero, + context = s_wglCreateContextAttribsArb(dc, shareContext?.Handle ?? IntPtr.Zero, new[] { // major @@ -142,7 +145,7 @@ namespace Avalonia.Win32.OpenGl } using(new WglRestoreContext(dc, context, null)) - GlDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); + s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); if (context != IntPtr.Zero) return new WglContext(shareContext, version, context, window, dc, _defaultPixelFormat, _defaultPfd); diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs b/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs index ed40488c70..86143d078d 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs @@ -17,45 +17,69 @@ namespace Avalonia.Win32.OpenGl; internal class WglGdiResourceManager { - class GetDCOp + private class GetDCOp { - public IntPtr Window; - public TaskCompletionSource Result; + public readonly IntPtr Window; + public readonly TaskCompletionSource Result; + + public GetDCOp(IntPtr window, TaskCompletionSource result) + { + Window = window; + Result = result; + } } - class ReleaseDCOp + private class ReleaseDCOp { - public IntPtr Window; - public IntPtr DC; - public TaskCompletionSource Result; + public readonly IntPtr Window; + public readonly IntPtr DC; + public readonly TaskCompletionSource Result; + + public ReleaseDCOp(IntPtr window, IntPtr dc, TaskCompletionSource result) + { + Window = window; + DC = dc; + Result = result; + } } - - class CreateWindowOp + + private class CreateWindowOp { - public TaskCompletionSource Result; + public readonly TaskCompletionSource Result; + + public CreateWindowOp(TaskCompletionSource result) + { + Result = result; + } } - class DestroyWindowOp + private class DestroyWindowOp { - public IntPtr Window; - public TaskCompletionSource Result; + public readonly IntPtr Window; + public readonly TaskCompletionSource Result; + + public DestroyWindowOp(IntPtr window, TaskCompletionSource result) + { + Window = window; + Result = result; + } } - private static readonly Queue s_Queue = new(); - private static readonly AutoResetEvent s_Event = new(false); - private static readonly ushort s_WindowClass; + private static readonly Queue s_queue = new(); + private static readonly AutoResetEvent s_event = new(false); + private static readonly ushort s_windowClass; private static readonly UnmanagedMethods.WndProc s_wndProcDelegate = WndProc; - static void Worker() + private static void Worker() { while (true) { - s_Event.WaitOne(); - lock (s_Queue) + s_event.WaitOne(); + lock (s_queue) { - if(s_Queue.Count == 0) + if(s_queue.Count == 0) continue; - var job = s_Queue.Dequeue(); + var job = s_queue.Dequeue(); if (job is GetDCOp getDc) getDc.Result.TrySetResult(UnmanagedMethods.GetDC(getDc.Window)); else if (job is ReleaseDCOp releaseDc) @@ -66,7 +90,7 @@ internal class WglGdiResourceManager else if (job is CreateWindowOp createWindow) createWindow.Result.TrySetResult(UnmanagedMethods.CreateWindowEx( 0, - s_WindowClass, + s_windowClass, null, (int)UnmanagedMethods.WindowStyles.WS_OVERLAPPEDWINDOW, 0, @@ -97,16 +121,15 @@ internal class WglGdiResourceManager style = (int)UnmanagedMethods.ClassStyles.CS_OWNDC }; - s_WindowClass = UnmanagedMethods.RegisterClassEx(ref wndClassEx); + s_windowClass = UnmanagedMethods.RegisterClassEx(ref wndClassEx); var th = new Thread(Worker) { IsBackground = true, Name = "Win32 OpenGL HDC manager" }; // This makes CLR to automatically pump the event queue from WaitOne th.SetApartmentState(ApartmentState.STA); th.Start(); } - - - - static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + + + private static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); } @@ -114,53 +137,36 @@ internal class WglGdiResourceManager public static IntPtr CreateOffscreenWindow() { var tcs = new TaskCompletionSource(); - lock(s_Queue) - s_Queue.Enqueue(new CreateWindowOp() - { - Result = tcs - }); - s_Event.Set(); + lock (s_queue) + s_queue.Enqueue(new CreateWindowOp(tcs)); + s_event.Set(); return tcs.Task.Result; } public static IntPtr GetDC(IntPtr hWnd) { var tcs = new TaskCompletionSource(); - lock(s_Queue) - s_Queue.Enqueue(new GetDCOp - { - Window = hWnd, - Result = tcs - }); - s_Event.Set(); + lock (s_queue) + s_queue.Enqueue(new GetDCOp(hWnd, tcs)); + s_event.Set(); return tcs.Task.Result; } public static void ReleaseDC(IntPtr hWnd, IntPtr hDC) { - var tcs = new TaskCompletionSource(); - lock(s_Queue) - s_Queue.Enqueue(new ReleaseDCOp() - { - Window = hWnd, - DC = hDC, - Result = tcs - }); - s_Event.Set(); + var tcs = new TaskCompletionSource(); + lock (s_queue) + s_queue.Enqueue(new ReleaseDCOp(hWnd, hDC, tcs)); + s_event.Set(); tcs.Task.Wait(); } public static void DestroyWindow(IntPtr hWnd) { - var tcs = new TaskCompletionSource(); - lock(s_Queue) - s_Queue.Enqueue(new DestroyWindowOp() - { - Window = hWnd, - Result = tcs - }); - s_Event.Set(); + var tcs = new TaskCompletionSource(); + lock (s_queue) + s_queue.Enqueue(new DestroyWindowOp(hWnd, tcs)); + s_event.Set(); tcs.Task.Wait(); - } } diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs b/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs index 39dd330d52..61b932e9c7 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs @@ -6,27 +6,31 @@ using Avalonia.Platform; namespace Avalonia.Win32.OpenGl { - class WglPlatformOpenGlInterface : IPlatformGraphics + internal class WglPlatformOpenGlInterface : IPlatformGraphics { public WglContext PrimaryContext { get; } public bool UsesSharedContext => false; IPlatformGraphicsContext IPlatformGraphics.CreateContext() => CreateContext(); public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException(); - - public IGlContext CreateContext() => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, null); - private WglPlatformOpenGlInterface(WglContext primary) + public IGlContext CreateContext() + => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, null) + ?? throw new OpenGlException("Unable to create additional WGL context"); + + private WglPlatformOpenGlInterface(WglContext primary) { PrimaryContext = primary; } - public static WglPlatformOpenGlInterface TryCreate() + public static WglPlatformOpenGlInterface? TryCreate() { try { var opts = AvaloniaLocator.Current.GetService() ?? new Win32PlatformOptions(); - var primary = WglDisplay.CreateContext(opts.WglProfiles.ToArray(), null); - return new WglPlatformOpenGlInterface(primary); + if (WglDisplay.CreateContext(opts.WglProfiles.ToArray(), null) is { } primary) + { + return new WglPlatformOpenGlInterface(primary); + } } catch (Exception e) { diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs b/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs index b145ffbb37..ee0934af7d 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs @@ -8,11 +8,11 @@ namespace Avalonia.Win32.OpenGl { internal class WglRestoreContext : IDisposable { - private readonly object _monitor; + private readonly object? _monitor; private readonly IntPtr _oldDc; private readonly IntPtr _oldContext; - public WglRestoreContext(IntPtr gc, IntPtr context, object monitor, bool takeMonitor = true) + public WglRestoreContext(IntPtr gc, IntPtr context, object? monitor, bool takeMonitor = true) { _monitor = monitor; _oldDc = wglGetCurrentDC(); diff --git a/src/Windows/Avalonia.Win32/PopupImpl.cs b/src/Windows/Avalonia.Win32/PopupImpl.cs index 3a56af12f0..75c1a2d564 100644 --- a/src/Windows/Avalonia.Win32/PopupImpl.cs +++ b/src/Windows/Avalonia.Win32/PopupImpl.cs @@ -5,9 +5,9 @@ using Avalonia.Win32.Interop; namespace Avalonia.Win32 { - class PopupImpl : WindowImpl, IPopupImpl + internal class PopupImpl : WindowImpl, IPopupImpl { - private readonly IWindowBaseImpl _parent; + private readonly IWindowBaseImpl? _parent; private bool _dropShadowHint = true; private Size? _maxAutoSize; @@ -92,7 +92,7 @@ namespace Avalonia.Win32 IntPtr.Zero); s_parentHandle = IntPtr.Zero; - PopupImpl.EnableBoxShadow(result, _dropShadowHint); + EnableBoxShadow(result, _dropShadowHint); return result; } @@ -113,7 +113,7 @@ namespace Avalonia.Win32 // This is needed because we are calling virtual methods from constructors // One fabulous design decision leads to another, I guess - static IWindowBaseImpl SaveParentHandle(IWindowBaseImpl parent) + private static IWindowBaseImpl SaveParentHandle(IWindowBaseImpl parent) { s_parentHandle = parent.Handle.Handle; return parent; @@ -126,7 +126,7 @@ namespace Avalonia.Win32 } - private PopupImpl(IWindowBaseImpl parent, bool dummy) : base() + private PopupImpl(IWindowBaseImpl parent, bool dummy) { _parent = parent; PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(parent, MoveResize)); @@ -159,10 +159,7 @@ namespace Avalonia.Win32 { _dropShadowHint = enabled; - if (Handle != null) - { - PopupImpl.EnableBoxShadow(Handle.Handle, enabled); - } + EnableBoxShadow(Handle.Handle, enabled); } public IPopupPositioner PopupPositioner { get; } diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs index f3754cd58f..69431c7ff6 100644 --- a/src/Windows/Avalonia.Win32/ScreenImpl.cs +++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using Avalonia.Metadata; using Avalonia.Platform; -using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 @@ -11,12 +10,15 @@ namespace Avalonia.Win32 [Unstable] public class ScreenImpl : IScreenImpl { + private Screen[]? _allScreens; + + /// public int ScreenCount { get => GetSystemMetrics(SystemMetric.SM_CMONITORS); } - private Screen[] _allScreens; + /// public IReadOnlyList AllScreens { get @@ -38,7 +40,7 @@ namespace Avalonia.Win32 if (method != IntPtr.Zero) { GetDpiForMonitor(monitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var x, out _); - dpi = (double)x; + dpi = x; } else { @@ -74,7 +76,8 @@ namespace Avalonia.Win32 _allScreens = null; } - public Screen ScreenFromWindow(IWindowBaseImpl window) + /// + public Screen? ScreenFromWindow(IWindowBaseImpl window) { var handle = window.Handle.Handle; @@ -83,7 +86,8 @@ namespace Avalonia.Win32 return FindScreenByHandle(monitor); } - public Screen ScreenFromPoint(PixelPoint point) + /// + public Screen? ScreenFromPoint(PixelPoint point) { var monitor = MonitorFromPoint(new POINT { @@ -94,7 +98,8 @@ namespace Avalonia.Win32 return FindScreenByHandle(monitor); } - public Screen ScreenFromRect(PixelRect rect) + /// + public Screen? ScreenFromRect(PixelRect rect) { var monitor = MonitorFromRect(new RECT { @@ -107,7 +112,7 @@ namespace Avalonia.Win32 return FindScreenByHandle(monitor); } - private Screen FindScreenByHandle(IntPtr handle) + private Screen? FindScreenByHandle(IntPtr handle) { return AllScreens.Cast().FirstOrDefault(m => m.Handle == handle); } diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs index fe920ff1a1..8a10c6d2e1 100644 --- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs +++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs @@ -11,8 +11,6 @@ using Avalonia.Styling; using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; -#nullable enable - namespace Avalonia.Win32 { [Unstable] @@ -25,9 +23,9 @@ namespace Avalonia.Win32 private IconImpl? _icon; private string? _tooltipText; private readonly Win32NativeToManagedMenuExporter _exporter; - private static readonly Dictionary s_trayIcons = new Dictionary(); + private static readonly Dictionary s_trayIcons = new(); private bool _disposedValue; - private static readonly uint WM_TASKBARCREATED = UnmanagedMethods.RegisterWindowMessage("TaskbarCreated"); + private static readonly uint WM_TASKBARCREATED = RegisterWindowMessage("TaskbarCreated"); public TrayIconImpl() { @@ -62,17 +60,20 @@ namespace Avalonia.Win32 } } + /// public void SetIcon(IWindowIconImpl? icon) { _icon = icon as IconImpl; UpdateIcon(); } + /// public void SetIsVisible(bool visible) { UpdateIcon(!visible); } + /// public void SetToolTipText(string? text) { _tooltipText = text; @@ -209,8 +210,11 @@ namespace Avalonia.Win32 private void MoveResize(PixelPoint position, Size size, double scaling) { - PlatformImpl!.Move(position); - PlatformImpl!.Resize(size, PlatformResizeReason.Layout); + if (PlatformImpl is { } platformImpl) + { + platformImpl.Move(position); + platformImpl.Resize(size, PlatformResizeReason.Layout); + } } protected override void ArrangeCore(Rect finalRect) @@ -221,7 +225,7 @@ namespace Avalonia.Win32 { Anchor = PopupAnchor.TopLeft, Gravity = PopupGravity.BottomRight, - AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.Scaling, new Size(1, 1)), + AnchorRectangle = new Rect(Position.ToPoint(Screens.Primary?.Scaling ?? 1.0), new Size(1, 1)), Size = finalRect.Size, ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY, }); @@ -247,18 +251,22 @@ namespace Avalonia.Win32 { get { - var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft; - var size = _hiddenWindow.Screens.Primary.Bounds.Size; - return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.Scaling, size.Height * _hiddenWindow.Screens.Primary.Scaling); + if (_hiddenWindow.Screens.Primary is { } screen) + { + var point = screen.Bounds.TopLeft; + var size = screen.Bounds.Size; + return new Rect(point.X, point.Y, size.Width * screen.Scaling, size.Height * screen.Scaling); + } + return default; } } public void MoveAndResize(Point devicePoint, Size virtualSize) { - _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.Scaling); + _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, Scaling); } - public double Scaling => _hiddenWindow.Screens.Primary.Scaling; + public double Scaling => _hiddenWindow.Screens.Primary?.Scaling ?? 1.0; } } diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs index ab6de1a027..c26ce5fd45 100644 --- a/src/Windows/Avalonia.Win32/Win32GlManager.cs +++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs @@ -1,6 +1,4 @@ using Avalonia.OpenGL; -using Avalonia.OpenGL.Angle; -using Avalonia.OpenGL.Egl; using Avalonia.Platform; using Avalonia.Win32.DirectX; using Avalonia.Win32.OpenGl; @@ -11,16 +9,19 @@ namespace Avalonia.Win32 { static class Win32GlManager { - - public static IPlatformGraphics Initialize() + public static IPlatformGraphics? Initialize() { var gl = InitializeCore(); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); + + if (gl is not null) + { + AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); + } + return gl; } - static IPlatformGraphics InitializeCore() + private static IPlatformGraphics? InitializeCore() { var opts = AvaloniaLocator.Current.GetService() ?? new Win32PlatformOptions(); @@ -55,7 +56,5 @@ namespace Avalonia.Win32 return null; } - - } } diff --git a/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs b/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs index fd05e780bf..620cd64e79 100644 --- a/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs +++ b/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs @@ -1,13 +1,13 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Avalonia.Controls.Platform; using Avalonia.Platform; -using Avalonia.VisualTree; using Avalonia.Win32.Interop; namespace Avalonia.Win32 { - class Win32NativeControlHost : INativeControlHostImpl + internal class Win32NativeControlHost : INativeControlHostImpl { private readonly bool _useLayeredWindow; public WindowImpl Window { get; } @@ -18,7 +18,7 @@ namespace Avalonia.Win32 Window = window; } - void AssertCompatible(IPlatformHandle handle) + private void AssertCompatible(IPlatformHandle handle) { if (!IsCompatibleWith(handle)) throw new ArgumentException($"Don't know what to do with {handle.HandleDescriptor}"); @@ -33,7 +33,7 @@ namespace Avalonia.Win32 public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) { var holder = new DumbWindow(_useLayeredWindow, Window.Handle.Handle); - Win32NativeControlAttachment attachment = null; + Win32NativeControlAttachment? attachment = null; try { var child = create(holder); @@ -46,7 +46,7 @@ namespace Avalonia.Win32 catch { attachment?.Dispose(); - holder?.Destroy(); + holder.Destroy(); throw; } } @@ -60,13 +60,13 @@ namespace Avalonia.Win32 public bool IsCompatibleWith(IPlatformHandle handle) => handle.HandleDescriptor == "HWND"; - class DumbWindow : IDisposable, INativeControlHostDestroyableControlHandle + private class DumbWindow : IDisposable, INativeControlHostDestroyableControlHandle { public IntPtr Handle { get;} public string HandleDescriptor => "HWND"; public void Destroy() => Dispose(); - UnmanagedMethods.WndProc _wndProcDelegate; + private readonly UnmanagedMethods.WndProc _wndProcDelegate; private readonly string _className; public DumbWindow(bool layered = false, IntPtr? parent = null) @@ -103,9 +103,7 @@ namespace Avalonia.Win32 UnmanagedMethods.LayeredWindowFlags.LWA_ALPHA); } - - - protected virtual unsafe IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + private static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); } @@ -128,11 +126,11 @@ namespace Avalonia.Win32 } } - class Win32NativeControlAttachment : INativeControlHostControlTopLevelAttachment + private class Win32NativeControlAttachment : INativeControlHostControlTopLevelAttachment { - private DumbWindow _holder; - private IPlatformHandle _child; - private Win32NativeControlHost _attachedTo; + private DumbWindow? _holder; + private IPlatformHandle? _child; + private Win32NativeControlHost? _attachedTo; public Win32NativeControlAttachment(DumbWindow holder, IPlatformHandle child) { @@ -142,7 +140,8 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(child.Handle, UnmanagedMethods.ShowWindowCommand.Show); } - void CheckDisposed() + [MemberNotNull(nameof(_holder))] + private void CheckDisposed() { if (_holder == null) throw new ObjectDisposedException(nameof(Win32NativeControlAttachment)); @@ -158,13 +157,13 @@ namespace Avalonia.Win32 _attachedTo = null; } - public INativeControlHostImpl AttachedTo + public INativeControlHostImpl? AttachedTo { get => _attachedTo; set { CheckDisposed(); - _attachedTo = (Win32NativeControlHost) value; + _attachedTo = value as Win32NativeControlHost; if (_attachedTo == null) { UnmanagedMethods.ShowWindow(_holder.Handle, UnmanagedMethods.ShowWindowCommand.Hide); @@ -179,6 +178,7 @@ namespace Avalonia.Win32 public void HideWithSize(Size size) { + CheckDisposed(); UnmanagedMethods.SetWindowPos(_holder.Handle, IntPtr.Zero, -100, -100, 1, 1, UnmanagedMethods.SetWindowPosFlags.SWP_HIDEWINDOW | @@ -198,8 +198,12 @@ namespace Avalonia.Win32 bounds *= _attachedTo.Window.RenderScaling; var pixelRect = new PixelRect((int)bounds.X, (int)bounds.Y, Math.Max(1, (int)bounds.Width), Math.Max(1, (int)bounds.Height)); - - UnmanagedMethods.MoveWindow(_child.Handle, 0, 0, pixelRect.Width, pixelRect.Height, true); + + if (_child is not null) + { + UnmanagedMethods.MoveWindow(_child.Handle, 0, 0, pixelRect.Width, pixelRect.Height, true); + } + UnmanagedMethods.SetWindowPos(_holder.Handle, IntPtr.Zero, pixelRect.X, pixelRect.Y, pixelRect.Width, pixelRect.Height, UnmanagedMethods.SetWindowPosFlags.SWP_SHOWWINDOW diff --git a/src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs b/src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs index fdf36206d0..46cdf66653 100644 --- a/src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs +++ b/src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs @@ -1,12 +1,7 @@ -using System.Collections.Generic; -using Avalonia.Reactive; +using Avalonia.Reactive; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Platform; -using Avalonia.Media.Imaging; -using Avalonia.Utilities; - -#nullable enable namespace Avalonia.Win32 { @@ -19,7 +14,7 @@ namespace Avalonia.Win32 _nativeMenu = nativeMenu; } - private AvaloniaList Populate(NativeMenu nativeMenu) + private static AvaloniaList Populate(NativeMenu nativeMenu) { var result = new AvaloniaList(); diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index c34be9008a..4b327ed02a 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -17,12 +17,10 @@ using Avalonia.Rendering.Composition; using Avalonia.Threading; using Avalonia.Utilities; using Avalonia.Win32.Input; -using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia { -#nullable enable public static class Win32ApplicationExtensions { public static AppBuilder UseWin32(this AppBuilder builder) @@ -106,17 +104,19 @@ namespace Avalonia public IPlatformGraphics? CustomPlatformGraphics { get; set; } } } -#nullable restore namespace Avalonia.Win32 { public class Win32Platform : IPlatformThreadingInterface, IWindowingPlatform, IPlatformIconLoader, IPlatformLifetimeEventsImpl { - private static readonly Win32Platform s_instance = new Win32Platform(); - private static Thread _uiThread; - private UnmanagedMethods.WndProc _wndProcDelegate; + private static readonly Win32Platform s_instance = new(); + private static Thread? s_uiThread; + private static Win32PlatformOptions? s_options; + private static Compositor? s_compositor; + + private WndProc? _wndProcDelegate; private IntPtr _hwnd; - private readonly List _delegates = new List(); + private readonly List _delegates = new(); public Win32Platform() { @@ -135,9 +135,12 @@ namespace Avalonia.Win32 public static Version WindowsVersion { get; } = RtlGetVersion(); internal static bool UseOverlayPopups => Options.OverlayPopups; - public static Win32PlatformOptions Options { get; private set; } - internal static Compositor Compositor { get; private set; } + public static Win32PlatformOptions Options + => s_options ?? throw new InvalidOperationException($"{nameof(Win32Platform)} hasn't been initialized"); + + internal static Compositor Compositor + => s_compositor ?? throw new InvalidOperationException($"{nameof(Win32Platform)} hasn't been initialized"); public static void Initialize() { @@ -146,7 +149,7 @@ namespace Avalonia.Win32 public static void Initialize(Win32PlatformOptions options) { - Options = options; + s_options = options; var renderTimer = options.ShouldRenderOnUIThread ? new UiThreadRenderTimer(60) : new DefaultRenderTimer(60); AvaloniaLocator.CurrentMutable @@ -171,26 +174,24 @@ namespace Avalonia.Win32 .Bind().ToConstant(new WindowsMountedVolumeInfoProvider()) .Bind().ToConstant(s_instance); - _uiThread = Thread.CurrentThread; + s_uiThread = Thread.CurrentThread; - var platformGraphics = options?.CustomPlatformGraphics + var platformGraphics = options.CustomPlatformGraphics ?? Win32GlManager.Initialize(); if (OleContext.Current != null) AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); - Compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService(), platformGraphics); + s_compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService(), platformGraphics); } public bool HasMessages() { - UnmanagedMethods.MSG msg; - return PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); + return PeekMessage(out _, IntPtr.Zero, 0, 0, 0); } public void ProcessMessage() { - if (GetMessage(out var msg, IntPtr.Zero, 0, 0) > -1) { TranslateMessage(ref msg); @@ -222,8 +223,7 @@ namespace Avalonia.Win32 public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action callback) { - UnmanagedMethods.TimerProc timerDelegate = - (hWnd, uMsg, nIDEvent, dwTime) => callback(); + TimerProc timerDelegate = (_, _, _, _) => callback(); IntPtr handle = SetTimer( IntPtr.Zero, @@ -253,11 +253,11 @@ namespace Avalonia.Win32 new IntPtr(SignalL)); } - public bool CurrentThreadIsLoopThread => _uiThread == Thread.CurrentThread; + public bool CurrentThreadIsLoopThread => s_uiThread == Thread.CurrentThread; - public event Action Signaled; + public event Action? Signaled; - public event EventHandler ShutdownRequested; + public event EventHandler? ShutdownRequested; [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) @@ -301,11 +301,11 @@ namespace Avalonia.Win32 private void CreateMessageWindow() { // Ensure that the delegate doesn't get garbage collected by storing it as a field. - _wndProcDelegate = new UnmanagedMethods.WndProc(WndProc); + _wndProcDelegate = WndProc; - UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX + WNDCLASSEX wndClassEx = new WNDCLASSEX { - cbSize = Marshal.SizeOf(), + cbSize = Marshal.SizeOf(), lpfnWndProc = _wndProcDelegate, hInstance = GetModuleHandle(null), lpszClassName = "AvaloniaMessageWindow " + Guid.NewGuid(), @@ -326,7 +326,7 @@ namespace Avalonia.Win32 } } - public ITrayIconImpl CreateTrayIcon () + public ITrayIconImpl CreateTrayIcon() { return new TrayIconImpl(); } diff --git a/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs b/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs index 0310c4bfad..c5f7f17b32 100644 --- a/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs +++ b/src/Windows/Avalonia.Win32/Win32PlatformSettings.cs @@ -1,8 +1,6 @@ using System; -using System.Runtime.InteropServices; using Avalonia.Input; using Avalonia.Platform; -using Avalonia.Win32.Interop; using Avalonia.Win32.WinRT; using static Avalonia.Win32.Interop.UnmanagedMethods; @@ -10,14 +8,14 @@ namespace Avalonia.Win32; internal class Win32PlatformSettings : DefaultPlatformSettings { - private PlatformColorValues _lastColorValues; + private PlatformColorValues? _lastColorValues; public override Size GetTapSize(PointerType type) { return type switch { PointerType.Touch => new(10, 10), - _ => new(GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDRAG), GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDRAG)), + _ => new(GetSystemMetrics(SystemMetric.SM_CXDRAG), GetSystemMetrics(SystemMetric.SM_CYDRAG)), }; } @@ -26,7 +24,7 @@ internal class Win32PlatformSettings : DefaultPlatformSettings return type switch { PointerType.Touch => new(16, 16), - _ => new(GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK), GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDOUBLECLK)), + _ => new(GetSystemMetrics(SystemMetric.SM_CXDOUBLECLK), GetSystemMetrics(SystemMetric.SM_CYDOUBLECLK)), }; } diff --git a/src/Windows/Avalonia.Win32/Win32StorageProvider.cs b/src/Windows/Avalonia.Win32/Win32StorageProvider.cs index 2da642bd19..2fd49c8b09 100644 --- a/src/Windows/Avalonia.Win32/Win32StorageProvider.cs +++ b/src/Windows/Avalonia.Win32/Win32StorageProvider.cs @@ -1,13 +1,10 @@ -#nullable enable - -using System; +using System; using System.Linq; using System.Collections.Generic; using System.IO; using System.ComponentModel; using System.Runtime.InteropServices; using System.Threading.Tasks; -using Avalonia.MicroCom; using Avalonia.Platform.Storage; using Avalonia.Platform.Storage.FileIO; using Avalonia.Win32.Interop; @@ -146,7 +143,7 @@ namespace Avalonia.Win32 } } - var showResult = frm.Show(_windowImpl.Handle!.Handle); + var showResult = frm.Show(_windowImpl.Handle.Handle); if ((uint)showResult == (uint)UnmanagedMethods.HRESULT.E_CANCELLED) { @@ -188,7 +185,7 @@ namespace Avalonia.Win32 var message = new Win32Exception(ex.HResult).Message; throw new COMException(message, ex); } - })!; + }); } @@ -220,7 +217,6 @@ namespace Avalonia.Win32 } var size = Marshal.SizeOf(); - var arr = new byte[size]; var resultArr = new byte[size * filters.Count]; for (int i = 0; i < filters.Count; i++) @@ -236,7 +232,7 @@ namespace Avalonia.Win32 { var filterStr = new UnmanagedMethods.COMDLG_FILTERSPEC { - pszName = filter.Name ?? string.Empty, + pszName = filter.Name, pszSpec = string.Join(";", filter.Patterns) }; diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs index 32f44842f8..1a922b4acd 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs @@ -1,14 +1,13 @@ using System; using System.Linq; using System.Runtime.InteropServices; -using Avalonia.MicroCom; using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { - abstract class WinUIEffectBase : WinRTInspectable, IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop + internal abstract class WinUIEffectBase : WinRTInspectable, IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop { - private IGraphicsEffectSource[] _sources; + private IGraphicsEffectSource[]? _sources; public WinUIEffectBase(params IGraphicsEffectSource[] _sources) { @@ -32,7 +31,7 @@ namespace Avalonia.Win32.WinRT.Composition throw new COMException("Not supported", unchecked((int)0x80004001)); public abstract uint PropertyCount { get; } - public abstract IPropertyValue GetProperty(uint index); + public abstract IPropertyValue? GetProperty(uint index); public IGraphicsEffectSource GetSource(uint index) { @@ -53,14 +52,14 @@ namespace Avalonia.Win32.WinRT.Composition _sources = null; } } - - class WinUIGaussianBlurEffect : WinUIEffectBase + + internal class WinUIGaussianBlurEffect : WinUIEffectBase { public WinUIGaussianBlurEffect(IGraphicsEffectSource source) : base(source) { } - enum D2D1_GAUSSIANBLUR_OPTIMIZATION + private enum D2D1_GAUSSIANBLUR_OPTIMIZATION { D2D1_GAUSSIANBLUR_OPTIMIZATION_SPEED, D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED, @@ -68,14 +67,14 @@ namespace Avalonia.Win32.WinRT.Composition D2D1_GAUSSIANBLUR_OPTIMIZATION_FORCE_DWORD }; - enum D2D1_BORDER_MODE + private enum D2D1_BORDER_MODE { D2D1_BORDER_MODE_SOFT, D2D1_BORDER_MODE_HARD, D2D1_BORDER_MODE_FORCE_DWORD }; - enum D2D1GaussianBlurProp + private enum D2D1GaussianBlurProp { D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION, @@ -87,7 +86,7 @@ namespace Avalonia.Win32.WinRT.Composition public override uint PropertyCount => 3; - public override IPropertyValue GetProperty(uint index) + public override IPropertyValue? GetProperty(uint index) { switch ((D2D1GaussianBlurProp)index) { @@ -105,14 +104,14 @@ namespace Avalonia.Win32.WinRT.Composition return null; } } - - class SaturationEffect : WinUIEffectBase + + internal class SaturationEffect : WinUIEffectBase { public SaturationEffect(IGraphicsEffectSource source) : base(source) { } - enum D2D1_SATURATION_PROP + private enum D2D1_SATURATION_PROP { D2D1_SATURATION_PROP_SATURATION, D2D1_SATURATION_PROP_FORCE_DWORD @@ -122,7 +121,7 @@ namespace Avalonia.Win32.WinRT.Composition public override uint PropertyCount => 1; - public override IPropertyValue GetProperty(uint index) + public override IPropertyValue? GetProperty(uint index) { switch ((D2D1_SATURATION_PROP)index) { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs index 5be25a3d4b..2f22ba99f9 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Threading; using Avalonia.OpenGL.Egl; using Avalonia.Reactive; -using Avalonia.Win32.Interop; using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition; @@ -12,8 +11,8 @@ internal class WinUiCompositedWindow : IDisposable { public EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo WindowInfo { get; } private readonly WinUiCompositionShared _shared; - private readonly ICompositionRoundedRectangleGeometry _compositionRoundedRectangleGeometry; - private readonly IVisual _mica; + private readonly ICompositionRoundedRectangleGeometry? _compositionRoundedRectangleGeometry; + private readonly IVisual? _mica; private readonly IVisual _blur; private readonly IVisual _visual; private PixelSize _size; @@ -25,7 +24,7 @@ internal class WinUiCompositedWindow : IDisposable lock (_shared.SyncRoot) { _compositionRoundedRectangleGeometry?.Dispose(); - _blur?.Dispose(); + _blur.Dispose(); _mica?.Dispose(); _visual.Dispose(); _surfaceBrush.Dispose(); diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs index 9ee024f9ad..95ef338f08 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs @@ -1,15 +1,8 @@ using System; -using System.Runtime.InteropServices; -using Avalonia.MicroCom; -using Avalonia.OpenGL; -using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; -using Avalonia.OpenGL.Surfaces; using Avalonia.Platform; -using Avalonia.Utilities; using Avalonia.Win32.DirectX; using Avalonia.Win32.Interop; -using Avalonia.Win32.OpenGl.Angle; using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition @@ -18,7 +11,7 @@ namespace Avalonia.Win32.WinRT.Composition { private readonly WinUiCompositionShared _shared; private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info; - private WinUiCompositedWindow _window; + private WinUiCompositedWindow? _window; private BlurEffect _blurEffect; public WinUiCompositedWindowSurface(WinUiCompositionShared shared, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info) @@ -52,6 +45,8 @@ namespace Avalonia.Win32.WinRT.Composition internal class WinUiCompositedWindowRenderTarget : IDirect3D11TextureRenderTarget { + private static readonly Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c"); + private readonly IPlatformGraphicsContext _context; private readonly WinUiCompositedWindow _window; private readonly IUnknown _d3dDevice; @@ -63,6 +58,7 @@ namespace Avalonia.Win32.WinRT.Composition private PixelSize _size; private bool _lost; private readonly ICompositionDrawingSurfaceInterop _surfaceInterop; + private readonly ICompositionDrawingSurface _drawingSurface; public WinUiCompositedWindowRenderTarget(IPlatformGraphicsContext context, WinUiCompositedWindow window, IntPtr device, @@ -83,28 +79,33 @@ namespace Avalonia.Win32.WinRT.Composition _surface = _drawingSurface.QueryInterface(); _surfaceInterop = _drawingSurface.QueryInterface(); } - finally + catch { - if (_surfaceInterop == null) - Dispose(); + _surface?.Dispose(); + _surfaceInterop?.Dispose(); + _drawingSurface?.Dispose(); + _compositionDevice2?.Dispose(); + _compositionDevice?.Dispose(); + _interop?.Dispose(); + _compositor?.Dispose(); + _d3dDevice?.Dispose(); + throw; } } public void Dispose() { - _surface?.Dispose(); - _surfaceInterop?.Dispose(); - _drawingSurface?.Dispose(); - _compositionDevice2?.Dispose(); - _compositionDevice?.Dispose(); - _interop?.Dispose(); - _compositor?.Dispose(); - _d3dDevice?.Dispose(); + _surface.Dispose(); + _surfaceInterop.Dispose(); + _drawingSurface.Dispose(); + _compositionDevice2.Dispose(); + _compositionDevice.Dispose(); + _interop.Dispose(); + _compositor.Dispose(); + _d3dDevice.Dispose(); } public bool IsCorrupted => _context.IsLost || _lost; - private static Guid IID_ID3D11Texture2D = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c"); - private readonly ICompositionDrawingSurface _drawingSurface; public unsafe IDirect3D11TextureRenderTargetRenderSession BeginDraw() { @@ -155,12 +156,12 @@ namespace Avalonia.Win32.WinRT.Composition { if (needsEndDraw) _surfaceInterop.EndDraw(); - transaction?.Dispose(); + transaction.Dispose(); } } } - class Session : IDirect3D11TextureRenderTargetRenderSession + private class Session : IDirect3D11TextureRenderTargetRenderSession { private readonly IDisposable _transaction; private readonly PixelSize _size; @@ -200,4 +201,4 @@ namespace Avalonia.Win32.WinRT.Composition public double Scaling => _scaling; } } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs index 301e605e7a..602d0a3f8a 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs @@ -8,11 +8,11 @@ internal class WinUiCompositionShared : IDisposable public ICompositor Compositor { get; } public ICompositor5 Compositor5 { get; } public ICompositorDesktopInterop DesktopInterop { get; } - public ICompositionBrush BlurBrush; - public ICompositionBrush MicaBrush; + public ICompositionBrush BlurBrush { get; } + public ICompositionBrush? MicaBrush { get; } public object SyncRoot { get; } = new(); - public static readonly Version MinHostBackdropVersion = new Version(10, 0, 22000); + public static readonly Version MinHostBackdropVersion = new(10, 0, 22000); public WinUiCompositionShared(ICompositor compositor) { @@ -26,9 +26,9 @@ internal class WinUiCompositionShared : IDisposable public void Dispose() { BlurBrush.Dispose(); - MicaBrush.Dispose(); + MicaBrush?.Dispose(); DesktopInterop.Dispose(); Compositor.Dispose(); Compositor5.Dispose(); } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs index e7af4046d6..7b970868df 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; using MicroCom.Runtime; @@ -6,7 +5,7 @@ namespace Avalonia.Win32.WinRT.Composition; internal static class WinUiCompositionUtils { - public static ICompositionBrush CreateMicaBackdropBrush(ICompositor compositor) + public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor) { if (Win32Platform.WindowsVersion.Build < 22000) return null; @@ -18,7 +17,7 @@ internal static class WinUiCompositionUtils return blurredWallpaperBackdropBrush?.QueryInterface(); } - public static unsafe ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor) + public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor) { using var backDropParameterFactory = NativeWinRTMethods.CreateActivationFactory( @@ -39,7 +38,7 @@ internal static class WinUiCompositionUtils return compositionEffectBrush.QueryInterface(); } - public static ICompositionRoundedRectangleGeometry ClipVisual(ICompositor compositor, float? _backdropCornerRadius, params IVisual[] containerVisuals) + public static ICompositionRoundedRectangleGeometry? ClipVisual(ICompositor compositor, float? _backdropCornerRadius, params IVisual?[] containerVisuals) { if (!_backdropCornerRadius.HasValue) return null; @@ -77,7 +76,7 @@ internal static class WinUiCompositionUtils public static ICompositionBrush CreateBackdropBrush(ICompositor compositor) { - ICompositionBackdropBrush brush = null; + ICompositionBackdropBrush? brush = null; try { if (Win32Platform.WindowsVersion >= WinUiCompositionShared.MinHostBackdropVersion) @@ -98,4 +97,4 @@ internal static class WinUiCompositionUtils brush?.Dispose(); } } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositorConnection.cs index a1408baae0..754af86c06 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositorConnection.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositorConnection.cs @@ -7,20 +7,17 @@ using Avalonia.Logging; using Avalonia.MicroCom; using Avalonia.OpenGL.Egl; using Avalonia.Rendering; -using Avalonia.Win32.DirectX; using Avalonia.Win32.Interop; -using Avalonia.Win32.OpenGl.Angle; -using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition; internal class WinUiCompositorConnection : IRenderTimer { private readonly WinUiCompositionShared _shared; - public event Action Tick; + public event Action? Tick; public bool RunsInBackground => true; - public unsafe WinUiCompositorConnection() + public WinUiCompositorConnection() { using var compositor = NativeWinRTMethods.CreateInstance("Windows.UI.Composition.Compositor"); /* @@ -42,10 +39,9 @@ internal class WinUiCompositorConnection : IRenderTimer _shared = new WinUiCompositionShared(compositor); } - static bool TryCreateAndRegisterCore() + private static bool TryCreateAndRegisterCore() { var tcs = new TaskCompletionSource(); - var pumpLock = new object(); var th = new Thread(() => { WinUiCompositorConnection connect; @@ -80,10 +76,10 @@ internal class WinUiCompositorConnection : IRenderTimer return tcs.Task.Result; } - class RunLoopHandler : CallbackBase, IAsyncActionCompletedHandler + private class RunLoopHandler : CallbackBase, IAsyncActionCompletedHandler { private readonly WinUiCompositorConnection _parent; - private Stopwatch _st = Stopwatch.StartNew(); + private readonly Stopwatch _st = Stopwatch.StartNew(); public RunLoopHandler(WinUiCompositorConnection parent) { @@ -101,7 +97,7 @@ internal class WinUiCompositorConnection : IRenderTimer private void RunLoop() { var cts = new CancellationTokenSource(); - AppDomain.CurrentDomain.ProcessExit += (sender, args) => + AppDomain.CurrentDomain.ProcessExit += (_, _) => cts.Cancel(); lock (_shared.SyncRoot) diff --git a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs index 01b45f3df2..21f83addeb 100644 --- a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs +++ b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs @@ -1,12 +1,6 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Reflection; using System.Runtime.InteropServices; using System.Threading; -using Avalonia.MicroCom; -using Avalonia.Win32.Interop; using MicroCom.Runtime; namespace Avalonia.Win32.WinRT @@ -108,24 +102,24 @@ namespace Avalonia.Win32.WinRT [DllImport("combase.dll", PreserveSig = false)] private static extern IntPtr RoGetActivationFactory(IntPtr activatableClassId, ref Guid iid); - private static bool _initialized; + private static bool s_initialized; private static void EnsureRoInitialized() { - if (_initialized) + if (s_initialized) return; RoInitialize(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA ? RO_INIT_TYPE.RO_INIT_SINGLETHREADED : RO_INIT_TYPE.RO_INIT_MULTITHREADED); - _initialized = true; + s_initialized = true; } } - class HStringInterop : IDisposable + internal class HStringInterop : IDisposable { private IntPtr _s; - private bool _owns; + private readonly bool _owns; - public HStringInterop(string s) + public HStringInterop(string? s) { _s = s == null ? IntPtr.Zero : NativeWinRTMethods.WindowsCreateString(s); _owns = true; @@ -139,7 +133,7 @@ namespace Avalonia.Win32.WinRT public IntPtr Handle => _s; - public unsafe string Value + public unsafe string? Value { get { diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs index 1fde57fe38..aabf148e75 100644 --- a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs +++ b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs @@ -2,12 +2,11 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Avalonia.MicroCom; using MicroCom.Runtime; namespace Avalonia.Win32.WinRT { - class WinRTInspectable : IInspectable, IMicroComShadowContainer + internal class WinRTInspectable : IInspectable, IMicroComShadowContainer { public virtual void Dispose() { @@ -25,9 +24,9 @@ namespace Avalonia.Win32.WinRT *iidCount = (ulong) interfaces.Length; } - public IntPtr RuntimeClassName => NativeWinRTMethods.WindowsCreateString(GetType().FullName); + public IntPtr RuntimeClassName => NativeWinRTMethods.WindowsCreateString(GetType().FullName!); public TrustLevel TrustLevel => TrustLevel.BaseTrust; - public MicroComShadow Shadow { get; set; } + public MicroComShadow? Shadow { get; set; } public virtual void OnReferencedFromNative() { } diff --git a/src/Windows/Avalonia.Win32/WinScreen.cs b/src/Windows/Avalonia.Win32/WinScreen.cs index 1038f41a17..69d334cbcc 100644 --- a/src/Windows/Avalonia.Win32/WinScreen.cs +++ b/src/Windows/Avalonia.Win32/WinScreen.cs @@ -15,14 +15,16 @@ namespace Avalonia.Win32 public IntPtr Handle => _hMonitor; + /// public override int GetHashCode() { - return (int)_hMonitor; + return _hMonitor.GetHashCode(); } - public override bool Equals(object obj) + /// + public override bool Equals(object? obj) { - return (obj is WinScreen screen) ? _hMonitor == screen._hMonitor : base.Equals(obj); + return obj is WinScreen screen && _hMonitor == screen._hMonitor; } } } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 8c362b0c29..288bdf2448 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -1,12 +1,9 @@ using System; -using System.Buffers; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -using System.Text; using Avalonia.Automation.Peers; using Avalonia.Controls; -using Avalonia.Controls.Remote; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Platform; @@ -27,9 +24,9 @@ namespace Avalonia.Win32 protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { const double wheelDelta = 120.0; - const long UiaRootObjectId = -25; + const long uiaRootObjectId = -25; uint timestamp = unchecked((uint)GetMessageTime()); - RawInputEventArgs e = null; + RawInputEventArgs? e = null; var shouldTakeFocus = false; var message = (WindowsMessage)msg; switch (message) @@ -92,7 +89,7 @@ namespace Avalonia.Win32 } // We need to release IMM context and state to avoid leaks. - if (Imm32InputMethod.Current.HWND == _hwnd) + if (Imm32InputMethod.Current.Hwnd == _hwnd) { Imm32InputMethod.Current.ClearLanguageAndWindow(); } @@ -104,7 +101,7 @@ namespace Avalonia.Win32 Closed?.Invoke(); _mouseDevice.Dispose(); - _touchDevice?.Dispose(); + _touchDevice.Dispose(); //Free other resources Dispose(); @@ -140,7 +137,7 @@ namespace Avalonia.Win32 { var key = KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)); - if (key != Key.None) + if (key != Key.None && _owner is not null) { e = new RawKeyEventArgs( WindowsKeyboardDevice.Instance, @@ -170,7 +167,7 @@ namespace Avalonia.Win32 { var key = KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)); - if (key != Key.None) + if (key != Key.None && _owner is not null) { e = new RawKeyEventArgs( WindowsKeyboardDevice.Instance, @@ -185,7 +182,7 @@ namespace Avalonia.Win32 case WindowsMessage.WM_CHAR: { // Ignore control chars and chars that were handled in WM_KEYDOWN. - if (ToInt32(wParam) >= 32 && !_ignoreWmChar) + if (ToInt32(wParam) >= 32 && !_ignoreWmChar && _owner is not null) { e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _owner, new string((char)ToInt32(wParam), 1)); @@ -204,7 +201,7 @@ namespace Avalonia.Win32 break; } shouldTakeFocus = ShouldTakeFocusOnClick; - if (ShouldIgnoreTouchEmulatedMessage()) + if (ShouldIgnoreTouchEmulatedMessage() || _owner is null) { break; } @@ -213,7 +210,9 @@ namespace Avalonia.Win32 _mouseDevice, timestamp, _owner, +#pragma warning disable CS8509 message switch +#pragma warning restore CS8509 { WindowsMessage.WM_LBUTTONDOWN => RawPointerEventType.LeftButtonDown, WindowsMessage.WM_RBUTTONDOWN => RawPointerEventType.RightButtonDown, @@ -221,7 +220,7 @@ namespace Avalonia.Win32 WindowsMessage.WM_XBUTTONDOWN => HighWord(ToInt32(wParam)) == 1 ? RawPointerEventType.XButton1Down : - RawPointerEventType.XButton2Down + RawPointerEventType.XButton2Down, }, DipFromLParam(lParam), GetMouseModifiers(wParam)); break; @@ -236,7 +235,7 @@ namespace Avalonia.Win32 { break; } - if (ShouldIgnoreTouchEmulatedMessage()) + if (ShouldIgnoreTouchEmulatedMessage() || _owner is null) { break; } @@ -245,7 +244,9 @@ namespace Avalonia.Win32 _mouseDevice, timestamp, _owner, +#pragma warning disable CS8509 message switch +#pragma warning restore CS8509 { WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp, WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp, @@ -309,6 +310,11 @@ namespace Avalonia.Win32 var prevPoint = _lastWmMousePoint; _lastWmMousePoint = currPoint; + if (_owner is null) + { + break; + } + e = new RawPointerEventArgs( _mouseDevice, timestamp, @@ -317,7 +323,7 @@ namespace Avalonia.Win32 point, GetMouseModifiers(wParam)) { - IntermediatePoints = new Lazy>(() => CreateLazyIntermediatePoints(currPoint, prevPoint)) + IntermediatePoints = new Lazy?>(() => CreateIntermediatePoints(currPoint, prevPoint)) }; break; @@ -325,7 +331,7 @@ namespace Avalonia.Win32 case WindowsMessage.WM_MOUSEWHEEL: { - if (IsMouseInPointerEnabled) + if (IsMouseInPointerEnabled || _owner is null) { break; } @@ -341,7 +347,7 @@ namespace Avalonia.Win32 case WindowsMessage.WM_MOUSEHWHEEL: { - if (IsMouseInPointerEnabled) + if (IsMouseInPointerEnabled || _owner is null) { break; } @@ -362,6 +368,10 @@ namespace Avalonia.Win32 break; } _trackingMouse = false; + if (_owner is null) + { + break; + } e = new RawPointerEventArgs( _mouseDevice, timestamp, @@ -377,7 +387,7 @@ namespace Avalonia.Win32 case WindowsMessage.WM_NCMBUTTONDOWN: case WindowsMessage.WM_NCXBUTTONDOWN: { - if (IsMouseInPointerEnabled) + if (IsMouseInPointerEnabled || _owner is null) { break; } @@ -385,7 +395,9 @@ namespace Avalonia.Win32 _mouseDevice, timestamp, _owner, +#pragma warning disable CS8509 message switch +#pragma warning restore CS8509 { WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType .NonClientLeftButtonDown, @@ -396,12 +408,12 @@ namespace Avalonia.Win32 RawPointerEventType.XButton1Down : RawPointerEventType.XButton2Down, }, - PointToClient(WindowImpl.PointFromLParam(lParam)), GetMouseModifiers(wParam)); + PointToClient(PointFromLParam(lParam)), GetMouseModifiers(wParam)); break; } case WindowsMessage.WM_TOUCH: { - if (_wmPointerEnabled) + if (_wmPointerEnabled || _owner is null || Input is not { } input) { break; } @@ -414,7 +426,7 @@ namespace Avalonia.Win32 { foreach (var touchInput in touchInputs) { - Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time, + input.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time, _owner, touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_UP) ? RawPointerEventType.TouchEnd : @@ -438,14 +450,14 @@ namespace Avalonia.Win32 case WindowsMessage.WM_POINTERUP: case WindowsMessage.WM_POINTERUPDATE: { - if (!_wmPointerEnabled) + if (!_wmPointerEnabled || _owner is null) { break; } GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp); var eventType = GetEventType(message, info); - var args = CreatePointerArgs(device, timestamp, eventType, point, modifiers, info.pointerId); + var args = CreatePointerArgs(device, timestamp, _owner, eventType, point, modifiers, info.pointerId); args.IntermediatePoints = CreateLazyIntermediatePoints(info); e = args; break; @@ -454,19 +466,19 @@ namespace Avalonia.Win32 case WindowsMessage.WM_POINTERLEAVE: case WindowsMessage.WM_POINTERCAPTURECHANGED: { - if (!_wmPointerEnabled) + if (!_wmPointerEnabled || _owner is null) { break; } GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp); var eventType = device is TouchDevice ? RawPointerEventType.TouchCancel : RawPointerEventType.LeaveWindow; - e = CreatePointerArgs(device, timestamp, eventType, point, modifiers, info.pointerId); + e = CreatePointerArgs(device, timestamp, _owner, eventType, point, modifiers, info.pointerId); break; } case WindowsMessage.WM_POINTERWHEEL: case WindowsMessage.WM_POINTERHWHEEL: { - if (!_wmPointerEnabled) + if (!_wmPointerEnabled || _owner is null) { break; } @@ -488,7 +500,7 @@ namespace Avalonia.Win32 } // Do not generate events, but release mouse capture on any other device input. - GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp); + GetDevicePointerInfo(wParam, out var device, out _, out _, out _, ref timestamp); if (device != _mouseDevice) { _mouseDevice.Capture(null); @@ -726,9 +738,9 @@ namespace Avalonia.Win32 break; case WindowsMessage.WM_GETOBJECT: - if ((long)lParam == UiaRootObjectId && UiaCoreTypesApi.IsNetComInteropAvailable) + if ((long)lParam == uiaRootObjectId && UiaCoreTypesApi.IsNetComInteropAvailable && _owner is Control control) { - var peer = ControlAutomationPeer.CreatePeerForElement((Control)_owner); + var peer = ControlAutomationPeer.CreatePeerForElement(control); var node = AutomationNode.GetOrCreate(peer); return UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, wParam, lParam, node); } @@ -775,12 +787,12 @@ namespace Avalonia.Win32 } } - private unsafe Lazy> CreateLazyIntermediatePoints(POINTER_INFO info) + private Lazy?>? CreateLazyIntermediatePoints(POINTER_INFO info) { var historyCount = Math.Min((int)info.historyCount, MaxPointerHistorySize); if (historyCount > 1) { - return new Lazy>(() => + return new Lazy?>(() => { s_intermediatePointsPooledList.Clear(); s_intermediatePointsPooledList.Capacity = historyCount; @@ -829,7 +841,7 @@ namespace Avalonia.Win32 return null; } - private unsafe IReadOnlyList CreateLazyIntermediatePoints(MOUSEMOVEPOINT movePoint, MOUSEMOVEPOINT prevMovePoint) + private unsafe IReadOnlyList CreateIntermediatePoints(MOUSEMOVEPOINT movePoint, MOUSEMOVEPOINT prevMovePoint) { // To understand some of this code, please check MS docs: // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmousemovepointsex#remarks @@ -888,11 +900,11 @@ namespace Avalonia.Win32 } } - private RawPointerEventArgs CreatePointerArgs(IInputDevice device, ulong timestamp, RawPointerEventType eventType, RawPointerPoint point, RawInputModifiers modifiers, uint rawPointerId) + private RawPointerEventArgs CreatePointerArgs(IInputDevice device, ulong timestamp, IInputRoot owner, RawPointerEventType eventType, RawPointerPoint point, RawInputModifiers modifiers, uint rawPointerId) { return device is TouchDevice - ? new RawTouchEventArgs(device, timestamp, _owner, eventType, point, modifiers, rawPointerId) - : new RawPointerEventArgs(device, timestamp, _owner, eventType, point, modifiers) + ? new RawTouchEventArgs(device, timestamp, owner, eventType, point, modifiers, rawPointerId) + : new RawPointerEventArgs(device, timestamp, owner, eventType, point, modifiers) { RawPointerId = rawPointerId }; @@ -1029,7 +1041,7 @@ namespace Avalonia.Win32 // note: for non-ime language, also create it so that emoji panel tracks cursor var langid = LGID(hkl); - if (langid == _langid && Imm32InputMethod.Current.HWND == Hwnd) + if (langid == _langid && Imm32InputMethod.Current.Hwnd == Hwnd) { return; } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index fb27ab7856..20ab738a2a 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -3,8 +3,6 @@ using Avalonia.Controls; using Avalonia.Input; using static Avalonia.Win32.Interop.UnmanagedMethods; -#nullable enable - namespace Avalonia.Win32 { public partial class WindowImpl @@ -13,7 +11,7 @@ namespace Avalonia.Win32 private HitTestValues HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) { // Get the point coordinates for the hit test (screen space). - var ptMouse = WindowImpl.PointFromLParam(lParam); + var ptMouse = PointFromLParam(lParam); // Get the window rectangle. GetWindowRect(hWnd, out var rcWindow); @@ -101,11 +99,9 @@ namespace Avalonia.Win32 lRet = (IntPtr)hittestResult; - uint timestamp = unchecked((uint)GetMessageTime()); - if (hittestResult == HitTestValues.HTCAPTION) { - var position = PointToClient(WindowImpl.PointFromLParam(lParam)); + var position = PointToClient(PointFromLParam(lParam)); if (_owner is Window window) { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs index 07f2311be8..49197a83e8 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs @@ -2,14 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using Avalonia.Controls; using Avalonia.Controls.Platform; -using Avalonia.Input; -using Avalonia.Input.Raw; -using Avalonia.Win32.Input; -using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 1e0d92d442..57407b5f34 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -1,33 +1,29 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; -using Avalonia.Controls; -using Avalonia.Automation.Peers; +using Avalonia.Collections.Pooled; using Avalonia.Controls.Platform; -using Avalonia.Input; +using Avalonia.Controls; using Avalonia.Input.Raw; using Avalonia.Input.TextInput; -using Avalonia.OpenGL; -using Avalonia.OpenGL.Angle; +using Avalonia.Input; +using Avalonia.Metadata; using Avalonia.OpenGL.Egl; -using Avalonia.OpenGL.Surfaces; +using Avalonia.Platform.Storage; using Avalonia.Platform; -using Avalonia.Rendering; using Avalonia.Rendering.Composition; -using Avalonia.Win32.Automation; +using Avalonia.Rendering; +using Avalonia.Win32.DirectX; using Avalonia.Win32.Input; using Avalonia.Win32.Interop; +using Avalonia.Win32.OpenGl.Angle; using Avalonia.Win32.OpenGl; -using Avalonia.Win32.WinRT; using Avalonia.Win32.WinRT.Composition; +using Avalonia.Win32.WinRT; using static Avalonia.Win32.Interop.UnmanagedMethods; -using Avalonia.Collections.Pooled; -using Avalonia.Metadata; -using Avalonia.Platform.Storage; -using Avalonia.Win32.DirectX; -using Avalonia.Win32.OpenGl.Angle; namespace Avalonia.Win32 { @@ -37,13 +33,13 @@ namespace Avalonia.Win32 [Unstable] public partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo { - private static readonly List s_instances = new List(); + private static readonly List s_instances = new(); - private static readonly IntPtr DefaultCursor = LoadCursor( + private static readonly IntPtr s_defaultCursor = LoadCursor( IntPtr.Zero, new IntPtr((int)UnmanagedMethods.Cursor.IDC_ARROW)); private static readonly Dictionary s_edgeLookup = - new Dictionary + new() { { WindowEdge.East, HitTestValues.HTRIGHT }, { WindowEdge.North, HitTestValues.HTTOP }, @@ -61,8 +57,8 @@ namespace Avalonia.Win32 private Thickness _extendedMargins; private Thickness _offScreenMargin; private double _extendTitleBarHint = -1; - private bool _isUsingComposition; - private IBlurHost _blurHost; + private readonly bool _isUsingComposition; + private readonly IBlurHost? _blurHost; private PlatformResizeReason _resizeReason; private MOUSEMOVEPOINT _lastWmMousePoint; @@ -76,26 +72,26 @@ namespace Avalonia.Win32 private readonly PenDevice _penDevice; private readonly ManagedDeferredRendererLock _rendererLock; private readonly FramebufferManager _framebuffer; - private readonly object _gl; + private readonly object? _gl; private readonly bool _wmPointerEnabled; - private Win32NativeControlHost _nativeControlHost; - private IStorageProvider _storageProvider; + private readonly Win32NativeControlHost _nativeControlHost; + private readonly IStorageProvider _storageProvider; private WndProc _wndProcDelegate; - private string _className; + private string? _className; private IntPtr _hwnd; - private IInputRoot _owner; + private IInputRoot? _owner; private WindowProperties _windowProperties; private bool _trackingMouse;//ToDo - there is something missed. Needs investigation @Steven Kirk private bool _topmost; private double _scaling = 1; private WindowState _showWindowState; private WindowState _lastWindowState; - private OleDropTarget _dropTarget; + private OleDropTarget? _dropTarget; private Size _minSize; private Size _maxSize; private POINT _maxTrackSize; - private WindowImpl _parent; + private WindowImpl? _parent; private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; private bool _isCloseRequested; private bool _shown; @@ -142,7 +138,7 @@ namespace Avalonia.Win32 angle.PlatformApi == AngleOptions.PlatformApi.DirectX11; _isUsingComposition = compositionConnector is { } && isUsingAngleDX11; - DxgiConnection dxgiConnection = null; + DxgiConnection? dxgiConnection = null; var isUsingDxgiSwapchain = false; if (!_isUsingComposition) { @@ -159,23 +155,20 @@ namespace Avalonia.Win32 { if (_isUsingComposition) { - var cgl = compositionConnector.CreateSurface(this); + var cgl = compositionConnector!.CreateSurface(this); _blurHost = cgl; - _gl = cgl; - - _isUsingComposition = true; } else if (isUsingDxgiSwapchain) { - var dxgigl = new DxgiSwapchainWindow(dxgiConnection, this); + var dxgigl = new DxgiSwapchainWindow(dxgiConnection!, this); _gl = dxgigl; } else { - if (glPlatform is AngleWin32PlatformGraphics egl2) + if (glPlatform is AngleWin32PlatformGraphics) _gl = new EglGlPlatformSurface(this); - else if (glPlatform is WglPlatformOpenGlInterface wgl) + else if (glPlatform is WglPlatformOpenGlInterface) _gl = new WglGlPlatformSurface(this); } } @@ -187,29 +180,41 @@ namespace Avalonia.Win32 s_instances.Add(this); } - public Action Activated { get; set; } + /// + public Action? Activated { get; set; } - public Func Closing { get; set; } + /// + public Func? Closing { get; set; } - public Action Closed { get; set; } + /// + public Action? Closed { get; set; } - public Action Deactivated { get; set; } + /// + public Action? Deactivated { get; set; } - public Action Input { get; set; } + /// + public Action? Input { get; set; } - public Action Paint { get; set; } + /// + public Action? Paint { get; set; } - public Action Resized { get; set; } + /// + public Action? Resized { get; set; } - public Action ScalingChanged { get; set; } + /// + public Action? ScalingChanged { get; set; } - public Action PositionChanged { get; set; } + /// + public Action? PositionChanged { get; set; } - public Action WindowStateChanged { get; set; } + /// + public Action? WindowStateChanged { get; set; } - public Action LostFocus { get; set; } + /// + public Action? LostFocus { get; set; } - public Action TransparencyLevelChanged { get; set; } + /// + public Action? TransparencyLevelChanged { get; set; } public Thickness BorderThickness { @@ -240,10 +245,13 @@ namespace Avalonia.Win32 private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.Scaling ?? 1; + /// public double RenderScaling => _scaling; + /// public double DesktopScaling => RenderScaling; + /// public Size ClientSize { get @@ -254,6 +262,7 @@ namespace Avalonia.Win32 } } + /// public Size? FrameSize { get @@ -269,14 +278,18 @@ namespace Avalonia.Win32 } } + /// public IScreenImpl Screen { get; } + /// public IPlatformHandle Handle { get; private set; } + /// public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / RenderScaling, _maxTrackSize.Y / RenderScaling); public IMouseDevice MouseDevice => _mouseDevice; + /// public WindowState WindowState { get @@ -314,13 +327,15 @@ namespace Avalonia.Win32 } } + /// public WindowTransparencyLevel TransparencyLevel { get; private set; } protected IntPtr Hwnd => _hwnd; private bool IsMouseInPointerEnabled => _wmPointerEnabled && IsMouseInPointerEnabled(); - public object TryGetFeature(Type featureType) + /// + public object? TryGetFeature(Type featureType) { if (featureType == typeof(ITextInputMethodImpl)) { @@ -339,7 +354,8 @@ namespace Avalonia.Win32 return null; } - + + /// public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { TransparencyLevel = EnableBlur(transparencyLevel); @@ -521,8 +537,13 @@ namespace Avalonia.Win32 } } - public IEnumerable Surfaces => new object[] { (IPlatformNativeSurfaceHandle)Handle, _gl, _framebuffer }; + /// + public IEnumerable Surfaces + => _gl is null ? + new object[] { Handle, _framebuffer } : + new object[] { Handle, _gl, _framebuffer }; + /// public PixelPoint Position { get @@ -568,17 +589,21 @@ namespace Avalonia.Win32 } } + /// public void Move(PixelPoint point) => Position = point; + /// public void SetMinMaxSize(Size minSize, Size maxSize) { _minSize = minSize; _maxSize = maxSize; } + /// public IRenderer CreateRenderer(IRenderRoot root) => new CompositingRenderer(root, Win32Platform.Compositor, () => Surfaces); + /// public void Resize(Size value, PlatformResizeReason reason) { if (WindowState != WindowState.Normal) @@ -606,13 +631,16 @@ namespace Avalonia.Win32 } } + /// public void Activate() { SetForegroundWindow(_hwnd); } - public IPopupImpl CreatePopup() => Win32Platform.UseOverlayPopups ? null : new PopupImpl(this); + /// + public IPopupImpl? CreatePopup() => Win32Platform.UseOverlayPopups ? null : new PopupImpl(this); + /// public void Dispose() { (_gl as IDisposable)?.Dispose(); @@ -654,6 +682,7 @@ namespace Avalonia.Win32 InvalidateRect(_hwnd, ref r, false); } + /// public Point PointToClient(PixelPoint point) { var p = new POINT { X = point.X, Y = point.Y }; @@ -661,6 +690,7 @@ namespace Avalonia.Win32 return new Point(p.X, p.Y) / RenderScaling; } + /// public PixelPoint PointToScreen(Point point) { point *= RenderScaling; @@ -669,29 +699,34 @@ namespace Avalonia.Win32 return new PixelPoint(p.X, p.Y); } + /// public void SetInputRoot(IInputRoot inputRoot) { _owner = inputRoot; - CreateDropTarget(); + CreateDropTarget(inputRoot); } + /// public void Hide() { UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide); _shown = false; } + /// public virtual void Show(bool activate, bool isDialog) { SetParent(_parent); ShowWindow(_showWindowState, activate); } - public Action GotInputWhenDisabled { get; set; } + /// + public Action? GotInputWhenDisabled { get; set; } - public void SetParent(IWindowImpl parent) + /// + public void SetParent(IWindowImpl? parent) { - _parent = (WindowImpl)parent; + _parent = parent as WindowImpl; var parentHwnd = _parent?._hwnd ?? IntPtr.Zero; @@ -704,8 +739,10 @@ namespace Avalonia.Win32 SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, parentHwnd); } + /// public void SetEnabled(bool enable) => EnableWindow(_hwnd, enable); + /// public void BeginMoveDrag(PointerPressedEventArgs e) { e.Pointer.Capture(null); @@ -713,6 +750,7 @@ namespace Avalonia.Win32 new IntPtr((int)HitTestValues.HTCAPTION), IntPtr.Zero); } + /// public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e) { if (_windowProperties.IsResizable) @@ -727,35 +765,37 @@ namespace Avalonia.Win32 } } - public void SetTitle(string title) + /// + public void SetTitle(string? title) { SetWindowText(_hwnd, title); } - public void SetCursor(ICursorImpl cursor) + /// + public void SetCursor(ICursorImpl? cursor) { var impl = cursor as CursorImpl; - if (cursor is null || impl is object) - { - var hCursor = impl?.Handle ?? DefaultCursor; - SetClassLong(_hwnd, ClassLongIndex.GCLP_HCURSOR, hCursor); + var hCursor = impl?.Handle ?? s_defaultCursor; + SetClassLong(_hwnd, ClassLongIndex.GCLP_HCURSOR, hCursor); - if (_owner.IsPointerOver) - { - UnmanagedMethods.SetCursor(hCursor); - } + if (_owner?.IsPointerOver == true) + { + UnmanagedMethods.SetCursor(hCursor); } } - public void SetIcon(IWindowIconImpl icon) + /// + public void SetIcon(IWindowIconImpl? icon) { - var impl = (IconImpl)icon; + var impl = icon as IconImpl; + var hIcon = impl?.HIcon ?? IntPtr.Zero; PostMessage(_hwnd, (int)WindowsMessage.WM_SETICON, new IntPtr((int)Icons.ICON_BIG), hIcon); } + /// public void ShowTaskbarIcon(bool value) { var newWindowProperties = _windowProperties; @@ -765,6 +805,7 @@ namespace Avalonia.Win32 UpdateWindowProperties(newWindowProperties); } + /// public void CanResize(bool value) { var newWindowProperties = _windowProperties; @@ -774,6 +815,7 @@ namespace Avalonia.Win32 UpdateWindowProperties(newWindowProperties); } + /// public void SetSystemDecorations(SystemDecorations value) { var newWindowProperties = _windowProperties; @@ -783,6 +825,7 @@ namespace Avalonia.Win32 UpdateWindowProperties(newWindowProperties); } + /// public void SetTopmost(bool value) { if (value == _topmost) @@ -799,6 +842,7 @@ namespace Avalonia.Win32 _topmost = value; } + /// public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { if (Win32Platform.WindowsVersion.Build >= 22000) @@ -829,6 +873,9 @@ namespace Avalonia.Win32 IntPtr.Zero); } + [MemberNotNull(nameof(_wndProcDelegate))] + [MemberNotNull(nameof(_className))] + [MemberNotNull(nameof(Handle))] private void CreateWindow() { // Ensure that the delegate doesn't get garbage collected by storing it as a field. @@ -845,7 +892,7 @@ namespace Avalonia.Win32 style = (int)windowClassStyle, lpfnWndProc = _wndProcDelegate, hInstance = GetModuleHandle(null), - hCursor = DefaultCursor, + hCursor = s_defaultCursor, hbrBackground = IntPtr.Zero, lpszClassName = _className }; @@ -878,20 +925,23 @@ namespace Avalonia.Win32 monitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpix, - out var dpiy) == 0) + out _) == 0) { _scaling = dpix / 96.0; } } } - private void CreateDropTarget() + private void CreateDropTarget(IInputRoot inputRoot) { - var odt = new OleDropTarget(this, _owner); - - if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false) + if (AvaloniaLocator.Current.GetService() is { } dragDropDevice) { - _dropTarget = odt; + var odt = new OleDropTarget(this, inputRoot, dragDropDevice); + + if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false) + { + _dropTarget = odt; + } } } @@ -1105,7 +1155,7 @@ namespace Avalonia.Win32 case WindowState.FullScreen: newWindowProperties.IsFullScreen = true; - command = IsWindowVisible(_hwnd) ? (ShowWindowCommand?)null : ShowWindowCommand.Restore; + command = IsWindowVisible(_hwnd) ? null : ShowWindowCommand.Restore; break; default: @@ -1370,13 +1420,13 @@ namespace Avalonia.Win32 private const int MF_DISABLED = 0x2; private const int SC_CLOSE = 0xF060; - static void DisableCloseButton(IntPtr hwnd) + private static void DisableCloseButton(IntPtr hwnd) { EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); } - static void EnableCloseButton(IntPtr hwnd) + private static void EnableCloseButton(IntPtr hwnd) { EnableMenuItem(GetSystemMenu(hwnd, false), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED); @@ -1407,6 +1457,7 @@ namespace Avalonia.Win32 IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; + /// public void SetExtendClientAreaToDecorationsHint(bool hint) { _isClientAreaExtended = hint; @@ -1414,6 +1465,7 @@ namespace Avalonia.Win32 ExtendClientArea(); } + /// public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) { _extendChromeHints = hints; @@ -1433,7 +1485,7 @@ namespace Avalonia.Win32 public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended; /// - public Action ExtendClientAreaToDecorationsChanged { get; set; } + public Action? ExtendClientAreaToDecorationsChanged { get; set; } /// public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome); diff --git a/src/Windows/Avalonia.Win32/WindowsMountedVolumeInfoListener.cs b/src/Windows/Avalonia.Win32/WindowsMountedVolumeInfoListener.cs index 3244e75a34..f2da804107 100644 --- a/src/Windows/Avalonia.Win32/WindowsMountedVolumeInfoListener.cs +++ b/src/Windows/Avalonia.Win32/WindowsMountedVolumeInfoListener.cs @@ -2,7 +2,6 @@ using System; using System.Collections.ObjectModel; using System.IO; using System.Linq; -using Avalonia.Reactive; using Avalonia.Controls.Platform; using Avalonia.Logging; using Avalonia.Threading; @@ -12,12 +11,12 @@ namespace Avalonia.Win32 internal class WindowsMountedVolumeInfoListener : IDisposable { private readonly IDisposable _disposable; - private bool _beenDisposed = false; - private ObservableCollection mountedDrives; + private bool _beenDisposed; + private readonly ObservableCollection _mountedDrives; public WindowsMountedVolumeInfoListener(ObservableCollection mountedDrives) { - this.mountedDrives = mountedDrives; + _mountedDrives = mountedDrives; _disposable = DispatcherTimer.Run(Poll, TimeSpan.FromSeconds(1)); @@ -51,14 +50,14 @@ namespace Avalonia.Win32 }) .ToArray(); - if (mountedDrives.SequenceEqual(mountVolInfos)) + if (_mountedDrives.SequenceEqual(mountVolInfos)) return true; else { - mountedDrives.Clear(); + _mountedDrives.Clear(); foreach (var i in mountVolInfos) - mountedDrives.Add(i); + _mountedDrives.Add(i); return true; } } diff --git a/src/tools/DevGenerators/Helpers.cs b/src/tools/DevGenerators/Helpers.cs index 3da89d2d0e..9cebf6daea 100644 --- a/src/tools/DevGenerators/Helpers.cs +++ b/src/tools/DevGenerators/Helpers.cs @@ -6,16 +6,21 @@ namespace Generator; static class Helpers { + private static readonly SymbolDisplayFormat s_symbolDisplayFormat = + SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions( + SymbolDisplayFormat.FullyQualifiedFormat.MiscellaneousOptions | + SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + public static StringBuilder Pad(this StringBuilder sb, int count) => sb.Append(' ', count * 4); public static string GetFullyQualifiedName(this ISymbol symbol) { - return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + return symbol.ToDisplayString(s_symbolDisplayFormat); } public static bool HasFullyQualifiedName(this ISymbol symbol, string name) { - return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == name; + return symbol.ToDisplayString(s_symbolDisplayFormat) == name; } public static bool HasAttributeWithFullyQualifiedName(this ISymbol symbol, string name) @@ -28,4 +33,4 @@ static class Helpers return false; } -} \ No newline at end of file +}