From 2b08668c644225edb78f841c7ac529704dab4623 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Sun, 12 Feb 2023 12:14:05 +0100 Subject: [PATCH] Addressed feedback on PR #10307 --- .../Avalonia.Win32/NonPumpingSyncContext.cs | 43 ++++++++++-- .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 67 ++++++++----------- src/Windows/Avalonia.Win32/WindowImpl.cs | 57 ++-------------- 3 files changed, 71 insertions(+), 96 deletions(-) diff --git a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs index 0c02f643b2..2c4d2c9468 100644 --- a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs +++ b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs @@ -8,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] @@ -34,7 +59,15 @@ namespace Avalonia.Win32 public static IDisposable? Use() { var current = Current; - return current is null or NonPumpingSyncContext ? null : new NonPumpingSyncContext(current); + if (current == null) + { + if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) + return null; + } + if (current is NonPumpingSyncContext) + return null; + + return new NonPumpingSyncContext(current); } internal class HelperImpl : NonPumpingLockHelper.IHelperImpl diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 288bdf2448..ed80f88b53 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -137,12 +137,12 @@ namespace Avalonia.Win32 { var key = KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)); - if (key != Key.None && _owner is not null) + if (key != Key.None) { e = new RawKeyEventArgs( WindowsKeyboardDevice.Instance, timestamp, - _owner, + Owner, RawKeyEventType.KeyDown, key, WindowsKeyboardDevice.Instance.Modifiers); @@ -167,12 +167,12 @@ namespace Avalonia.Win32 { var key = KeyInterop.KeyFromVirtualKey(ToInt32(wParam), ToInt32(lParam)); - if (key != Key.None && _owner is not null) + if (key != Key.None) { e = new RawKeyEventArgs( WindowsKeyboardDevice.Instance, timestamp, - _owner, + Owner, RawKeyEventType.KeyUp, key, WindowsKeyboardDevice.Instance.Modifiers); @@ -182,9 +182,9 @@ namespace Avalonia.Win32 case WindowsMessage.WM_CHAR: { // Ignore control chars and chars that were handled in WM_KEYDOWN. - if (ToInt32(wParam) >= 32 && !_ignoreWmChar && _owner is not null) + 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)); } @@ -201,7 +201,7 @@ namespace Avalonia.Win32 break; } shouldTakeFocus = ShouldTakeFocusOnClick; - if (ShouldIgnoreTouchEmulatedMessage() || _owner is null) + if (ShouldIgnoreTouchEmulatedMessage()) { break; } @@ -209,7 +209,7 @@ namespace Avalonia.Win32 e = new RawPointerEventArgs( _mouseDevice, timestamp, - _owner, + Owner, #pragma warning disable CS8509 message switch #pragma warning restore CS8509 @@ -235,7 +235,7 @@ namespace Avalonia.Win32 { break; } - if (ShouldIgnoreTouchEmulatedMessage() || _owner is null) + if (ShouldIgnoreTouchEmulatedMessage()) { break; } @@ -243,7 +243,7 @@ namespace Avalonia.Win32 e = new RawPointerEventArgs( _mouseDevice, timestamp, - _owner, + Owner, #pragma warning disable CS8509 message switch #pragma warning restore CS8509 @@ -310,15 +310,10 @@ namespace Avalonia.Win32 var prevPoint = _lastWmMousePoint; _lastWmMousePoint = currPoint; - if (_owner is null) - { - break; - } - e = new RawPointerEventArgs( _mouseDevice, timestamp, - _owner, + Owner, RawPointerEventType.Move, point, GetMouseModifiers(wParam)) @@ -331,14 +326,14 @@ namespace Avalonia.Win32 case WindowsMessage.WM_MOUSEWHEEL: { - if (IsMouseInPointerEnabled || _owner is null) + if (IsMouseInPointerEnabled) { break; } e = new RawMouseWheelEventArgs( _mouseDevice, timestamp, - _owner, + Owner, PointToClient(PointFromLParam(lParam)), new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta), GetMouseModifiers(wParam)); @@ -347,14 +342,14 @@ namespace Avalonia.Win32 case WindowsMessage.WM_MOUSEHWHEEL: { - if (IsMouseInPointerEnabled || _owner is null) + if (IsMouseInPointerEnabled) { break; } e = new RawMouseWheelEventArgs( _mouseDevice, timestamp, - _owner, + Owner, PointToClient(PointFromLParam(lParam)), new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam)); @@ -368,14 +363,10 @@ namespace Avalonia.Win32 break; } _trackingMouse = false; - if (_owner is null) - { - break; - } e = new RawPointerEventArgs( _mouseDevice, timestamp, - _owner, + Owner, RawPointerEventType.LeaveWindow, new Point(-1, -1), WindowsKeyboardDevice.Instance.Modifiers); @@ -387,14 +378,14 @@ namespace Avalonia.Win32 case WindowsMessage.WM_NCMBUTTONDOWN: case WindowsMessage.WM_NCXBUTTONDOWN: { - if (IsMouseInPointerEnabled || _owner is null) + if (IsMouseInPointerEnabled) { break; } e = new RawPointerEventArgs( _mouseDevice, timestamp, - _owner, + Owner, #pragma warning disable CS8509 message switch #pragma warning restore CS8509 @@ -413,7 +404,7 @@ namespace Avalonia.Win32 } case WindowsMessage.WM_TOUCH: { - if (_wmPointerEnabled || _owner is null || Input is not { } input) + if (_wmPointerEnabled || Input is not { } input) { break; } @@ -427,7 +418,7 @@ namespace Avalonia.Win32 foreach (var touchInput in touchInputs) { input.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time, - _owner, + Owner, touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_UP) ? RawPointerEventType.TouchEnd : touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_DOWN) ? @@ -450,14 +441,14 @@ namespace Avalonia.Win32 case WindowsMessage.WM_POINTERUP: case WindowsMessage.WM_POINTERUPDATE: { - if (!_wmPointerEnabled || _owner is null) + if (!_wmPointerEnabled) { break; } GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp); var eventType = GetEventType(message, info); - var args = CreatePointerArgs(device, timestamp, _owner, eventType, point, modifiers, info.pointerId); + var args = CreatePointerArgs(device, timestamp, eventType, point, modifiers, info.pointerId); args.IntermediatePoints = CreateLazyIntermediatePoints(info); e = args; break; @@ -466,19 +457,19 @@ namespace Avalonia.Win32 case WindowsMessage.WM_POINTERLEAVE: case WindowsMessage.WM_POINTERCAPTURECHANGED: { - if (!_wmPointerEnabled || _owner is null) + if (!_wmPointerEnabled) { break; } GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp); var eventType = device is TouchDevice ? RawPointerEventType.TouchCancel : RawPointerEventType.LeaveWindow; - e = CreatePointerArgs(device, timestamp, _owner, eventType, point, modifiers, info.pointerId); + e = CreatePointerArgs(device, timestamp, eventType, point, modifiers, info.pointerId); break; } case WindowsMessage.WM_POINTERWHEEL: case WindowsMessage.WM_POINTERHWHEEL: { - if (!_wmPointerEnabled || _owner is null) + if (!_wmPointerEnabled) { break; } @@ -486,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 }; @@ -900,11 +891,11 @@ namespace Avalonia.Win32 } } - private RawPointerEventArgs CreatePointerArgs(IInputDevice device, ulong timestamp, IInputRoot owner, RawPointerEventType eventType, RawPointerPoint point, RawInputModifiers modifiers, uint rawPointerId) + 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 }; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 57407b5f34..812c72fd3c 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -180,40 +180,31 @@ namespace Avalonia.Win32 s_instances.Add(this); } - /// + private IInputRoot Owner + => _owner ?? throw new InvalidOperationException($"{nameof(SetInputRoot)} must have been called"); + public Action? Activated { get; set; } - /// public Func? Closing { get; set; } - /// public Action? Closed { get; set; } - /// public Action? Deactivated { get; set; } - /// public Action? Input { get; set; } - /// public Action? Paint { get; set; } - /// public Action? Resized { get; set; } - /// public Action? ScalingChanged { get; set; } - /// public Action? PositionChanged { get; set; } - /// public Action? WindowStateChanged { get; set; } - /// public Action? LostFocus { get; set; } - /// public Action? TransparencyLevelChanged { get; set; } public Thickness BorderThickness @@ -245,13 +236,10 @@ namespace Avalonia.Win32 private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.Scaling ?? 1; - /// public double RenderScaling => _scaling; - /// public double DesktopScaling => RenderScaling; - /// public Size ClientSize { get @@ -262,7 +250,6 @@ namespace Avalonia.Win32 } } - /// public Size? FrameSize { get @@ -278,18 +265,14 @@ namespace Avalonia.Win32 } } - /// public IScreenImpl Screen { get; } - /// public IPlatformHandle Handle { get; private set; } - /// public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / RenderScaling, _maxTrackSize.Y / RenderScaling); public IMouseDevice MouseDevice => _mouseDevice; - /// public WindowState WindowState { get @@ -327,14 +310,12 @@ namespace Avalonia.Win32 } } - /// public WindowTransparencyLevel TransparencyLevel { get; private set; } protected IntPtr Hwnd => _hwnd; private bool IsMouseInPointerEnabled => _wmPointerEnabled && IsMouseInPointerEnabled(); - /// public object? TryGetFeature(Type featureType) { if (featureType == typeof(ITextInputMethodImpl)) @@ -355,7 +336,6 @@ namespace Avalonia.Win32 return null; } - /// public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { TransparencyLevel = EnableBlur(transparencyLevel); @@ -537,13 +517,11 @@ namespace Avalonia.Win32 } } - /// public IEnumerable Surfaces => _gl is null ? new object[] { Handle, _framebuffer } : new object[] { Handle, _gl, _framebuffer }; - /// public PixelPoint Position { get @@ -589,21 +567,17 @@ namespace Avalonia.Win32 } } - /// public void Move(PixelPoint point) => Position = point; - /// public void SetMinMaxSize(Size minSize, Size maxSize) { _minSize = minSize; _maxSize = maxSize; } - /// public IRenderer CreateRenderer(IRenderRoot root) => new CompositingRenderer(root, Win32Platform.Compositor, () => Surfaces); - /// public void Resize(Size value, PlatformResizeReason reason) { if (WindowState != WindowState.Normal) @@ -631,16 +605,13 @@ namespace Avalonia.Win32 } } - /// public void Activate() { SetForegroundWindow(_hwnd); } - /// public IPopupImpl? CreatePopup() => Win32Platform.UseOverlayPopups ? null : new PopupImpl(this); - /// public void Dispose() { (_gl as IDisposable)?.Dispose(); @@ -682,7 +653,6 @@ namespace Avalonia.Win32 InvalidateRect(_hwnd, ref r, false); } - /// public Point PointToClient(PixelPoint point) { var p = new POINT { X = point.X, Y = point.Y }; @@ -690,7 +660,6 @@ namespace Avalonia.Win32 return new Point(p.X, p.Y) / RenderScaling; } - /// public PixelPoint PointToScreen(Point point) { point *= RenderScaling; @@ -699,31 +668,26 @@ namespace Avalonia.Win32 return new PixelPoint(p.X, p.Y); } - /// public void SetInputRoot(IInputRoot inputRoot) { _owner = inputRoot; CreateDropTarget(inputRoot); } - /// public void Hide() { UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide); _shown = false; } - /// public virtual void Show(bool activate, bool isDialog) { SetParent(_parent); ShowWindow(_showWindowState, activate); } - /// public Action? GotInputWhenDisabled { get; set; } - /// public void SetParent(IWindowImpl? parent) { _parent = parent as WindowImpl; @@ -739,10 +703,8 @@ namespace Avalonia.Win32 SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, parentHwnd); } - /// public void SetEnabled(bool enable) => EnableWindow(_hwnd, enable); - /// public void BeginMoveDrag(PointerPressedEventArgs e) { e.Pointer.Capture(null); @@ -750,7 +712,6 @@ namespace Avalonia.Win32 new IntPtr((int)HitTestValues.HTCAPTION), IntPtr.Zero); } - /// public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e) { if (_windowProperties.IsResizable) @@ -765,13 +726,11 @@ namespace Avalonia.Win32 } } - /// public void SetTitle(string? title) { SetWindowText(_hwnd, title); } - /// public void SetCursor(ICursorImpl? cursor) { var impl = cursor as CursorImpl; @@ -779,13 +738,12 @@ namespace Avalonia.Win32 var hCursor = impl?.Handle ?? s_defaultCursor; SetClassLong(_hwnd, ClassLongIndex.GCLP_HCURSOR, hCursor); - if (_owner?.IsPointerOver == true) + if (Owner.IsPointerOver) { UnmanagedMethods.SetCursor(hCursor); } } - /// public void SetIcon(IWindowIconImpl? icon) { var impl = icon as IconImpl; @@ -795,7 +753,6 @@ namespace Avalonia.Win32 new IntPtr((int)Icons.ICON_BIG), hIcon); } - /// public void ShowTaskbarIcon(bool value) { var newWindowProperties = _windowProperties; @@ -805,7 +762,6 @@ namespace Avalonia.Win32 UpdateWindowProperties(newWindowProperties); } - /// public void CanResize(bool value) { var newWindowProperties = _windowProperties; @@ -815,7 +771,6 @@ namespace Avalonia.Win32 UpdateWindowProperties(newWindowProperties); } - /// public void SetSystemDecorations(SystemDecorations value) { var newWindowProperties = _windowProperties; @@ -825,7 +780,6 @@ namespace Avalonia.Win32 UpdateWindowProperties(newWindowProperties); } - /// public void SetTopmost(bool value) { if (value == _topmost) @@ -842,7 +796,6 @@ namespace Avalonia.Win32 _topmost = value; } - /// public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { if (Win32Platform.WindowsVersion.Build >= 22000) @@ -1457,7 +1410,6 @@ namespace Avalonia.Win32 IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => Handle.Handle; - /// public void SetExtendClientAreaToDecorationsHint(bool hint) { _isClientAreaExtended = hint; @@ -1465,7 +1417,6 @@ namespace Avalonia.Win32 ExtendClientArea(); } - /// public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) { _extendChromeHints = hints;