diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs index ed14ab7878..6dda7b81ca 100644 --- a/src/Avalonia.X11/Stubs.cs +++ b/src/Avalonia.X11/Stubs.cs @@ -9,14 +9,6 @@ using Avalonia.Platform; namespace Avalonia.X11 { - class CursorFactoryStub : IStandardCursorFactory - { - public IPlatformHandle GetCursor(StandardCursorType cursorType) - { - return new PlatformHandle(IntPtr.Zero, "FAKE"); - } - } - class ClipboardStub : IClipboard { private string _text; diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs index e7b83f59d3..50a735b2ef 100644 --- a/src/Avalonia.X11/X11Atoms.cs +++ b/src/Avalonia.X11/X11Atoms.cs @@ -176,9 +176,6 @@ namespace Avalonia.X11 { public readonly IntPtr OEMTEXT; public readonly IntPtr UNICODETEXT; public readonly IntPtr TARGETS; - public readonly IntPtr PostAtom; - public readonly IntPtr HoverState; - public readonly IntPtr AsyncAtom; public X11Atoms (IntPtr display) { @@ -249,10 +246,7 @@ namespace Avalonia.X11 { "PRIMARY", "COMPOUND_TEXT", "UTF8_STRING", - "TARGETS", - "_SWF_AsyncAtom", - "_SWF_PostMessageAtom", - "_SWF_HoverAtom" }; + "TARGETS"}; IntPtr[] atoms = new IntPtr [atom_names.Length];; @@ -324,9 +318,6 @@ namespace Avalonia.X11 { OEMTEXT = atoms [off++]; UNICODETEXT = atoms [off++]; TARGETS = atoms [off++]; - AsyncAtom = atoms [off++]; - PostAtom = atoms [off++]; - HoverState = atoms [off++]; DIB = XA_PIXMAP; diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs new file mode 100644 index 0000000000..d25a0da0a2 --- /dev/null +++ b/src/Avalonia.X11/X11CursorFactory.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Input; +using Avalonia.Platform; + +namespace Avalonia.X11 +{ + class X11CursorFactory : IStandardCursorFactory + { + private readonly IntPtr _display; + private Dictionary _cursors; + + private static readonly Dictionary s_mapping = + new Dictionary + { + {StandardCursorType.Arrow, CursorFontShape.XC_arrow}, + {StandardCursorType.Cross, CursorFontShape.XC_cross}, + {StandardCursorType.Hand, CursorFontShape.XC_hand1}, + {StandardCursorType.Help, CursorFontShape.XC_question_arrow}, + {StandardCursorType.Ibeam, CursorFontShape.XC_xterm}, + {StandardCursorType.No, CursorFontShape.XC_X_cursor}, + {StandardCursorType.Wait, CursorFontShape.XC_watch}, + {StandardCursorType.AppStarting, CursorFontShape.XC_watch}, + {StandardCursorType.BottomSize, CursorFontShape.XC_bottom_side}, + {StandardCursorType.DragCopy, CursorFontShape.XC_center_ptr}, + {StandardCursorType.DragLink, CursorFontShape.XC_fleur}, + {StandardCursorType.DragMove, CursorFontShape.XC_diamond_cross}, + {StandardCursorType.LeftSide, CursorFontShape.XC_left_side}, + {StandardCursorType.RightSide, CursorFontShape.XC_right_side}, + {StandardCursorType.SizeAll, CursorFontShape.XC_sizing}, + {StandardCursorType.TopSide, CursorFontShape.XC_top_side}, + {StandardCursorType.UpArrow, CursorFontShape.XC_sb_up_arrow}, + {StandardCursorType.BottomLeftCorner, CursorFontShape.XC_bottom_left_corner}, + {StandardCursorType.BottomRightCorner, CursorFontShape.XC_bottom_right_corner}, + {StandardCursorType.SizeNorthSouth, CursorFontShape.XC_sb_v_double_arrow}, + {StandardCursorType.SizeWestEast, CursorFontShape.XC_sb_h_double_arrow}, + {StandardCursorType.TopLeftCorner, CursorFontShape.XC_top_left_corner}, + {StandardCursorType.TopRightCorner, CursorFontShape.XC_top_right_corner}, + }; + + public X11CursorFactory(IntPtr display) + { + _display = display; + _cursors = Enum.GetValues(typeof(CursorFontShape)).Cast() + .ToDictionary(id => id, id => XLib.XCreateFontCursor(_display, id)); + } + + public IPlatformHandle GetCursor(StandardCursorType cursorType) + { + var handle = s_mapping.TryGetValue(cursorType, out var shape) + ? _cursors[shape] + : _cursors[CursorFontShape.XC_arrow]; + return new PlatformHandle(handle, "XCURSOR"); + } + } +} diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index ddad739dd0..527cdc31ef 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -14,6 +14,7 @@ namespace Avalonia.X11 public IntPtr BlackPixel { get; } public IntPtr RootWindow { get; } public IntPtr DefaultRootWindow { get; } + public IntPtr DefaultCursor { get; } public X11Atoms Atoms { get; } public IntPtr LastActivityTimestamp { get; set; } @@ -25,6 +26,7 @@ namespace Avalonia.X11 DefaultScreen = XDefaultScreen(display); BlackPixel = XBlackPixel(display, DefaultScreen); RootWindow = XRootWindow(display, DefaultScreen); + DefaultCursor = XCreateFontCursor(display, CursorFontShape.XC_arrow); DefaultRootWindow = XDefaultRootWindow(display); Atoms = new X11Atoms(display); } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 33497be411..b3ffc2a30b 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -36,7 +36,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Control)) .Bind().ToFunc(() => KeyboardDevice) - .Bind().ToConstant(new CursorFactoryStub()) + .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToSingleton() .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new SystemDialogsStub()) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 036c7d0f34..82564e98e0 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -482,6 +482,14 @@ namespace Avalonia.X11 public void SetCursor(IPlatformHandle cursor) { + if (cursor == null) + XDefineCursor(_x11.Display, _handle, _x11.DefaultCursor); + else + { + if (cursor.HandleDescriptor != "XCURSOR") + throw new ArgumentException("Expected XCURSOR handle type"); + XDefineCursor(_x11.Display, _handle, cursor.Handle); + } } public IPlatformHandle Handle { get; }