Browse Source

Merge branch 'master' into ime_improvements

pull/10328/head
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
d1abd749d8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
  2. 2
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  3. 32
      samples/GpuInterop/VulkanDemo/VulkanImage.cs
  4. 2
      src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs
  5. 4
      src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs
  6. 1
      src/Avalonia.Base/Rendering/IRenderTimer.cs
  7. 2
      src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
  8. 8
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  9. 2
      src/Avalonia.Controls/WindowBase.cs
  10. 2
      src/Windows/Avalonia.Win32/AngleOptions.cs
  11. 2
      src/Windows/Avalonia.Win32/Automation/AutomationNode.ExpandCollapse.cs
  12. 2
      src/Windows/Avalonia.Win32/Automation/AutomationNode.RangeValue.cs
  13. 2
      src/Windows/Avalonia.Win32/Automation/AutomationNode.Scroll.cs
  14. 8
      src/Windows/Avalonia.Win32/Automation/AutomationNode.Selection.cs
  15. 2
      src/Windows/Avalonia.Win32/Automation/AutomationNode.Toggle.cs
  16. 2
      src/Windows/Avalonia.Win32/Automation/AutomationNode.Value.cs
  17. 10
      src/Windows/Avalonia.Win32/Automation/AutomationNode.cs
  18. 2
      src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs
  19. 4
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  20. 30
      src/Windows/Avalonia.Win32/ClipboardFormats.cs
  21. 18
      src/Windows/Avalonia.Win32/ClipboardImpl.cs
  22. 37
      src/Windows/Avalonia.Win32/DataObject.cs
  23. 8
      src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs
  24. 28
      src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
  25. 41
      src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
  26. 40
      src/Windows/Avalonia.Win32/DirectX/directx.idl
  27. 2
      src/Windows/Avalonia.Win32/FramebufferManager.cs
  28. 78
      src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
  29. 9
      src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
  30. 3
      src/Windows/Avalonia.Win32/Interop/Automation/IGridProvider.cs
  31. 2
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragment.cs
  32. 5
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderFragmentRoot.cs
  33. 2
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple.cs
  34. 5
      src/Windows/Avalonia.Win32/Interop/Automation/IRawElementProviderSimple2.cs
  35. 2
      src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs
  36. 3
      src/Windows/Avalonia.Win32/Interop/Automation/IValueProvider.cs
  37. 10
      src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreProviderApi.cs
  38. 4
      src/Windows/Avalonia.Win32/Interop/Automation/UiaCoreTypesApi.cs
  39. 15
      src/Windows/Avalonia.Win32/Interop/TaskBarList.cs
  40. 54
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  41. 40
      src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
  42. 9
      src/Windows/Avalonia.Win32/OffscreenParentWindow.cs
  43. 12
      src/Windows/Avalonia.Win32/OleContext.cs
  44. 17
      src/Windows/Avalonia.Win32/OleDataObject.cs
  45. 43
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  46. 6
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleD3DTextureFeature.cs
  47. 2
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleEglInterface.cs
  48. 30
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalD3D11Texture2D.cs
  49. 20
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs
  50. 3
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32EglDisplay.cs
  51. 16
      src/Windows/Avalonia.Win32/OpenGl/Angle/AngleWin32PlatformGraphics.cs
  52. 16
      src/Windows/Avalonia.Win32/OpenGl/WglContext.cs
  53. 45
      src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs
  54. 122
      src/Windows/Avalonia.Win32/OpenGl/WglGdiResourceManager.cs
  55. 18
      src/Windows/Avalonia.Win32/OpenGl/WglPlatformOpenGlInterface.cs
  56. 4
      src/Windows/Avalonia.Win32/OpenGl/WglRestoreContext.cs
  57. 15
      src/Windows/Avalonia.Win32/PopupImpl.cs
  58. 19
      src/Windows/Avalonia.Win32/ScreenImpl.cs
  59. 32
      src/Windows/Avalonia.Win32/TrayIconImpl.cs
  60. 17
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  61. 42
      src/Windows/Avalonia.Win32/Win32NativeControlHost.cs
  62. 9
      src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs
  63. 50
      src/Windows/Avalonia.Win32/Win32Platform.cs
  64. 8
      src/Windows/Avalonia.Win32/Win32PlatformSettings.cs
  65. 12
      src/Windows/Avalonia.Win32/Win32StorageProvider.cs
  66. 27
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
  67. 7
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
  68. 49
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
  69. 10
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
  70. 11
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
  71. 16
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositorConnection.cs
  72. 20
      src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs
  73. 7
      src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs
  74. 8
      src/Windows/Avalonia.Win32/WinScreen.cs
  75. 69
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  76. 8
      src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs
  77. 7
      src/Windows/Avalonia.Win32/WindowImpl.WndProc.cs
  78. 157
      src/Windows/Avalonia.Win32/WindowImpl.cs
  79. 13
      src/Windows/Avalonia.Win32/WindowsMountedVolumeInfoListener.cs
  80. 11
      src/tools/DevGenerators/Helpers.cs

