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

36
src/Avalonia.X11/X11CursorFactory.cs

@ -61,16 +61,28 @@ namespace Avalonia.X11
_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)
{
IntPtr handle;
if (cursorType == StandardCursorType.None)
handle = _nullCursor;
else
handle = GetCursorHandleCached(cursorType);
var handle = GetCursorHandle(cursorType);
return new CursorImpl(handle);
}
public IntPtr GetCursorHandle(StandardCursorType cursorType)
{
return cursorType == StandardCursorType.None ? _nullCursor : GetCursorHandleCached(cursorType);
}
public unsafe ICursorImpl CreateCursor(Bitmap cursor, PixelPoint 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);
}
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 readonly IntPtr _display;
@ -130,9 +151,10 @@ namespace Avalonia.X11
{
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);
else if(s_mapping.TryGetValue(type, out var cursorShape))
if (handle == 0 && s_mapping.TryGetValue(type, out var cursorShape))
handle = XLib.XCreateFontCursor(_display, cursorShape);
if (handle == IntPtr.Zero)

Loading…
Cancel
Save