Added ICursorImpl.
This commit is contained in:
@@ -61,7 +61,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
|
||||
|
||||
public virtual PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, 1);
|
||||
|
||||
public virtual void SetCursor(IPlatformHandle cursor)
|
||||
public virtual void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Avalonia.Platform
|
||||
/// Sets the cursor associated with the toplevel.
|
||||
/// </summary>
|
||||
/// <param name="cursor">The cursor. Use null for default cursor</param>
|
||||
void SetCursor(IPlatformHandle cursor);
|
||||
void SetCursor(ICursorImpl cursor);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a method called when the underlying implementation is destroyed.
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace Avalonia.Controls
|
||||
this.GetObservable(PointerOverElementProperty)
|
||||
.Select(
|
||||
x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
|
||||
.Switch().Subscribe(cursor => PlatformImpl?.SetCursor(cursor?.PlatformCursor));
|
||||
.Switch().Subscribe(cursor => PlatformImpl?.SetCursor(cursor?.PlatformImpl));
|
||||
|
||||
if (((IStyleHost)this).StylingParent is IResourceHost applicationResources)
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Avalonia.DesignerSupport.Remote
|
||||
|
||||
public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
|
||||
|
||||
public void SetCursor(IPlatformHandle cursor)
|
||||
public void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -194,8 +194,13 @@ namespace Avalonia.DesignerSupport.Remote
|
||||
|
||||
class CursorFactoryStub : ICursorFactory
|
||||
{
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType) => new PlatformHandle(IntPtr.Zero, "STUB");
|
||||
public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot) => new PlatformHandle(IntPtr.Zero, "STUB");
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType) => new CursorStub();
|
||||
public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot) => new CursorStub();
|
||||
|
||||
private class CursorStub : ICursorImpl
|
||||
{
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
class IconLoaderStub : IPlatformIconLoader
|
||||
|
||||
@@ -54,14 +54,12 @@ namespace Avalonia.Headless
|
||||
|
||||
class HeadlessCursorFactoryStub : ICursorFactory
|
||||
{
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType)
|
||||
{
|
||||
return new PlatformHandle(new IntPtr((int)cursorType), "STUB");
|
||||
}
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType) => new CursorStub();
|
||||
public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot) => new CursorStub();
|
||||
|
||||
public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
private class CursorStub : ICursorImpl
|
||||
{
|
||||
return new PlatformHandle(IntPtr.Zero, "STUB");
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Avalonia.Headless
|
||||
|
||||
public PixelPoint PointToScreen(Point point) => PixelPoint.FromPoint(point, RenderScaling);
|
||||
|
||||
public void SetCursor(IPlatformHandle cursor)
|
||||
public void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ namespace Avalonia.Input
|
||||
{
|
||||
public static readonly Cursor Default = new Cursor(StandardCursorType.Arrow);
|
||||
|
||||
internal Cursor(IPlatformHandle platformCursor)
|
||||
internal Cursor(ICursorImpl platformImpl)
|
||||
{
|
||||
PlatformCursor = platformCursor;
|
||||
PlatformImpl = platformImpl;
|
||||
}
|
||||
|
||||
public Cursor(StandardCursorType cursorType)
|
||||
@@ -68,7 +68,7 @@ namespace Avalonia.Input
|
||||
{
|
||||
}
|
||||
|
||||
public IPlatformHandle PlatformCursor { get; }
|
||||
public ICursorImpl PlatformImpl { get; }
|
||||
|
||||
public static Cursor Parse(string s)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Avalonia.Platform
|
||||
{
|
||||
public interface ICursorFactory
|
||||
{
|
||||
IPlatformHandle GetCursor(StandardCursorType cursorType);
|
||||
IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot);
|
||||
ICursorImpl GetCursor(StandardCursorType cursorType);
|
||||
ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using Avalonia.Input;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Avalonia.Platform
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a platform implementation of a <see cref="Cursor"/>.
|
||||
/// </summary>
|
||||
public interface ICursorImpl : IDisposable
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Avalonia.Native.Interop;
|
||||
|
||||
namespace Avalonia.Native
|
||||
{
|
||||
class AvaloniaNativeCursor : IPlatformHandle, IDisposable
|
||||
class AvaloniaNativeCursor : ICursorImpl, IDisposable
|
||||
{
|
||||
public IAvnCursor Cursor { get; private set; }
|
||||
public IntPtr Handle => IntPtr.Zero;
|
||||
@@ -33,13 +33,13 @@ namespace Avalonia.Native
|
||||
_native = native;
|
||||
}
|
||||
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType)
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType)
|
||||
{
|
||||
var cursor = _native.GetCursor((AvnStandardCursorType)cursorType);
|
||||
return new AvaloniaNativeCursor( cursor );
|
||||
}
|
||||
|
||||
public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ namespace Avalonia.Native
|
||||
public Action Deactivated { get; set; }
|
||||
public Action Activated { get; set; }
|
||||
|
||||
public void SetCursor(IPlatformHandle cursor)
|
||||
public void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
if (_native == null)
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Avalonia.X11
|
||||
.ToDictionary(id => id, id => XLib.XCreateFontCursor(_display, id));
|
||||
}
|
||||
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType)
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType)
|
||||
{
|
||||
IntPtr handle;
|
||||
if (cursorType == StandardCursorType.None)
|
||||
@@ -69,10 +69,10 @@ namespace Avalonia.X11
|
||||
? _cursors[shape]
|
||||
: _cursors[CursorFontShape.XC_top_left_arrow];
|
||||
}
|
||||
return new PlatformHandle(handle, "XCURSOR");
|
||||
return new CursorImpl(handle);
|
||||
}
|
||||
|
||||
public unsafe IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
public unsafe ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
{
|
||||
return new XImageCursor(_display, cursor, hotSpot);
|
||||
}
|
||||
@@ -85,7 +85,7 @@ namespace Avalonia.X11
|
||||
return XLib.XCreatePixmapCursor(display, pixmap, pixmap, ref color, ref color, 0, 0);
|
||||
}
|
||||
|
||||
private unsafe class XImageCursor : IFramebufferPlatformSurface, IPlatformHandle, IDisposable
|
||||
private unsafe class XImageCursor : CursorImpl, IFramebufferPlatformSurface, IPlatformHandle
|
||||
{
|
||||
private readonly PixelSize _pixelSize;
|
||||
private readonly IUnmanagedBlob _blob;
|
||||
@@ -117,10 +117,9 @@ namespace Avalonia.X11
|
||||
Handle = XLib.XcursorImageLoadCursor(display, _blob.Address);
|
||||
}
|
||||
|
||||
public IntPtr Handle { get; }
|
||||
public string HandleDescriptor => "XCURSOR";
|
||||
|
||||
public void Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
XLib.XcursorImageDestroy(Handle);
|
||||
_blob.Dispose();
|
||||
@@ -135,4 +134,12 @@ namespace Avalonia.X11
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CursorImpl : ICursorImpl
|
||||
{
|
||||
public CursorImpl() { }
|
||||
public CursorImpl(IntPtr handle) => Handle = handle;
|
||||
public IntPtr Handle { get; protected set; }
|
||||
public virtual void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,15 +878,13 @@ namespace Avalonia.X11
|
||||
UpdateSizeHints(null);
|
||||
}
|
||||
|
||||
public void SetCursor(IPlatformHandle cursor)
|
||||
public void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
if (cursor == null)
|
||||
XDefineCursor(_x11.Display, _handle, _x11.DefaultCursor);
|
||||
else
|
||||
else if (cursor is CursorImpl impl)
|
||||
{
|
||||
if (cursor.HandleDescriptor != "XCURSOR")
|
||||
throw new ArgumentException("Expected XCURSOR handle type");
|
||||
XDefineCursor(_x11.Display, _handle, cursor.Handle);
|
||||
XDefineCursor(_x11.Display, _handle, impl.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Avalonia.LinuxFramebuffer
|
||||
|
||||
public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
|
||||
|
||||
public void SetCursor(IPlatformHandle cursor)
|
||||
public void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,12 @@ namespace Avalonia.LinuxFramebuffer
|
||||
{
|
||||
internal class CursorFactoryStub : ICursorFactory
|
||||
{
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType)
|
||||
{
|
||||
return new PlatformHandle(IntPtr.Zero, null);
|
||||
}
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType) => new CursorStub();
|
||||
public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot) => new CursorStub();
|
||||
|
||||
public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
private class CursorStub : ICursorImpl
|
||||
{
|
||||
return new PlatformHandle(IntPtr.Zero, null);
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
internal class PlatformSettings : IPlatformSettings
|
||||
|
||||
@@ -225,12 +225,12 @@ namespace Avalonia.Win32.Interop.Wpf
|
||||
protected override void OnTextInput(TextCompositionEventArgs e)
|
||||
=> _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, e.Text));
|
||||
|
||||
void ITopLevelImpl.SetCursor(IPlatformHandle cursor)
|
||||
void ITopLevelImpl.SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
if (cursor == null)
|
||||
Cursor = Cursors.Arrow;
|
||||
else if (cursor.HandleDescriptor == "HCURSOR")
|
||||
Cursor = CursorShim.FromHCursor(cursor.Handle);
|
||||
else if (cursor is IPlatformHandle handle)
|
||||
Cursor = CursorShim.FromHCursor(handle.Handle);
|
||||
}
|
||||
|
||||
Action<RawInputEventArgs> ITopLevelImpl.Input { get; set; } //TODO
|
||||
|
||||
@@ -3,9 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Win32.Interop;
|
||||
using SdBitmap = System.Drawing.Bitmap;
|
||||
@@ -36,8 +34,7 @@ namespace Avalonia.Win32
|
||||
IntPtr cursor = UnmanagedMethods.LoadCursor(mh, new IntPtr(id));
|
||||
if (cursor != IntPtr.Zero)
|
||||
{
|
||||
PlatformHandle phCursor = new PlatformHandle(cursor, PlatformConstants.CursorHandleType);
|
||||
Cache.Add(cursorType, phCursor);
|
||||
Cache.Add(cursorType, new CursorImpl(cursor, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,25 +74,23 @@ namespace Avalonia.Win32
|
||||
{StandardCursorType.DragLink, 32516},
|
||||
};
|
||||
|
||||
private static readonly Dictionary<StandardCursorType, IPlatformHandle> Cache =
|
||||
new Dictionary<StandardCursorType, IPlatformHandle>();
|
||||
private static readonly Dictionary<StandardCursorType, CursorImpl> Cache =
|
||||
new Dictionary<StandardCursorType, CursorImpl>();
|
||||
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType)
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType)
|
||||
{
|
||||
IPlatformHandle rv;
|
||||
if (!Cache.TryGetValue(cursorType, out rv))
|
||||
if (!Cache.TryGetValue(cursorType, out var rv))
|
||||
{
|
||||
Cache[cursorType] =
|
||||
rv =
|
||||
new PlatformHandle(
|
||||
UnmanagedMethods.LoadCursor(IntPtr.Zero, new IntPtr(CursorTypeMapping[cursorType])),
|
||||
PlatformConstants.CursorHandleType);
|
||||
rv = new CursorImpl(
|
||||
UnmanagedMethods.LoadCursor(IntPtr.Zero, new IntPtr(CursorTypeMapping[cursorType])),
|
||||
false);
|
||||
Cache.Add(cursorType, rv);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
{
|
||||
using var source = LoadSystemDrawingBitmap(cursor);
|
||||
using var mask = AlphaToMask(source);
|
||||
@@ -109,9 +104,7 @@ namespace Avalonia.Win32
|
||||
ColorBitmap = source.GetHbitmap(),
|
||||
};
|
||||
|
||||
return new PlatformHandle(
|
||||
UnmanagedMethods.CreateIconIndirect(ref info),
|
||||
PlatformConstants.CursorHandleType);
|
||||
return new CursorImpl(UnmanagedMethods.CreateIconIndirect(ref info), true);
|
||||
}
|
||||
|
||||
private SdBitmap LoadSystemDrawingBitmap(IBitmapImpl bitmap)
|
||||
@@ -168,4 +161,27 @@ namespace Avalonia.Win32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class CursorImpl : ICursorImpl, IPlatformHandle
|
||||
{
|
||||
private readonly bool _isCustom;
|
||||
|
||||
public CursorImpl(IntPtr handle, bool isCustom)
|
||||
{
|
||||
Handle = handle;
|
||||
_isCustom = isCustom;
|
||||
}
|
||||
|
||||
public IntPtr Handle { get; private set; }
|
||||
public string HandleDescriptor => PlatformConstants.CursorHandleType;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isCustom && Handle != IntPtr.Zero)
|
||||
{
|
||||
UnmanagedMethods.DestroyIcon(Handle);
|
||||
Handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1034,6 +1034,9 @@ namespace Avalonia.Win32.Interop
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr CreateIconIndirect([In] ref ICONINFO iconInfo);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool DestroyIcon(IntPtr hIcon);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
|
||||
|
||||
|
||||
@@ -557,14 +557,19 @@ namespace Avalonia.Win32
|
||||
SetWindowText(_hwnd, title);
|
||||
}
|
||||
|
||||
public void SetCursor(IPlatformHandle cursor)
|
||||
public void SetCursor(ICursorImpl cursor)
|
||||
{
|
||||
var hCursor = cursor?.Handle ?? DefaultCursor;
|
||||
SetClassLong(_hwnd, ClassLongIndex.GCLP_HCURSOR, hCursor);
|
||||
var impl = cursor as CursorImpl;
|
||||
|
||||
if (_owner.IsPointerOver)
|
||||
if (cursor is null || impl is object)
|
||||
{
|
||||
UnmanagedMethods.SetCursor(hCursor);
|
||||
var hCursor = impl?.Handle ?? DefaultCursor;
|
||||
SetClassLong(_hwnd, ClassLongIndex.GCLP_HCURSOR, hCursor);
|
||||
|
||||
if (_owner.IsPointerOver)
|
||||
{
|
||||
UnmanagedMethods.SetCursor(hCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Platform;
|
||||
|
||||
@@ -6,14 +5,21 @@ namespace Avalonia.Controls.UnitTests
|
||||
{
|
||||
public class CursorFactoryMock : ICursorFactory
|
||||
{
|
||||
public IPlatformHandle GetCursor(StandardCursorType cursorType)
|
||||
public ICursorImpl GetCursor(StandardCursorType cursorType)
|
||||
{
|
||||
return new PlatformHandle(IntPtr.Zero, cursorType.ToString());
|
||||
return new MockCursorImpl();
|
||||
}
|
||||
|
||||
public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
public ICursorImpl CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
||||
{
|
||||
return new PlatformHandle(IntPtr.Zero, "Custom");
|
||||
return new MockCursorImpl();
|
||||
}
|
||||
|
||||
private class MockCursorImpl : ICursorImpl
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user