2
samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs

@ -47,7 +47,7 @@ public class D3DMemoryHelper
MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex|ResourceOptionFlags.SharedNthandle,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
});
}

2
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@ -173,7 +173,7 @@ public unsafe class VulkanContext : IDisposable
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, ref queueFamilyCount, familyProperties);
for (uint queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
{
var family = familyProperties[c];
var family = familyProperties[queueFamilyIndex];
if (!family.QueueFlags.HasAllFlags(QueueFlags.GraphicsBit))
continue;

32
samples/GpuInterop/VulkanDemo/VulkanImage.cs

@ -4,10 +4,13 @@ using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Vulkan;
using SharpDX.DXGI;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
using Device = Silk.NET.Vulkan.Device;
using Format = Silk.NET.Vulkan.Format;
namespace GpuInterop.VulkanDemo;
@ -24,7 +27,6 @@ public unsafe class VulkanImage : IDisposable
private ImageView? _imageView { get; set; }
private DeviceMemory _imageMemory { get; set; }
private SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
private IntPtr _win32ShareHandle;
internal Image? InternalHandle { get; private set; }
internal Format Format { get; }
@ -60,7 +62,7 @@ public unsafe class VulkanImage : IDisposable
//MipLevels = MipLevels != 0 ? MipLevels : (uint)Math.Floor(Math.Log(Math.Max(Size.Width, Size.Height), 2));
var handleType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
ExternalMemoryHandleTypeFlags.D3D11TextureKmtBit :
ExternalMemoryHandleTypeFlags.D3D11TextureBit :
ExternalMemoryHandleTypeFlags.OpaqueFDBit;
var externalMemoryCreateInfo = new ExternalMemoryImageCreateInfo
{
@ -108,14 +110,14 @@ public unsafe class VulkanImage : IDisposable
if (exportable && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource>();
_win32ShareHandle = dxgi.SharedHandle;
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
handleImport = new ImportMemoryWin32HandleInfoKHR
{
PNext = &dedicatedAllocation,
SType = StructureType.ImportMemoryWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureKmtBit,
Handle = _win32ShareHandle,
HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
};
}
@ -185,11 +187,19 @@ public unsafe class VulkanImage : IDisposable
return fd;
}
public IPlatformHandle Export() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
new PlatformHandle(_win32ShareHandle,
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle) :
new PlatformHandle(new IntPtr(ExportFd()),
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
public IPlatformHandle Export()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
using var dxgi = _d3dTexture2D!.QueryInterface<Resource1>();
return new PlatformHandle(
dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
}
else
return new PlatformHandle(new IntPtr(ExportFd()),
KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaquePosixFileDescriptor);
}
public ImageTiling Tiling => ImageTiling.Optimal;

2
src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs

@ -26,6 +26,6 @@ namespace Avalonia.Platform
bool CurrentThreadIsLoopThread { get; }
event Action<DispatcherPriority?> Signaled;
event Action<DispatcherPriority?>? Signaled;
}
}

4
src/Avalonia.Base/Platform/Storage/FilePickerFileType.cs

@ -7,9 +7,9 @@ namespace Avalonia.Platform.Storage;
/// </summary>
public sealed class FilePickerFileType
{
public FilePickerFileType(string name)
public FilePickerFileType(string? name)
{
Name = name;
Name = name ?? string.Empty;
}
/// <summary>

1
src/Avalonia.Base/Rendering/IRenderTimer.cs

@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using Avalonia.Metadata;
namespace Avalonia.Rendering

2
src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs

@ -13,6 +13,6 @@ namespace Avalonia.Platform
/// <remarks>
/// Raised on on OSX via the Quit menu or right-clicking on the application icon and selecting Quit.
/// </remarks>
event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
event EventHandler<ShutdownRequestedEventArgs>? ShutdownRequested;
}
}

