Browse Source

Win32 dispatcher fixes

pull/10691/head
Nikita Tsukanov 4 years ago
parent
commit
fe4945d395
  1. 35
      src/Avalonia.Base/Threading/Dispatcher.Timers.cs
  2. 2
      src/Avalonia.Base/Threading/DispatcherTimer.cs
  3. 2
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  4. 30
      src/Windows/Avalonia.Win32/Win32DispatcherImpl.cs
  5. 29
      src/Windows/Avalonia.Win32/Win32Platform.cs

35
src/Avalonia.Base/Threading/Dispatcher.Timers.cs

@ -17,23 +17,21 @@ public partial class Dispatcher
private void UpdateOSTimer() private void UpdateOSTimer()
{ {
lock (InstanceLock) VerifyAccess();
{ var nextDueTime =
var nextDueTime = (_dueTimeForTimers.HasValue && _dueTimeForBackgroundProcessing.HasValue) ?
(_dueTimeForTimers.HasValue && _dueTimeForBackgroundProcessing.HasValue) Math.Min(_dueTimeForTimers.Value, _dueTimeForBackgroundProcessing.Value) :
? Math.Min(_dueTimeForTimers.Value, _dueTimeForBackgroundProcessing.Value) _dueTimeForTimers ?? _dueTimeForBackgroundProcessing;
: _dueTimeForTimers ?? _dueTimeForBackgroundProcessing; if (_osTimerSetTo == nextDueTime)
if(_osTimerSetTo == nextDueTime) return;
return; _impl.UpdateTimer(_osTimerSetTo = nextDueTime);
_impl.UpdateTimer(_osTimerSetTo = nextDueTime);
}
} }
internal void UpdateOSTimerForTimers() internal void RescheduleTimers()
{ {
if (!CheckAccess()) if (!CheckAccess())
{ {
Post(UpdateOSTimerForTimers, DispatcherPriority.Send); Post(RescheduleTimers, DispatcherPriority.Send);
return; return;
} }
@ -89,7 +87,7 @@ public partial class Dispatcher
} }
} }
UpdateOSTimerForTimers(); RescheduleTimers();
} }
internal void RemoveTimer(DispatcherTimer timer) internal void RemoveTimer(DispatcherTimer timer)
@ -103,15 +101,18 @@ public partial class Dispatcher
} }
} }
UpdateOSTimerForTimers(); RescheduleTimers();
} }
private void OnOSTimer() private void OnOSTimer()
{ {
_impl.UpdateTimer(null);
_osTimerSetTo = null;
bool needToPromoteTimers = false; bool needToPromoteTimers = false;
bool needToProcessQueue = false; bool needToProcessQueue = false;
lock (InstanceLock) lock (InstanceLock)
{ {
_impl.UpdateTimer(_osTimerSetTo = null);
needToPromoteTimers = _dueTimeForTimers.HasValue && _dueTimeForTimers.Value <= Clock.TickCount; needToPromoteTimers = _dueTimeForTimers.HasValue && _dueTimeForTimers.Value <= Clock.TickCount;
if (needToPromoteTimers) if (needToPromoteTimers)
_dueTimeForTimers = null; _dueTimeForTimers = null;
@ -119,13 +120,13 @@ public partial class Dispatcher
_dueTimeForBackgroundProcessing.Value <= Clock.TickCount; _dueTimeForBackgroundProcessing.Value <= Clock.TickCount;
if (needToProcessQueue) if (needToProcessQueue)
_dueTimeForBackgroundProcessing = null; _dueTimeForBackgroundProcessing = null;
UpdateOSTimer();
} }
if (needToPromoteTimers) if (needToPromoteTimers)
PromoteTimers(); PromoteTimers();
if (needToProcessQueue) if (needToProcessQueue)
ExecuteJobsCore(); ExecuteJobsCore();
UpdateOSTimer();
} }
internal void PromoteTimers() internal void PromoteTimers()
@ -195,10 +196,10 @@ public partial class Dispatcher
} }
finally finally
{ {
UpdateOSTimerForTimers(); RescheduleTimers();
} }
} }
internal static List<DispatcherTimer> SnapshotTimersForUnitTests() => internal static List<DispatcherTimer> SnapshotTimersForUnitTests() =>
s_uiThread!._timers.ToList(); s_uiThread!._timers.ToList();
} }

2
src/Avalonia.Base/Threading/DispatcherTimer.cs

@ -132,7 +132,7 @@ public partial class DispatcherTimer
if (updateOSTimer) if (updateOSTimer)
{ {
_dispatcher.UpdateOSTimerForTimers(); _dispatcher.RescheduleTimers();
} }
} }
} }

