Browse Source

Removed pointer global state that caused trouble

pull/3158/head
Nikita Tsukanov 7 years ago
parent
commit
3b1005f04e
  1. 13
      src/Avalonia.Input/MouseDevice.cs
  2. 21
      src/Avalonia.Input/TouchDevice.cs
  3. 1
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  4. 5
      src/Avalonia.Native/WindowImplBase.cs
  5. 2
      src/Avalonia.X11/X11Platform.cs
  6. 10
      src/Avalonia.X11/X11Window.cs
  7. 12
      src/Avalonia.X11/XI2Manager.cs
  8. 8
      src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
  9. 27
      src/Windows/Avalonia.Win32/WindowImpl.cs

13
src/Avalonia.Input/MouseDevice.cs

@ -14,13 +14,14 @@ namespace Avalonia.Input
/// <summary> /// <summary>
/// Represents a mouse device. /// Represents a mouse device.
/// </summary> /// </summary>
public class MouseDevice : IMouseDevice public class MouseDevice : IMouseDevice, IDisposable
{ {
private int _clickCount; private int _clickCount;
private Rect _lastClickRect; private Rect _lastClickRect;
private ulong _lastClickTime; private ulong _lastClickTime;
private readonly Pointer _pointer; private readonly Pointer _pointer;
private bool _disposed;
public MouseDevice(Pointer pointer = null) public MouseDevice(Pointer pointer = null)
{ {
@ -126,7 +127,9 @@ namespace Avalonia.Input
{ {
Contract.Requires<ArgumentNullException>(e != null); Contract.Requires<ArgumentNullException>(e != null);
var mouse = (IMouseDevice)e.Device; var mouse = (MouseDevice)e.Device;
if(mouse._disposed)
return;
Position = e.Root.PointToScreen(e.Position); Position = e.Root.PointToScreen(e.Position);
var props = CreateProperties(e); var props = CreateProperties(e);
@ -441,5 +444,11 @@ namespace Avalonia.Input
el = (IInputElement)el.VisualParent; el = (IInputElement)el.VisualParent;
} }
} }
public void Dispose()
{
_disposed = true;
_pointer?.Dispose();
}
} }
} }

21
src/Avalonia.Input/TouchDevice.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
@ -11,10 +12,11 @@ namespace Avalonia.Input
/// This class is supposed to be used on per-toplevel basis, don't use a shared one /// This class is supposed to be used on per-toplevel basis, don't use a shared one
/// </remarks> /// </remarks>
/// </summary> /// </summary>
public class TouchDevice : IInputDevice public class TouchDevice : IInputDevice, IDisposable
{ {
Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>(); private readonly Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>();
private bool _disposed;
KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) => KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) =>
(KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask); (KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask);
@ -28,6 +30,8 @@ namespace Avalonia.Input
public void ProcessRawEvent(RawInputEventArgs ev) public void ProcessRawEvent(RawInputEventArgs ev)
{ {
if(_disposed)
return;
var args = (RawTouchEventArgs)ev; var args = (RawTouchEventArgs)ev;
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer)) if (!_pointers.TryGetValue(args.TouchPointId, out var pointer))
{ {
@ -82,6 +86,17 @@ namespace Avalonia.Input
} }
public void Dispose()
{
if(_disposed)
return;
var values = _pointers.Values.ToList();
_pointers.Clear();
_disposed = true;
foreach (var p in values)
p.Dispose();
}
} }
} }

1
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -95,7 +95,6 @@ namespace Avalonia.Native
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactory(_factory.CreateCursorFactory())) .Bind<IStandardCursorFactory>().ToConstant(new CursorFactory(_factory.CreateCursorFactory()))
.Bind<IPlatformIconLoader>().ToSingleton<IconLoader>() .Bind<IPlatformIconLoader>().ToSingleton<IconLoader>()
.Bind<IKeyboardDevice>().ToConstant(KeyboardDevice) .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
.Bind<IMouseDevice>().ToConstant(MouseDevice)
.Bind<IPlatformSettings>().ToConstant(this) .Bind<IPlatformSettings>().ToConstant(this)
.Bind<IWindowingPlatform>().ToConstant(this) .Bind<IWindowingPlatform>().ToConstant(this)
.Bind<IClipboard>().ToConstant(new ClipboardImpl(_factory.CreateClipboard())) .Bind<IClipboard>().ToConstant(new ClipboardImpl(_factory.CreateClipboard()))