8
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -19,7 +19,7 @@ namespace Avalonia.Platform
/// <summary>
/// Gets or sets a method called when the minimized/maximized state of the window changes.
/// </summary>
Action<WindowState> WindowStateChanged { get; set; }
Action<WindowState>? WindowStateChanged { get; set; }
/// <summary>
/// Sets the title of the window.
@ -42,7 +42,7 @@ namespace Avalonia.Platform
/// <summary>
/// Called when a disabled window received input. Can be used to activate child windows.
/// </summary>
Action GotInputWhenDisabled { get; set; }
Action? GotInputWhenDisabled { get; set; }
/// <summary>
/// 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.
/// </summary>
Func<WindowCloseReason, bool> Closing { get; set; }
Func<WindowCloseReason, bool>? Closing { get; set; }
/// <summary>
/// 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
/// <summary>
/// Gets or Sets an action that is called whenever one of the extend client area properties changed.
/// </summary>
Action<bool> ExtendClientAreaToDecorationsChanged { get; set; }
Action<bool>? ExtendClientAreaToDecorationsChanged { get; set; }
/// <summary>
/// Gets a flag that indicates if Managed decorations i.e. caption buttons are required.

2
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; }
/// <summary>
/// Gets or sets the owner of the window.

2
src/Windows/Avalonia.Win32/AngleOptions.cs

@ -17,6 +17,6 @@ namespace Avalonia.Win32
new GlVersion(GlProfileType.OpenGLES, 2, 0)
};
public IList<PlatformApi> AllowedPlatformApis { get; set; } = null;
public IList<PlatformApi>? AllowedPlatformApis { get; set; } = null;
}
}

2
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

2
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

2
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

8
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<ISelectionProvider, IReadOnlyList<AutomationPeer>>(x => x.GetSelection());
return peers?.Select(x => (UIA.IRawElementProviderSimple)GetOrCreate(x)!).ToArray() ??
Array.Empty<UIA.IRawElementProviderSimple>();
return peers.Select(x => (UIA.IRawElementProviderSimple)GetOrCreate(x)).ToArray();
}
void UIA.ISelectionItemProvider.AddToSelection() => InvokeSync<ISelectionItemProvider>(x => x.AddToSelection());

2
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

2
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

10
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<AutomationProperty, UiaPropertyId> s_propertyMap = new Dictionary<AutomationProperty, UiaPropertyId>()
private static Dictionary<AutomationProperty, UiaPropertyId> 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<AutomationPeer, AutomationNode> s_nodes =
new ConditionalWeakTable<AutomationPeer, AutomationNode>();
private static ConditionalWeakTable<AutomationPeer, AutomationNode> 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);

2
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")]

4
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -6,7 +6,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<Compile Include="..\..\Avalonia.Base\Metadata\NullableAttributes.cs" Link="NullableAttributes.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
@ -16,7 +15,8 @@
<MicroComIdl Include="Win32Com\win32.idl" CSharpInteropPath="Win32Com\Win32.Generated.cs" />
<MicroComIdl Include="DirectX\directx.idl" CSharpInteropPath="DirectX\directx.Generated.cs" />
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
<Import Project="..\..\..\build\System.Drawing.Common.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
<Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\SourceGenerators.props" />
<ItemGroup>

30
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<ClipboardFormat> FormatList = new List<ClipboardFormat>()
private static readonly List<ClipboardFormat> 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;
}

18
src/Windows/Avalonia.Win32/ClipboardImpl.cs

@ -30,7 +30,7 @@ namespace Avalonia.Win32
return Disposable.Create(() => UnmanagedMethods.CloseClipboard());
}
public async Task<string> GetTextAsync()
public async Task<string?> 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<object> GetDataAsync(string format)
public async Task<object?> GetDataAsync(string format)
{
Dispatcher.UIThread.VerifyAccess();
var i = OleRetryCount;

37
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<string> IDataObject.GetFileNames()
IEnumerable<string>? 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<string> files)
return WriteFileListToHGlobal(ref hGlobal, files);
if (data is Stream stream)
@ -286,7 +279,7 @@ namespace Avalonia.Win32
}
if (data is IEnumerable<byte> 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<string> 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
}

8
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
}

28
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<TimeSpan>? 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<bool>();
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<IRenderTimer>().ToConstant(connection);
@ -191,6 +179,4 @@ namespace Avalonia.Win32.DirectX
return tcs.Task.Result;
}
}
#nullable restore
#pragma warning restore CA1416 // Validate platform compatibility
}

41
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;
}
/// <inheritdoc />
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
}

40
src/Windows/Avalonia.Win32/DirectX/directx.idl