2
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1796,7 +1796,7 @@ namespace Avalonia.Win32.Interop
QS_SENDMESSAGE = 0x0040, QS_SENDMESSAGE = 0x0040,
QS_HOTKEY = 0x0080, QS_HOTKEY = 0x0080,
QS_ALLPOSTMESSAGE = 0x0100, QS_ALLPOSTMESSAGE = 0x0100,
QS_EVENT = 0x0200, QS_EVENT = 0x02000,
QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON, QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON,
QS_INPUT = QS_MOUSE | QS_KEY, QS_INPUT = QS_MOUSE | QS_KEY,
QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY, QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY,

30
src/Windows/Avalonia.Win32/Win32DispatcherImpl.cs

@ -10,13 +10,10 @@ internal class Win32DispatcherImpl : IControlledDispatcherImpl, IDispatcherClock
{ {
private readonly IntPtr _messageWindow; private readonly IntPtr _messageWindow;
private static Thread? s_uiThread; private static Thread? s_uiThread;
private IntPtr? _timerHandle;
private readonly TimerProc _timerDelegate;
public Win32DispatcherImpl(IntPtr messageWindow) public Win32DispatcherImpl(IntPtr messageWindow)
{ {
_messageWindow = messageWindow; _messageWindow = messageWindow;
s_uiThread = Thread.CurrentThread; s_uiThread = Thread.CurrentThread;
_timerDelegate = TimerProc;
} }
public bool CurrentThreadIsLoopThread => s_uiThread == Thread.CurrentThread; public bool CurrentThreadIsLoopThread => s_uiThread == Thread.CurrentThread;
@ -37,26 +34,27 @@ internal class Win32DispatcherImpl : IControlledDispatcherImpl, IDispatcherClock
public event Action? Signaled; public event Action? Signaled;
public event Action? Timer; public event Action? Timer;
void TimerProc(IntPtr hWnd, uint uMsg, IntPtr nIdEvent, uint dwTime) => Timer?.Invoke(); public void FireTimer() => Timer?.Invoke();
public void UpdateTimer(int? dueTimeInMs) public void UpdateTimer(int? dueTimeInMs)
{ {
if (_timerHandle.HasValue)
KillTimer(IntPtr.Zero, _timerHandle.Value);
if (dueTimeInMs == null) if (dueTimeInMs == null)
return; {
KillTimer(_messageWindow, (IntPtr)Win32Platform.TIMERID_DISPATCHER);
var interval = (uint)Math.Max(1, TickCount - dueTimeInMs.Value); }
else
_timerHandle = SetTimer( {
IntPtr.Zero, var interval = (uint)Math.Max(1, TickCount - dueTimeInMs.Value);
IntPtr.Zero, SetTimer(
interval, _messageWindow,
_timerDelegate); (IntPtr)Win32Platform.TIMERID_DISPATCHER,
interval,
null!);
}
} }
public bool CanQueryPendingInput => true; public bool CanQueryPendingInput => true;
public bool HasPendingInput public bool HasPendingInput
{ {
get get

29
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -112,6 +112,7 @@ namespace Avalonia.Win32
private static readonly Win32Platform s_instance = new(); private static readonly Win32Platform s_instance = new();
private static Win32PlatformOptions? s_options; private static Win32PlatformOptions? s_options;
private static Compositor? s_compositor; private static Compositor? s_compositor;
internal const int TIMERID_DISPATCHER = 1;
private WndProc? _wndProcDelegate; private WndProc? _wndProcDelegate;
private IntPtr _hwnd; private IntPtr _hwnd;
@ -182,27 +183,7 @@ namespace Avalonia.Win32
s_compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(), platformGraphics); s_compositor = new Compositor(AvaloniaLocator.Current.GetRequiredService<IRenderLoop>(), platformGraphics);
} }
public bool HasMessages()
{
return PeekMessage(out _, IntPtr.Zero, 0, 0, 0);
}
public void ProcessMessage()
{
if (GetMessage(out var msg, IntPtr.Zero, 0, 0) > -1)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
else
{
Logging.Logger.TryGet(Logging.LogEventLevel.Error, Logging.LogArea.Win32Platform)
?.Log(this, "Unmanaged error in {0}. Error Code: {1}", nameof(ProcessMessage), Marshal.GetLastWin32Error());
}
}
public event EventHandler<ShutdownRequestedEventArgs>? ShutdownRequested; public event EventHandler<ShutdownRequestedEventArgs>? ShutdownRequested;
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")] [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]
@ -238,6 +219,12 @@ namespace Avalonia.Win32
win32PlatformSettings.OnColorValuesChanged(); win32PlatformSettings.OnColorValuesChanged();
} }
} }
if (msg == (uint)WindowsMessage.WM_TIMER)
{
if (wParam == (IntPtr)TIMERID_DISPATCHER)
_dispatcher?.FireTimer();
}
TrayIconImpl.ProcWnd(hWnd, msg, wParam, lParam); TrayIconImpl.ProcWnd(hWnd, msg, wParam, lParam);

Loading…
Cancel
Save