diff --git a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs index 38a23f918f..40cf81358f 100644 --- a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs +++ b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs @@ -1,3 +1,5 @@ +using System; +using System.Runtime.ConstrainedExecution; using System.Threading; namespace Avalonia.Threading @@ -7,6 +9,20 @@ namespace Avalonia.Threading /// public class AvaloniaSynchronizationContext : SynchronizationContext { + public interface INonPumpingPlatformWaitProvider + { + int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); + } + + private readonly INonPumpingPlatformWaitProvider _waitProvider; + + public AvaloniaSynchronizationContext(INonPumpingPlatformWaitProvider waitProvider) + { + _waitProvider = waitProvider; + if (_waitProvider != null) + SetWaitNotificationRequired(); + } + /// /// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer. /// @@ -22,7 +38,8 @@ namespace Avalonia.Threading return; } - SetSynchronizationContext(new AvaloniaSynchronizationContext()); + SetSynchronizationContext(new AvaloniaSynchronizationContext(AvaloniaLocator.Current + .GetService())); } /// @@ -39,5 +56,13 @@ namespace Avalonia.Threading else Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait(); } + + [PrePrepareMethod] + public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) + { + if (_waitProvider != null) + return _waitProvider.Wait(waitHandles, waitAll, millisecondsTimeout); + return base.Wait(waitHandles, waitAll, millisecondsTimeout); + } } } diff --git a/src/Avalonia.FreeDesktop/DBusHelper.cs b/src/Avalonia.FreeDesktop/DBusHelper.cs index b445f86613..91c4c28995 100644 --- a/src/Avalonia.FreeDesktop/DBusHelper.cs +++ b/src/Avalonia.FreeDesktop/DBusHelper.cs @@ -43,7 +43,7 @@ namespace Avalonia.FreeDesktop public void Initialized() { lock (_lock) - _ctx = new AvaloniaSynchronizationContext(); + _ctx = new AvaloniaSynchronizationContext(null); } } public static Connection Connection { get; private set; } diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 1aec4f0016..392ca31282 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -1382,6 +1383,22 @@ namespace Avalonia.Win32.Interop throw new Exception("RtlGetVersion failed!"); } } + + [DllImport("kernel32", EntryPoint="WaitForMultipleObjectsEx", SetLastError = true, CharSet = CharSet.Auto)] + private static extern int IntWaitForMultipleObjectsEx(int nCount, IntPtr[] pHandles, bool bWaitAll, int dwMilliseconds, bool bAlertable); + + public const int WAIT_FAILED = unchecked((int)0xFFFFFFFF); + + internal static int WaitForMultipleObjectsEx(int nCount, IntPtr[] pHandles, bool bWaitAll, int dwMilliseconds, bool bAlertable) + { + int result = IntWaitForMultipleObjectsEx(nCount, pHandles, bWaitAll, dwMilliseconds, bAlertable); + if(result == WAIT_FAILED) + { + throw new Win32Exception(); + } + + return result; + } [DllImport("user32.dll")] internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data); diff --git a/src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs b/src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs new file mode 100644 index 0000000000..a0160fcfbd --- /dev/null +++ b/src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs @@ -0,0 +1,15 @@ +using System; +using Avalonia.Threading; +using Avalonia.Win32.Interop; + +namespace Avalonia.Win32 +{ + internal class NonPumpingWaitProvider : AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider + { + public int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) + { + return UnmanagedMethods.WaitForMultipleObjectsEx(waitHandles.Length, waitHandles, waitAll, + millisecondsTimeout, false); + } + } +} diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index b7bb0e19ba..af6058d197 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -93,6 +93,7 @@ namespace Avalonia.Win32 .Bind().ToConstant(s_instance) .Bind().ToSingleton() .Bind().ToConstant(s_instance) + .Bind().ToConstant(new NonPumpingWaitProvider()) .Bind().ToConstant(new WindowsMountedVolumeInfoProvider()); if (options.AllowEglInitialization)