@ -36,6 +36,8 @@
@clr-map DXGI_SHARED_RESOURCE void*
@clr-map LUID ulong
@clr-map LPSTR ushort*
@clr-map LPWSTR ushort*
@clr-map LPCWSTR ushort*
enum DXGI_FORMAT
@ -501,6 +503,44 @@ interface ID3D11Device : IUnknown
UINT GetExceptionMode();
}
[uuid(a04bfb29-08ef-43d6-a49c-a9bdbdcbe686)]
interface ID3D11Device1 : ID3D11Device
{
void GetImmediateContext1( void** ppImmediateContext );
HRESULT CreateDeferredContext1(
UINT ContextFlags, // Reserved parameter; must be 0
[out, retval] IUnknown** ppDeferredContext );
HRESULT CreateBlendState1(
void* pBlendStateDesc,
[out, retval] IUnknown** ppBlendState );
HRESULT CreateRasterizerState1(
void* pRasterizerDesc,
[out, retval] IUnknown** ppRasterizerState );
HRESULT CreateDeviceContextState(
UINT Flags,
void* pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
GUID* EmulatedInterface,
void* pChosenFeatureLevel,
[out, retval] IUnknown** ppContextState);
HRESULT OpenSharedResource1(
IntPtr hResource,
Guid* ReturnedInterface,
[out, retval] IUnknown** ppResource);
HRESULT OpenSharedResourceByName(
LPCWSTR lpName,
DWORD dwDesiredAccess,
REFIID returnedInterface,
void** ppResource);
};
[uuid( 6f15aaf2-d208-4e89-9ab4-489535d34f9c)]
interface ID3D11Texture2D : IUnknown

2
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

78
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
/// <summary>
/// A Windows input method editor based on Windows Input Method Manager (IMM32).
/// </summary>
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()

9
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;

3
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; }
}

2
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)]

5
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();
}
}

2
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]

5
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
{

2
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

3
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)]

10
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);
}
}

4
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)]

15
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;
/// <summary>
/// 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<HrInit>((*ptr)->HrInit);
}
s_hrInitDelegate ??= Marshal.GetDelegateForFunctionPointer<HrInit>((*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<MarkFullscreenWindow>((*ptr)->MarkFullscreenWindow);
}
s_markFullscreenWindowDelegate ??=
Marshal.GetDelegateForFunctionPointer<MarkFullscreenWindow>((*ptr)->MarkFullscreenWindow);
s_markFullscreenWindowDelegate(s_taskBarList, hwnd, fullscreen);
}

54
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<T>(ref Guid clsid, ref Guid iid) where T : IUnknown
internal static T CreateInstance<T>(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<IUnknown>(pUnk, true);
return MicroComRuntime.QueryInterface<T>(unk);
return unk.QueryInterface<T>();
}
[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;
}
}

40
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;
@ -9,17 +8,42 @@ namespace Avalonia.Win32
{
internal class NonPumpingSyncContext : SynchronizationContext, IDisposable
{
private readonly SynchronizationContext _inner;
private readonly SynchronizationContext? _inner;
private NonPumpingSyncContext(SynchronizationContext inner)
private NonPumpingSyncContext(SynchronizationContext? inner)
{
_inner = inner;
SetWaitNotificationRequired();
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)
{
if (_inner is null)
{
#if NET6_0_OR_GREATER
ThreadPool.QueueUserWorkItem(static x => x.d(x.state), (d, state), false);
#else
ThreadPool.QueueUserWorkItem(_ => d(state));
#endif
}
else
{
_inner.Post(d, state);
}
}
public override void Send(SendOrPostCallback d, object? state)
{
if (_inner is null)
{
d(state);
}
else
{
_inner.Send(d, state);
}
}
#if !NET6_0_OR_GREATER
[PrePrepareMethod]
@ -32,7 +56,7 @@ namespace Avalonia.Win32
public void Dispose() => SetSynchronizationContext(_inner);
public static IDisposable Use()
public static IDisposable? Use()
{
var current = Current;
if (current == null)
@ -42,13 +66,13 @@ namespace Avalonia.Win32
}
if (current is NonPumpingSyncContext)
return null;
return new NonPumpingSyncContext(current);
}
internal class HelperImpl : NonPumpingLockHelper.IHelperImpl
{
IDisposable NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use();
IDisposable? NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use();
}
}
}

