Skip to content

Commit 99db0e1

Browse files
miloushMrJul
andauthored
Primary mouse device (#19898)
* Primary mouse device * Addressing feedback --------- Co-authored-by: Jan Kučera <[email protected]> Co-authored-by: Julien Lebosquain <[email protected]>
1 parent 4d3a281 commit 99db0e1

File tree

5 files changed

+41
-18
lines changed

5 files changed

+41
-18
lines changed

src/Avalonia.Base/Input/MouseDevice.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ namespace Avalonia.Input
1818
[PrivateApi]
1919
public class MouseDevice : IMouseDevice, IDisposable
2020
{
21+
private static MouseDevice? _primary;
22+
internal static MouseDevice Primary => _primary ??= new MouseDevice();
23+
2124
private int _clickCount;
2225
private Rect _lastClickRect;
2326
private ulong _lastClickTime;
@@ -31,6 +34,16 @@ public MouseDevice(Pointer? pointer = null)
3134
_pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
3235
}
3336

37+
internal static TMouseDevice GetOrCreatePrimary<TMouseDevice>() where TMouseDevice : MouseDevice, new()
38+
{
39+
if (_primary is TMouseDevice device)
40+
return device;
41+
42+
device = new TMouseDevice();
43+
_primary = device;
44+
return device;
45+
}
46+
3447
public void ProcessRawEvent(RawInputEventArgs e)
3548
{
3649
if (!e.Handled && e is RawPointerEventArgs margs)
@@ -300,6 +313,8 @@ private bool GestureSwipe(IMouseDevice device, ulong timestamp, IInputRoot root,
300313

301314
public void Dispose()
302315
{
316+
System.Diagnostics.Debug.Assert(this != _primary, "Disposing primary mouse device.");
317+
303318
_disposed = true;
304319
_pointer?.Dispose();
305320
}

src/Avalonia.Native/TopLevelImpl.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public TopLevelImpl(IAvaloniaNativeFactory factory)
8989
Factory = factory;
9090

9191
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
92-
_mouse = new MouseDevice();
92+
_mouse = Avalonia.Input.MouseDevice.Primary;
9393
_pen = new PenDevice();
9494
_cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>();
9595
}
@@ -387,8 +387,6 @@ public virtual void Dispose()
387387

388388
_nativeControlHost?.Dispose();
389389
_nativeControlHost = null;
390-
391-
_mouse?.Dispose();
392390
}
393391

394392
protected virtual bool ChromeHitTest(RawPointerEventArgs e)

src/Avalonia.X11/X11Window.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, X11Wind
9696
_popup = popupParent != null;
9797
_overrideRedirect = _popup || overrideRedirect;
9898
_x11 = platform.Info;
99-
_mouse = new MouseDevice();
99+
_mouse = Avalonia.Input.MouseDevice.Primary;
100100
_touch = new TouchDevice();
101101
_keyboard = platform.KeyboardDevice;
102102

@@ -1072,7 +1072,6 @@ private void Cleanup(bool fromDestroyNotification)
10721072
_platform.XI2?.OnWindowDestroyed(_handle);
10731073
var handle = _handle;
10741074
_handle = IntPtr.Zero;
1075-
_mouse.Dispose();
10761075
_touch.Dispose();
10771076
if (!fromDestroyNotification)
10781077
XDestroyWindow(_x11.Display, handle);

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

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam,
114114
//Window doesn't exist anymore
115115
_hwnd = IntPtr.Zero;
116116
//Remove root reference to this class, so unmanaged delegate can be collected
117-
s_instances.Remove(this);
117+
lock (s_instances)
118+
s_instances.Remove(this);
118119

119-
_mouseDevice.Dispose();
120120
_touchDevice.Dispose();
121121
//Free other resources
122122
Dispose();
@@ -280,14 +280,6 @@ protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam,
280280
DipFromLParam(lParam), GetMouseModifiers(wParam));
281281
break;
282282
}
283-
// Mouse capture is lost
284-
case WindowsMessage.WM_CANCELMODE:
285-
if (!IsMouseInPointerEnabled)
286-
{
287-
_mouseDevice.Capture(null);
288-
}
289-
290-
break;
291283

292284
case WindowsMessage.WM_MOUSEMOVE:
293285
{
@@ -394,13 +386,14 @@ protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam,
394386
break;
395387
}
396388

389+
// covers WM_CANCELMODE which sends WM_CAPTURECHANGED in DefWindowProc
397390
case WindowsMessage.WM_CAPTURECHANGED:
398391
{
399392
if (IsMouseInPointerEnabled)
400393
{
401394
break;
402395
}
403-
if (_hwnd != lParam)
396+
if (!IsOurWindow(lParam))
404397
{
405398
_trackingMouse = false;
406399
e = new RawPointerEventArgs(
@@ -907,6 +900,22 @@ protected virtual unsafe IntPtr AppWndProc(IntPtr hWnd, uint msg, IntPtr wParam,
907900
return DefWindowProc(hWnd, msg, wParam, lParam);
908901
}
909902

903+
private bool IsOurWindow(IntPtr hwnd)
904+
{
905+
if (hwnd == IntPtr.Zero)
906+
return false;
907+
908+
if (hwnd == _hwnd)
909+
return true;
910+
911+
lock (s_instances)
912+
for (int i = 0; i < s_instances.Count; i++)
913+
if (s_instances[i]._hwnd == hwnd)
914+
return true;
915+
916+
return false;
917+
}
918+
910919
private void OnShowHideMessage(bool shown)
911920
{
912921
_shown = shown;

src/Windows/Avalonia.Win32/WindowImpl.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ internal partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindow
119119
public WindowImpl()
120120
{
121121
_touchDevice = new TouchDevice();
122-
_mouseDevice = new WindowsMouseDevice();
122+
_mouseDevice = Avalonia.Input.MouseDevice.GetOrCreatePrimary<WindowsMouseDevice>();
123123
_penDevice = new PenDevice();
124124

125125
#if USE_MANAGED_DRAG
@@ -177,7 +177,9 @@ public WindowImpl()
177177
_nativeControlHost = new Win32NativeControlHost(this, !UseRedirectionBitmap);
178178
_defaultTransparencyLevel = UseRedirectionBitmap ? WindowTransparencyLevel.None : WindowTransparencyLevel.Transparent;
179179
_transparencyLevel = _defaultTransparencyLevel;
180-
s_instances.Add(this);
180+
181+
lock (s_instances)
182+
s_instances.Add(this);
181183
}
182184

183185
internal IInputRoot Owner

0 commit comments

Comments
 (0)