Browse Source

Merge pull request #3158 from AvaloniaUI/per-window-pointer-devices

Removed pointer global state that caused trouble
Steven Kirk 6 years ago
parent
commit
4ce49f2dca

+ 11 - 2
src/Avalonia.Input/MouseDevice.cs

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

+ 18 - 3
src/Avalonia.Input/TouchDevice.cs

@@ -1,3 +1,4 @@
+using System;
 using System.Collections.Generic;
 using System.Linq;
 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
     /// </remarks>
     /// </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)(modifiers & RawInputModifiers.KeyboardMask);
 
@@ -28,6 +30,8 @@ namespace Avalonia.Input
         
         public void ProcessRawEvent(RawInputEventArgs ev)
         {
+            if(_disposed)
+                return;
             var args = (RawTouchEventArgs)ev;
             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();
+        }
         
     }
 }

+ 0 - 1
src/Avalonia.Native/AvaloniaNativePlatform.cs

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

+ 3 - 2
src/Avalonia.Native/WindowImplBase.cs

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

+ 0 - 2
src/Avalonia.X11/X11Platform.cs

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

+ 8 - 2
src/Avalonia.X11/X11Window.cs

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

+ 6 - 6
src/Avalonia.X11/XI2Manager.cs

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

+ 0 - 8
src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs

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

+ 14 - 13
src/Windows/Avalonia.Win32/WindowImpl.cs

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