9
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
{

12
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")
{

17
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<string> GetFileNames()
public IEnumerable<string>? GetFileNames()
{
return (IEnumerable<string>)GetDataFromOleHGLOBAL(DataFormats.FileNames, DVASPECT.DVASPECT_CONTENT);
return (IEnumerable<string>?)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<string> ReadFileNamesFromHGlobal(IntPtr hGlobal)
{
List<string> files = new List<string>();
var files = new List<string>();
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

43
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<IDragDropDevice>();
_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;
}

6
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

2
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);

30
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<IDXGIResource>();
return new PlatformHandle(resource.SharedHandle,

20
src/Windows/Avalonia.Win32/OpenGl/Angle/AngleExternalObjectsFeature.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Avalonia.Controls.Documents;
using System.Linq;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
@ -15,12 +14,14 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
{
private readonly EglContext _context;
private readonly ID3D11Device _device;
private readonly ID3D11Device1 _device1;
public AngleExternalObjectsFeature(EglContext context)
{
_context = context;
var angle = (AngleWin32EglDisplay)context.Display;
_device = MicroComRuntime.CreateProxyFor<ID3D11Device>(angle.GetDirect3DDevice(), false).CloneReference();
_device1 = _device.QueryInterface<ID3D11Device1>();
using var dxgiDevice = _device.QueryInterface<IDXGIDevice>();
using var adapter = dxgiDevice.Adapter;
DeviceLuid = BitConverter.GetBytes(adapter.Desc.AdapterLuid);
@ -28,7 +29,8 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
public IReadOnlyList<string> SupportedImportableExternalImageTypes { get; } = new[]
{
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle,
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle,
};
public IReadOnlyList<string> SupportedExportableExternalImageTypes => SupportedImportableExternalImageTypes;
@ -72,13 +74,17 @@ internal class AngleExternalObjectsFeature : IGlContextExternalObjectsFeature, I
public unsafe IGlExternalImageTexture ImportImage(IPlatformHandle handle, PlatformGraphicsExternalImageProperties properties)
{
if (handle.HandleDescriptor != KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle)
if (!SupportedImportableExternalImageTypes.Contains(handle.HandleDescriptor))
throw new NotSupportedException("Unsupported external memory type");
using (_context.EnsureCurrent())
{
var guid = MicroComRuntime.GetGuidFor(typeof(ID3D11Texture2D));
using var opened = _device.OpenSharedResource(handle.Handle, &guid);
using var opened =
handle.HandleDescriptor ==
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle ?
_device.OpenSharedResource(handle.Handle, &guid) :
_device1.OpenSharedResource1(handle.Handle, &guid);
using var texture = opened.QueryInterface<ID3D11Texture2D>();
return new AngleExternalMemoryD3D11Texture2D(_context, texture, properties);
}
@ -93,8 +99,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()
{

3
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)

16
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);

16
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<GlVersion> preferredVersions = null)
public IGlContext? CreateSharedContext(IEnumerable<GlVersion>? 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;
}
}

45
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<WglCreateContextAttribsARBDelegate>(
s_wglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer<WglCreateContextAttribsARBDelegate>(
wglGetProcAddress("wglCreateContextAttribsARB"));
WglChoosePixelFormatArb =
s_wglChoosePixelFormatArb =
Marshal.GetDelegateForFunctionPointer<WglChoosePixelFormatARBDelegate>(
wglGetProcAddress("wglChoosePixelFormatARB"));
GlDebugMessageCallback =
s_glDebugMessageCallback =
Marshal.GetDelegateForFunctionPointer<GlDebugMessageCallbackDelegate>(
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);

122
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<IntPtr> Result;
public readonly IntPtr Window;
public readonly TaskCompletionSource<IntPtr> Result;
public GetDCOp(IntPtr window, TaskCompletionSource<IntPtr> result)
{
Window = window;
Result = result;
}
}
class ReleaseDCOp
private class ReleaseDCOp
{
public IntPtr Window;
public IntPtr DC;
public TaskCompletionSource<object> Result;
public readonly IntPtr Window;
public readonly IntPtr DC;
public readonly TaskCompletionSource<object?> Result;
public ReleaseDCOp(IntPtr window, IntPtr dc, TaskCompletionSource<object?> result)
{
Window = window;
DC = dc;
Result = result;
}
}
class CreateWindowOp
private class CreateWindowOp
{
public TaskCompletionSource<IntPtr> Result;
public readonly TaskCompletionSource<IntPtr> Result;
public CreateWindowOp(TaskCompletionSource<IntPtr> result)
{
Result = result;
}
}
class DestroyWindowOp
private class DestroyWindowOp
{
public IntPtr Window;
public TaskCompletionSource<object> Result;
public readonly IntPtr Window;
public readonly TaskCompletionSource<object?> Result;
public DestroyWindowOp(IntPtr window, TaskCompletionSource<object?> result)
{
Window = window;
Result = result;
}
}
private static readonly Queue<object> s_Queue = new();
private static readonly AutoResetEvent s_Event = new(false);
private static readonly ushort s_WindowClass;
private static readonly Queue<object> 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<IntPtr>();
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<IntPtr>();
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<object>();
lock(s_Queue)
s_Queue.Enqueue(new ReleaseDCOp()
{
Window = hWnd,
DC = hDC,
Result = tcs
});
s_Event.Set();
var tcs = new TaskCompletionSource<object?>();
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<object>();
lock(s_Queue)
s_Queue.Enqueue(new DestroyWindowOp()
{
Window = hWnd,
Result = tcs
});
s_Event.Set();
var tcs = new TaskCompletionSource<object?>();
lock (s_queue)
s_queue.Enqueue(new DestroyWindowOp(hWnd, tcs));
s_event.Set();
tcs.Task.Wait();
}
}

18
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<Win32PlatformOptions>() ?? 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)
{

4
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();

15
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; }

