Browse Source

Xdnd: set cursor

pull/20926/head
Julien Lebosquain 7 months ago
parent
commit
8a3416f457
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 65
      src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs
  2. 36
      src/Avalonia.X11/X11CursorFactory.cs

65
src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs

@ -29,7 +29,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
triggerEvent.Pointer.Capture(null); triggerEvent.Pointer.Capture(null);
var cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>(); var cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>() as X11CursorFactory;
using var handler = new Handler(platform, window.Handle, dataTransfer, allowedEffects, cursorFactory); using var handler = new Handler(platform, window.Handle, dataTransfer, allowedEffects, cursorFactory);
await handler.Completion; await handler.Completion;
@ -43,26 +43,28 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
private readonly IntPtr _sourceWindow; private readonly IntPtr _sourceWindow;
private readonly IDataTransfer _dataTransfer; private readonly IDataTransfer _dataTransfer;
private readonly DragDropEffects _allowedEffects; private readonly DragDropEffects _allowedEffects;
private readonly TaskCompletionSource<DragDropEffects> _completionSource = new(); private readonly X11CursorFactory? _cursorFactory;
private readonly DragDropDataProvider _dataProvider; private readonly DragDropDataProvider _dataProvider;
private readonly TaskCompletionSource<DragDropEffects> _completionSource = new();
private readonly IntPtr[] _formatAtoms; private readonly IntPtr[] _formatAtoms;
private X11WindowInfo? _originalSourceWindowInfo; private X11WindowInfo? _originalSourceWindowInfo;
private bool _pointerGrabbed; private bool _pointerGrabbed;
private XdndTargetInfo? _lastTarget; private XdndTargetInfo? _lastTarget;
private DragDropEffects _lastEffects; private DragDropEffects _currentEffects;
public Handler( public Handler(
AvaloniaX11Platform platform, AvaloniaX11Platform platform,
IntPtr sourceWindow, IntPtr sourceWindow,
IDataTransfer dataTransfer, IDataTransfer dataTransfer,
DragDropEffects allowedEffects, DragDropEffects allowedEffects,
ICursorFactory? cursorFactory) X11CursorFactory? cursorFactory)
{ {
_platform = platform; _platform = platform;
_sourceWindow = sourceWindow; _sourceWindow = sourceWindow;
_dataTransfer = dataTransfer; _dataTransfer = dataTransfer;
_allowedEffects = allowedEffects; _allowedEffects = allowedEffects;
_lastEffects = allowedEffects; _cursorFactory = cursorFactory;
_currentEffects = allowedEffects;
_dataProvider = new DragDropDataProvider(platform, dataTransfer.ToAsynchronous()); _dataProvider = new DragDropDataProvider(platform, dataTransfer.ToAsynchronous());
if (!platform.Windows.TryGetValue(sourceWindow, out var sourceWindowInfo)) if (!platform.Windows.TryGetValue(sourceWindow, out var sourceWindowInfo))
@ -86,7 +88,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
GrabMode.GrabModeAsync, GrabMode.GrabModeAsync,
GrabMode.GrabModeAsync, GrabMode.GrabModeAsync,
0, 0,
platform.Info.DefaultCursor, GetCursor(allowedEffects),
0); 0);
if (grabResult != GrabResult.GrabSuccess) if (grabResult != GrabResult.GrabSuccess)
@ -163,7 +165,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
} }
_lastTarget = target; _lastTarget = target;
_lastEffects = _allowedEffects; UpdateCurrentEffects(_allowedEffects);
if (target is { } newTarget) if (target is { } newTarget)
{ {
@ -212,7 +214,8 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
var accepted = (message.ptr2 & 1) == 1; var accepted = (message.ptr2 & 1) == 1;
var action = accepted ? message.ptr5 : 0; var action = accepted ? message.ptr5 : 0;
_lastEffects = XdndActionHelper.ActionToEffects(action, _platform.Info.Atoms); var effects = XdndActionHelper.ActionToEffects(action, _platform.Info.Atoms);
UpdateCurrentEffects(effects & _allowedEffects);
} }
private void OnXdndFinished(in XClientMessageEvent message) private void OnXdndFinished(in XClientMessageEvent message)
@ -225,11 +228,12 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
if (lastTarget.Version >= 5) if (lastTarget.Version >= 5)
{ {
var accepted = (message.ptr2 & 1) == 1; var accepted = (message.ptr2 & 1) == 1;
var action = accepted ? message.ptr5 : 0; var action = accepted ? message.ptr3 : 0;
_lastEffects = XdndActionHelper.ActionToEffects(action, _platform.Info.Atoms); var effects = XdndActionHelper.ActionToEffects(action, _platform.Info.Atoms);
UpdateCurrentEffects(effects & _allowedEffects);
} }
_completionSource.TrySetResult(_lastEffects); _completionSource.TrySetResult(_currentEffects);
} }
private XdndTargetInfo? FindXdndTarget(PixelPoint rootPosition) private XdndTargetInfo? FindXdndTarget(PixelPoint rootPosition)
@ -368,7 +372,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
{ {
if (targetWindow.DragDropDevice is not { } dragDropDevice) if (targetWindow.DragDropDevice is not { } dragDropDevice)
{ {
_lastEffects = DragDropEffects.None; UpdateCurrentEffects(DragDropEffects.None);
return; return;
} }
@ -385,7 +389,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
dragDropDevice.ProcessRawEvent(dragEvent); dragDropDevice.ProcessRawEvent(dragEvent);
_lastEffects = dragEvent.Effects; UpdateCurrentEffects(dragEvent.Effects & _allowedEffects);
} }
private void UngrabPointer() private void UngrabPointer()
@ -396,6 +400,39 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
XFlush(_platform.Display); XFlush(_platform.Display);
} }
private void UpdateCurrentEffects(DragDropEffects effects)
{
if (_currentEffects == effects)
return;
_currentEffects = effects;
if (_pointerGrabbed)
{
XChangeActivePointerGrab(
_platform.Display,
EventMask.ButtonPressMask | EventMask.ButtonReleaseMask | EventMask.PointerMotionMask,
GetCursor(effects),
0);
}
}
private IntPtr GetCursor(DragDropEffects effects)
{
if (_cursorFactory is not null)
{
if ((effects & DragDropEffects.Copy) != 0)
return _cursorFactory.GetCursorHandle(StandardCursorType.DragCopy);
if ((effects & DragDropEffects.Move) != 0)
return _cursorFactory.GetCursorHandle(StandardCursorType.DragMove);
if ((effects & DragDropEffects.Link) != 0)
return _cursorFactory.GetCursorHandle(StandardCursorType.DragLink);
return _cursorFactory.DragNoDropCursorHandle;
}
return _platform.Info.DefaultCursor;
}
public void Dispose() public void Dispose()
{ {
if (_pointerGrabbed) if (_pointerGrabbed)
@ -409,7 +446,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra
} }
_lastTarget = null; _lastTarget = null;
_lastEffects = DragDropEffects.None; _currentEffects = DragDropEffects.None;
if (_dataProvider.GetOwner() == _sourceWindow) if (_dataProvider.GetOwner() == _sourceWindow)
_dataProvider.SetOwner(0); _dataProvider.SetOwner(0);