5
src/Avalonia.Native/WindowImplBase.cs

@ -24,7 +24,7 @@ namespace Avalonia.Native
private object _syncRoot = new object(); private object _syncRoot = new object();
private bool _deferredRendering = false; private bool _deferredRendering = false;
private bool _gpu = false; private bool _gpu = false;
private readonly IMouseDevice _mouse; private readonly MouseDevice _mouse;
private readonly IKeyboardDevice _keyboard; private readonly IKeyboardDevice _keyboard;
private readonly IStandardCursorFactory _cursorFactory; private readonly IStandardCursorFactory _cursorFactory;
private Size _savedLogicalSize; private Size _savedLogicalSize;
@ -38,7 +38,7 @@ namespace Avalonia.Native
_deferredRendering = opts.UseDeferredRendering; _deferredRendering = opts.UseDeferredRendering;
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>(); _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
_mouse = AvaloniaLocator.Current.GetService<IMouseDevice>(); _mouse = new MouseDevice();
_cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>(); _cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();
} }
@ -142,6 +142,7 @@ namespace Avalonia.Native
{ {
n?.Dispose(); n?.Dispose();
} }
_parent._mouse.Dispose();
} }
void IAvnWindowBaseEvents.Activated() => _parent.Activated?.Invoke(); void IAvnWindowBaseEvents.Activated() => _parent.Activated?.Invoke();

2
src/Avalonia.X11/X11Platform.cs

@ -19,9 +19,7 @@ namespace Avalonia.X11
class AvaloniaX11Platform : IWindowingPlatform class AvaloniaX11Platform : IWindowingPlatform
{ {
private Lazy<KeyboardDevice> _keyboardDevice = new Lazy<KeyboardDevice>(() => new KeyboardDevice()); private Lazy<KeyboardDevice> _keyboardDevice = new Lazy<KeyboardDevice>(() => new KeyboardDevice());
private Lazy<MouseDevice> _mouseDevice = new Lazy<MouseDevice>(() => new MouseDevice());
public KeyboardDevice KeyboardDevice => _keyboardDevice.Value; public KeyboardDevice KeyboardDevice => _keyboardDevice.Value;
public MouseDevice MouseDevice => _mouseDevice.Value;
public Dictionary<IntPtr, Action<XEvent>> Windows = new Dictionary<IntPtr, Action<XEvent>>(); public Dictionary<IntPtr, Action<XEvent>> Windows = new Dictionary<IntPtr, Action<XEvent>>();
public XI2Manager XI2; public XI2Manager XI2;
public X11Info Info { get; private set; } public X11Info Info { get; private set; }

10
src/Avalonia.X11/X11Window.cs

@ -32,7 +32,8 @@ namespace Avalonia.X11
private PixelPoint? _configurePoint; private PixelPoint? _configurePoint;
private bool _triggeredExpose; private bool _triggeredExpose;
private IInputRoot _inputRoot; private IInputRoot _inputRoot;
private readonly IMouseDevice _mouse; private readonly MouseDevice _mouse;
private readonly TouchDevice _touch;
private readonly IKeyboardDevice _keyboard; private readonly IKeyboardDevice _keyboard;
private PixelPoint? _position; private PixelPoint? _position;
private PixelSize _realSize; private PixelSize _realSize;
@ -57,7 +58,8 @@ namespace Avalonia.X11
_platform = platform; _platform = platform;
_popup = popupParent != null; _popup = popupParent != null;
_x11 = platform.Info; _x11 = platform.Info;
_mouse = platform.MouseDevice; _mouse = new MouseDevice();
_touch = new TouchDevice();
_keyboard = platform.KeyboardDevice; _keyboard = platform.KeyboardDevice;
var glfeature = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>(); var glfeature = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
@ -702,6 +704,8 @@ namespace Avalonia.X11
_platform.XI2?.OnWindowDestroyed(_handle); _platform.XI2?.OnWindowDestroyed(_handle);
_handle = IntPtr.Zero; _handle = IntPtr.Zero;
Closed?.Invoke(); Closed?.Invoke();
_mouse.Dispose();
_touch.Dispose();
} }
if (_useRenderWindow && _renderHandle != IntPtr.Zero) if (_useRenderWindow && _renderHandle != IntPtr.Zero)
@ -830,6 +834,8 @@ namespace Avalonia.X11
} }
public IMouseDevice MouseDevice => _mouse; public IMouseDevice MouseDevice => _mouse;
public TouchDevice TouchDevice => _touch;
public IPopupImpl CreatePopup() public IPopupImpl CreatePopup()
=> _platform.Options.OverlayPopups ? null : new X11Window(_platform, this); => _platform.Options.OverlayPopups ? null : new X11Window(_platform, this);