19
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;
/// <inheritdoc />
public int ScreenCount
{
get => GetSystemMetrics(SystemMetric.SM_CMONITORS);
}
private Screen[] _allScreens;
/// <inheritdoc />
public IReadOnlyList<Screen> 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)
/// <inheritdoc />
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)
/// <inheritdoc />
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)
/// <inheritdoc />
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<WinScreen>().FirstOrDefault(m => m.Handle == handle);
}

32
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<int, TrayIconImpl> s_trayIcons = new Dictionary<int, TrayIconImpl>();
private static readonly Dictionary<int, TrayIconImpl> 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
}
}
/// <inheritdoc />
public void SetIcon(IWindowIconImpl? icon)
{
_icon = icon as IconImpl;
UpdateIcon();
}
/// <inheritdoc />
public void SetIsVisible(bool visible)
{
UpdateIcon(!visible);
}
/// <inheritdoc />
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;
}
}

17
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<IPlatformGraphics>().ToConstant(gl);
AvaloniaLocator.CurrentMutable.Bind<IPlatformGraphics>().ToConstant(gl);
if (gl is not null)
{
AvaloniaLocator.CurrentMutable.Bind<IPlatformGraphics>().ToConstant(gl);
}
return gl;
}
static IPlatformGraphics InitializeCore()
private static IPlatformGraphics? InitializeCore()
{
var opts = AvaloniaLocator.Current.GetService<Win32PlatformOptions>() ?? new Win32PlatformOptions();
@ -55,7 +56,5 @@ namespace Avalonia.Win32
return null;
}
}
}

42
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<IPlatformHandle, IPlatformHandle> 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

9
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<MenuItem> Populate(NativeMenu nativeMenu)
private static AvaloniaList<MenuItem> Populate(NativeMenu nativeMenu)
{
var result = new AvaloniaList<MenuItem>();

50
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<Delegate> _delegates = new List<Delegate>();
private readonly List<Delegate> _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<IMountedVolumeInfoProvider>().ToConstant(new WindowsMountedVolumeInfoProvider())
.Bind<IPlatformLifetimeEventsImpl>().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<IPlatformDragSource>().ToSingleton<DragSource>();
Compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(), platformGraphics);
s_compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(), 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<DispatcherPriority?> Signaled;
public event Action<DispatcherPriority?>? Signaled;
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
public event EventHandler<ShutdownRequestedEventArgs>? 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<UnmanagedMethods.WNDCLASSEX>(),
cbSize = Marshal.SizeOf<WNDCLASSEX>(),
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();
}

8
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)),
};
}

12
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<UnmanagedMethods.COMDLG_FILTERSPEC>();
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)
};

27
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)
{

7
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();

49
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<ICompositionSurface>();
_surfaceInterop = _drawingSurface.QueryInterface<ICompositionDrawingSurfaceInterop>();
}
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;
}
}
}
}

10
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();
}
}
}

11
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<ICompositionBrush>();
}
public static unsafe ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor)
public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor)
{
using var backDropParameterFactory =
NativeWinRTMethods.CreateActivationFactory<ICompositionEffectSourceParameterFactory>(
@ -39,7 +38,7 @@ internal static class WinUiCompositionUtils
return compositionEffectBrush.QueryInterface<ICompositionBrush>();
}
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();
}
}
}
}

16
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<TimeSpan> Tick;
public event Action<TimeSpan>? Tick;
public bool RunsInBackground => true;
public unsafe WinUiCompositorConnection()
public WinUiCompositorConnection()
{
using var compositor = NativeWinRTMethods.CreateInstance<ICompositor>("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<bool>();
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)

20
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
{

7
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()
{
}

8
src/Windows/Avalonia.Win32/WinScreen.cs

@ -15,14 +15,16 @@ namespace Avalonia.Win32
public IntPtr Handle => _hMonitor;
/// <inheritdoc />
public override int GetHashCode()
{
return (int)_hMonitor;
return _hMonitor.GetHashCode();
}
public override bool Equals(object obj)
/// <inheritdoc />
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;
}
}
}