36
src/Avalonia.X11/X11CursorFactory.cs

@ -61,16 +61,28 @@ namespace Avalonia.X11
_cursors = new Dictionary<StandardCursorType, IntPtr>(); _cursors = new Dictionary<StandardCursorType, IntPtr>();
} }
// We don't have a "DragNo" standard cursor type, but Xcursor provides one
public IntPtr DragNoDropCursorHandle
{
get
{
if (field == 0)
field = LoadDragNoDropCursor();
return field;
}
}
public ICursorImpl GetCursor(StandardCursorType cursorType) public ICursorImpl GetCursor(StandardCursorType cursorType)
{ {
IntPtr handle; var handle = GetCursorHandle(cursorType);
if (cursorType == StandardCursorType.None)
handle = _nullCursor;
else
handle = GetCursorHandleCached(cursorType);
return new CursorImpl(handle); return new CursorImpl(handle);
} }
public IntPtr GetCursorHandle(StandardCursorType cursorType)
{
return cursorType == StandardCursorType.None ? _nullCursor : GetCursorHandleCached(cursorType);
}
public unsafe ICursorImpl CreateCursor(Bitmap cursor, PixelPoint hotSpot) public unsafe ICursorImpl CreateCursor(Bitmap cursor, PixelPoint hotSpot)
{ {
return new XImageCursor(_display, cursor, hotSpot); return new XImageCursor(_display, cursor, hotSpot);
@ -84,6 +96,15 @@ namespace Avalonia.X11
return XLib.XCreatePixmapCursor(display, pixmap, pixmap, ref color, ref color, 0, 0); return XLib.XCreatePixmapCursor(display, pixmap, pixmap, ref color, ref color, 0, 0);
} }
private IntPtr LoadDragNoDropCursor()
{
var handle = XLib.XcursorLibraryLoadCursor(_display, "dnd-no-drop");
if (handle == 0)
handle = GetCursorHandleCached(StandardCursorType.No);
return handle;
}
private unsafe class XImageCursor : CursorImpl, IPlatformHandle private unsafe class XImageCursor : CursorImpl, IPlatformHandle
{ {
private readonly IntPtr _display; private readonly IntPtr _display;
@ -130,9 +151,10 @@ namespace Avalonia.X11
{ {
if (!_cursors.TryGetValue(type, out var handle)) if (!_cursors.TryGetValue(type, out var handle))
{ {
if(s_libraryCursors.TryGetValue(type, out var cursorName)) if (s_libraryCursors.TryGetValue(type, out var cursorName))
handle = XLib.XcursorLibraryLoadCursor(_display, cursorName); handle = XLib.XcursorLibraryLoadCursor(_display, cursorName);
else if(s_mapping.TryGetValue(type, out var cursorShape))
if (handle == 0 && s_mapping.TryGetValue(type, out var cursorShape))
handle = XLib.XCreateFontCursor(_display, cursorShape); handle = XLib.XCreateFontCursor(_display, cursorShape);
if (handle == IntPtr.Zero) if (handle == IntPtr.Zero)

Loading…
Cancel
Save