diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs index fdd8a31806..2af06960bc 100644 --- a/src/Avalonia.X11/X11CursorFactory.cs +++ b/src/Avalonia.X11/X11CursorFactory.cs @@ -15,7 +15,7 @@ namespace Avalonia.X11 private static IntPtr _nullCursor; private readonly IntPtr _display; - private Dictionary _cursors; + private Dictionary _cursors; private static readonly Dictionary s_mapping = new Dictionary @@ -45,29 +45,29 @@ namespace Avalonia.X11 {StandardCursorType.TopRightCorner, CursorFontShape.XC_top_right_corner}, }; + private static readonly Dictionary s_libraryCursors = new() + { + {StandardCursorType.DragCopy, "dnd-copy"}, + {StandardCursorType.DragLink, "dnd-link"}, + {StandardCursorType.DragMove, "dnd-move"}, + // TODO: Check if other platforms have dnd-none, dnd-no-drop and dnd-ask + }; + public X11CursorFactory(IntPtr display) { _display = display; _nullCursor = GetNullCursor(display); - // 78 = number of items in CursorFontShape enum - // Unlikely to change, but, do we have a Src Gen for this? - _cursors = new Dictionary(78); + _cursors = new Dictionary(); } public ICursorImpl GetCursor(StandardCursorType cursorType) { IntPtr handle; if (cursorType == StandardCursorType.None) - { handle = _nullCursor; - } else - { - handle = s_mapping.TryGetValue(cursorType, out var shape) - ? GetCursorHandleLazy(shape) - : GetCursorHandleLazy(CursorFontShape.XC_left_ptr); - } + handle = GetCursorHandleCached(cursorType); return new CursorImpl(handle); } @@ -139,10 +139,25 @@ namespace Avalonia.X11 public IFramebufferRenderTarget CreateFramebufferRenderTarget() => new FuncFramebufferRenderTarget(Lock); } - private nint GetCursorHandleLazy(CursorFontShape shape) + private nint GetCursorHandleCached(StandardCursorType type) { - if (!_cursors.TryGetValue(shape, out var handle)) - _cursors[shape] = handle = XLib.XCreateFontCursor(_display, shape); + if (!_cursors.TryGetValue(type, out var handle)) + { + if(s_libraryCursors.TryGetValue(type, out var cursorName)) + handle = XLib.XcursorLibraryLoadCursor(_display, cursorName); + else if(s_mapping.TryGetValue(type, out var cursorShape)) + handle = XLib.XCreateFontCursor(_display, cursorShape); + + if (handle == IntPtr.Zero) + { + if (type != StandardCursorType.Arrow) + handle = GetCursorHandleCached(StandardCursorType.Arrow); + else + handle = _nullCursor; + } + + _cursors[type] = handle; + } return handle; } diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index a11bfce211..3daf9fff1e 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -329,6 +329,9 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern IntPtr XCreateFontCursor(IntPtr display, CursorFontShape shape); + [DllImport(libXCursor)] + public static extern IntPtr XcursorLibraryLoadCursor(IntPtr display, string name); + [DllImport(libX11)] public static extern IntPtr XCreatePixmapCursor(IntPtr display, IntPtr source, IntPtr mask, ref XColor foreground_color, ref XColor background_color, int x_hot, int y_hot);