69
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();
@ -145,7 +142,7 @@ namespace Avalonia.Win32
e = new RawKeyEventArgs(
WindowsKeyboardDevice.Instance,
timestamp,
_owner,
Owner,
RawKeyEventType.KeyDown,
key,
WindowsKeyboardDevice.Instance.Modifiers);
@ -175,7 +172,7 @@ namespace Avalonia.Win32
e = new RawKeyEventArgs(
WindowsKeyboardDevice.Instance,
timestamp,
_owner,
Owner,
RawKeyEventType.KeyUp,
key,
WindowsKeyboardDevice.Instance.Modifiers);
@ -187,7 +184,7 @@ namespace Avalonia.Win32
// Ignore control chars and chars that were handled in WM_KEYDOWN.
if (ToInt32(wParam) >= 32 && !_ignoreWmChar)
{
e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _owner,
e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, Owner,
new string((char)ToInt32(wParam), 1));
}
@ -212,8 +209,10 @@ namespace Avalonia.Win32
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
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;
@ -244,8 +243,10 @@ namespace Avalonia.Win32
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
Owner,
#pragma warning disable CS8509
message switch
#pragma warning restore CS8509
{
WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp,
WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp,
@ -312,12 +313,12 @@ namespace Avalonia.Win32
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
Owner,
RawPointerEventType.Move,
point,
GetMouseModifiers(wParam))
{
IntermediatePoints = new Lazy<IReadOnlyList<RawPointerPoint>>(() => CreateLazyIntermediatePoints(currPoint, prevPoint))
IntermediatePoints = new Lazy<IReadOnlyList<RawPointerPoint>?>(() => CreateIntermediatePoints(currPoint, prevPoint))
};
break;
@ -332,7 +333,7 @@ namespace Avalonia.Win32
e = new RawMouseWheelEventArgs(
_mouseDevice,
timestamp,
_owner,
Owner,
PointToClient(PointFromLParam(lParam)),
new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta),
GetMouseModifiers(wParam));
@ -348,7 +349,7 @@ namespace Avalonia.Win32
e = new RawMouseWheelEventArgs(
_mouseDevice,
timestamp,
_owner,
Owner,
PointToClient(PointFromLParam(lParam)),
new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0),
GetMouseModifiers(wParam));
@ -365,7 +366,7 @@ namespace Avalonia.Win32
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
Owner,
RawPointerEventType.LeaveWindow,
new Point(-1, -1),
WindowsKeyboardDevice.Instance.Modifiers);
@ -384,8 +385,10 @@ namespace Avalonia.Win32
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
Owner,
#pragma warning disable CS8509
message switch
#pragma warning restore CS8509
{
WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType
.NonClientLeftButtonDown,
@ -396,12 +399,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 || Input is not { } input)
{
break;
}
@ -414,8 +417,8 @@ namespace Avalonia.Win32
{
foreach (var touchInput in touchInputs)
{
Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time,
_owner,
input.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time,
Owner,
touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_UP) ?
RawPointerEventType.TouchEnd :
touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_DOWN) ?
@ -474,7 +477,7 @@ namespace Avalonia.Win32
var val = (ToInt32(wParam) >> 16) / wheelDelta;
var delta = message == WindowsMessage.WM_POINTERWHEEL ? new Vector(0, val) : new Vector(val, 0);
e = new RawMouseWheelEventArgs(device, timestamp, _owner, point.Position, delta, modifiers)
e = new RawMouseWheelEventArgs(device, timestamp, Owner, point.Position, delta, modifiers)
{
RawPointerId = info.pointerId
};
@ -488,7 +491,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 +729,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 +778,12 @@ namespace Avalonia.Win32
}
}
private unsafe Lazy<IReadOnlyList<RawPointerPoint>> CreateLazyIntermediatePoints(POINTER_INFO info)
private Lazy<IReadOnlyList<RawPointerPoint>?>? CreateLazyIntermediatePoints(POINTER_INFO info)
{
var historyCount = Math.Min((int)info.historyCount, MaxPointerHistorySize);
if (historyCount > 1)
{
return new Lazy<IReadOnlyList<RawPointerPoint>>(() =>
return new Lazy<IReadOnlyList<RawPointerPoint>?>(() =>
{
s_intermediatePointsPooledList.Clear();
s_intermediatePointsPooledList.Capacity = historyCount;
@ -829,7 +832,7 @@ namespace Avalonia.Win32
return null;
}
private unsafe IReadOnlyList<RawPointerPoint> CreateLazyIntermediatePoints(MOUSEMOVEPOINT movePoint, MOUSEMOVEPOINT prevMovePoint)
private unsafe IReadOnlyList<RawPointerPoint> 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
@ -891,8 +894,8 @@ namespace Avalonia.Win32
private RawPointerEventArgs CreatePointerArgs(IInputDevice device, ulong timestamp, 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 +1032,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;
}

8
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)
{

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

157
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<WindowImpl> s_instances = new List<WindowImpl>();
private static readonly List<WindowImpl> 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<WindowEdge, HitTestValues> s_edgeLookup =
new Dictionary<WindowEdge, HitTestValues>
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,32 @@ namespace Avalonia.Win32
s_instances.Add(this);
}
public Action Activated { get; set; }
private IInputRoot Owner
=> _owner ?? throw new InvalidOperationException($"{nameof(SetInputRoot)} must have been called");
public Func<WindowCloseReason, bool> Closing { get; set; }
public Action? Activated { get; set; }
public Action Closed { get; set; }
public Func<WindowCloseReason, bool>? Closing { get; set; }
public Action Deactivated { get; set; }
public Action? Closed { get; set; }
public Action<RawInputEventArgs> Input { get; set; }
public Action? Deactivated { get; set; }
public Action<Rect> Paint { get; set; }
public Action<RawInputEventArgs>? Input { get; set; }
public Action<Size, PlatformResizeReason> Resized { get; set; }
public Action<Rect>? Paint { get; set; }
public Action<double> ScalingChanged { get; set; }
public Action<Size, PlatformResizeReason>? Resized { get; set; }
public Action<PixelPoint> PositionChanged { get; set; }
public Action<double>? ScalingChanged { get; set; }
public Action<WindowState> WindowStateChanged { get; set; }
public Action<PixelPoint>? PositionChanged { get; set; }
public Action LostFocus { get; set; }
public Action<WindowState>? WindowStateChanged { get; set; }
public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
public Action? LostFocus { get; set; }
public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; }
public Thickness BorderThickness
{
@ -320,7 +316,7 @@ namespace Avalonia.Win32
private bool IsMouseInPointerEnabled => _wmPointerEnabled && IsMouseInPointerEnabled();
public object TryGetFeature(Type featureType)
public object? TryGetFeature(Type featureType)
{
if (featureType == typeof(ITextInputMethodImpl))
{
@ -339,7 +335,7 @@ namespace Avalonia.Win32
return null;
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{
TransparencyLevel = EnableBlur(transparencyLevel);
@ -521,7 +517,10 @@ namespace Avalonia.Win32
}
}
public IEnumerable<object> Surfaces => new object[] { (IPlatformNativeSurfaceHandle)Handle, _gl, _framebuffer };
public IEnumerable<object> Surfaces
=> _gl is null ?
new object[] { Handle, _framebuffer } :
new object[] { Handle, _gl, _framebuffer };
public PixelPoint Position
{
@ -611,7 +610,7 @@ namespace Avalonia.Win32
SetForegroundWindow(_hwnd);
}
public IPopupImpl CreatePopup() => Win32Platform.UseOverlayPopups ? null : new PopupImpl(this);
public IPopupImpl? CreatePopup() => Win32Platform.UseOverlayPopups ? null : new PopupImpl(this);
public void Dispose()
{
@ -672,7 +671,7 @@ namespace Avalonia.Win32
public void SetInputRoot(IInputRoot inputRoot)
{
_owner = inputRoot;
CreateDropTarget();
CreateDropTarget(inputRoot);
}
public void Hide()
@ -687,11 +686,11 @@ namespace Avalonia.Win32
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;
@ -727,30 +726,28 @@ 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)
{
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);
@ -829,6 +826,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 +845,7 @@ namespace Avalonia.Win32
style = (int)windowClassStyle,
lpfnWndProc = _wndProcDelegate,
hInstance = GetModuleHandle(null),
hCursor = DefaultCursor,
hCursor = s_defaultCursor,
hbrBackground = IntPtr.Zero,
lpszClassName = _className
};
@ -878,20 +878,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<IDragDropDevice>() is { } dragDropDevice)
{
_dropTarget = odt;
var odt = new OleDropTarget(this, inputRoot, dragDropDevice);
if (OleContext.Current?.RegisterDragDrop(Handle, odt) ?? false)
{
_dropTarget = odt;
}
}
}
@ -1105,7 +1108,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 +1373,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);
@ -1433,7 +1436,7 @@ namespace Avalonia.Win32
public bool IsClientAreaExtendedToDecorations => _isClientAreaExtended;
/// <inheritdoc/>
public Action<bool> ExtendClientAreaToDecorationsChanged { get; set; }
public Action<bool>? ExtendClientAreaToDecorationsChanged { get; set; }
/// <inheritdoc/>
public bool NeedsManagedDecorations => _isClientAreaExtended && _extendChromeHints.HasAllFlags(ExtendClientAreaChromeHints.PreferSystemChrome);

13
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<MountedVolumeInfo> mountedDrives;
private bool _beenDisposed;
private readonly ObservableCollection<MountedVolumeInfo> _mountedDrives;
public WindowsMountedVolumeInfoListener(ObservableCollection<MountedVolumeInfo> 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;
}
}

11
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;
}
}
}

Loading…
Cancel
Save