12
src/Avalonia.X11/XI2Manager.cs

@ -92,8 +92,6 @@ namespace Avalonia.X11
private PointerDeviceInfo _pointerDevice; private PointerDeviceInfo _pointerDevice;
private AvaloniaX11Platform _platform; private AvaloniaX11Platform _platform;
private readonly TouchDevice _touchDevice = new TouchDevice();
public bool Init(AvaloniaX11Platform platform) public bool Init(AvaloniaX11Platform platform)
{ {
@ -198,7 +196,7 @@ namespace Avalonia.X11
(ev.Type == XiEventType.XI_TouchUpdate ? (ev.Type == XiEventType.XI_TouchUpdate ?
RawPointerEventType.TouchUpdate : RawPointerEventType.TouchUpdate :
RawPointerEventType.TouchEnd); RawPointerEventType.TouchEnd);
client.ScheduleInput(new RawTouchEventArgs(_touchDevice, client.ScheduleInput(new RawTouchEventArgs(client.TouchDevice,
ev.Timestamp, client.InputRoot, type, ev.Position, ev.Modifiers, ev.Detail)); ev.Timestamp, client.InputRoot, type, ev.Position, ev.Modifiers, ev.Detail));
return; return;
} }
@ -232,10 +230,10 @@ namespace Avalonia.X11
} }
if (scrollDelta != default) if (scrollDelta != default)
client.ScheduleInput(new RawMouseWheelEventArgs(_platform.MouseDevice, ev.Timestamp, client.ScheduleInput(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
client.InputRoot, ev.Position, scrollDelta, ev.Modifiers)); client.InputRoot, ev.Position, scrollDelta, ev.Modifiers));
if (_pointerDevice.HasMotion(ev)) if (_pointerDevice.HasMotion(ev))
client.ScheduleInput(new RawPointerEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot, client.ScheduleInput(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
RawPointerEventType.Move, ev.Position, ev.Modifiers)); RawPointerEventType.Move, ev.Position, ev.Modifiers));
} }
@ -248,7 +246,7 @@ namespace Avalonia.X11
: ev.Button == 3 ? (down ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp) : ev.Button == 3 ? (down ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp)
: (RawPointerEventType?)null; : (RawPointerEventType?)null;
if (type.HasValue) if (type.HasValue)
client.ScheduleInput(new RawPointerEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot, client.ScheduleInput(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
type.Value, ev.Position, ev.Modifiers)); type.Value, ev.Position, ev.Modifiers));
} }
@ -310,5 +308,7 @@ namespace Avalonia.X11
{ {
IInputRoot InputRoot { get; } IInputRoot InputRoot { get; }
void ScheduleInput(RawInputEventArgs args); void ScheduleInput(RawInputEventArgs args);
IMouseDevice MouseDevice { get; }
TouchDevice TouchDevice { get; }
} }
} }

8
src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs

@ -11,19 +11,11 @@ namespace Avalonia.Win32.Input
{ {
class WindowsMouseDevice : MouseDevice class WindowsMouseDevice : MouseDevice
{ {
public static WindowsMouseDevice Instance { get; } = new WindowsMouseDevice();
public WindowsMouseDevice() : base(new WindowsMousePointer()) public WindowsMouseDevice() : base(new WindowsMousePointer())
{ {
} }
public WindowImpl CurrentWindow
{
get;
set;
}
class WindowsMousePointer : Pointer class WindowsMousePointer : Pointer
{ {
public WindowsMousePointer() : base(Pointer.GetNextFreeId(),PointerType.Mouse, true) public WindowsMousePointer() : base(Pointer.GetNextFreeId(),PointerType.Mouse, true)

27
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -30,6 +30,7 @@ namespace Avalonia.Win32
private IntPtr _hwnd; private IntPtr _hwnd;
private bool _multitouch; private bool _multitouch;
private TouchDevice _touchDevice = new TouchDevice(); private TouchDevice _touchDevice = new TouchDevice();
private MouseDevice _mouseDevice = new WindowsMouseDevice();
private IInputRoot _owner; private IInputRoot _owner;
private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock(); private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock();
private bool _trackingMouse; private bool _trackingMouse;
@ -205,7 +206,7 @@ namespace Avalonia.Win32
} }
} }
public IMouseDevice MouseDevice => WindowsMouseDevice.Instance; public IMouseDevice MouseDevice => _mouseDevice;
public WindowState WindowState public WindowState WindowState
{ {
@ -333,7 +334,7 @@ namespace Avalonia.Win32
public void BeginMoveDrag(PointerPressedEventArgs e) public void BeginMoveDrag(PointerPressedEventArgs e)
{ {
WindowsMouseDevice.Instance.Capture(null); _mouseDevice.Capture(null);
UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN, UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero); new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero);
e.Pointer.Capture(null); e.Pointer.Capture(null);
@ -356,7 +357,7 @@ namespace Avalonia.Win32
#if USE_MANAGED_DRAG #if USE_MANAGED_DRAG
_managedDrag.BeginResizeDrag(edge, ScreenToClient(MouseDevice.Position)); _managedDrag.BeginResizeDrag(edge, ScreenToClient(MouseDevice.Position));
#else #else
WindowsMouseDevice.Instance.Capture(null); _mouseDevice.Capture(null);
UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN, UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)EdgeDic[edge]), IntPtr.Zero); new IntPtr((int)EdgeDic[edge]), IntPtr.Zero);
#endif #endif
@ -437,9 +438,7 @@ namespace Avalonia.Win32
uint timestamp = unchecked((uint)UnmanagedMethods.GetMessageTime()); uint timestamp = unchecked((uint)UnmanagedMethods.GetMessageTime());
RawInputEventArgs e = null; RawInputEventArgs e = null;
WindowsMouseDevice.Instance.CurrentWindow = this;
switch ((UnmanagedMethods.WindowsMessage)msg) switch ((UnmanagedMethods.WindowsMessage)msg)
{ {
case UnmanagedMethods.WindowsMessage.WM_ACTIVATE: case UnmanagedMethods.WindowsMessage.WM_ACTIVATE:
@ -485,6 +484,8 @@ namespace Avalonia.Win32
_parent._disabledBy.Remove(this); _parent._disabledBy.Remove(this);
_parent.UpdateEnabled(); _parent.UpdateEnabled();
} }
_mouseDevice.Dispose();
_touchDevice?.Dispose();
//Free other resources //Free other resources
Dispose(); Dispose();
return IntPtr.Zero; return IntPtr.Zero;
@ -542,7 +543,7 @@ namespace Avalonia.Win32
if(ShouldIgnoreTouchEmulatedMessage()) if(ShouldIgnoreTouchEmulatedMessage())
break; break;
e = new RawPointerEventArgs( e = new RawPointerEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN
@ -559,7 +560,7 @@ namespace Avalonia.Win32
if(ShouldIgnoreTouchEmulatedMessage()) if(ShouldIgnoreTouchEmulatedMessage())
break; break;
e = new RawPointerEventArgs( e = new RawPointerEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONUP msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONUP
@ -587,7 +588,7 @@ namespace Avalonia.Win32
} }
e = new RawPointerEventArgs( e = new RawPointerEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
RawPointerEventType.Move, RawPointerEventType.Move,
@ -597,7 +598,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSEWHEEL: case UnmanagedMethods.WindowsMessage.WM_MOUSEWHEEL:
e = new RawMouseWheelEventArgs( e = new RawMouseWheelEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
PointToClient(PointFromLParam(lParam)), PointToClient(PointFromLParam(lParam)),
@ -606,7 +607,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSEHWHEEL: case UnmanagedMethods.WindowsMessage.WM_MOUSEHWHEEL:
e = new RawMouseWheelEventArgs( e = new RawMouseWheelEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
PointToClient(PointFromLParam(lParam)), PointToClient(PointFromLParam(lParam)),
@ -616,7 +617,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE: case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE:
_trackingMouse = false; _trackingMouse = false;
e = new RawPointerEventArgs( e = new RawPointerEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
RawPointerEventType.LeaveWindow, RawPointerEventType.LeaveWindow,
@ -627,7 +628,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN:
case UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN: case UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN:
e = new RawPointerEventArgs( e = new RawPointerEventArgs(
WindowsMouseDevice.Instance, _mouseDevice,
timestamp, timestamp,
_owner, _owner,
msg == (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN msg == (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN

Loading…
Cancel
Save