Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
<!-- Native Wayland host from the MemerGamer/uno fork; see docs/linux-port/wayland-packages.md -->
<PropertyGroup>
<UnoWaylandVersion Condition="'$(UnoWaylandVersion)' == ''">6.7.135-wayland.6</UnoWaylandVersion>
<!-- Set to true with the first UnoWaylandVersion whose X11 host drags to other apps itself (wayland/host-x11dnd); Files then stops starting its own X11 drag source. -->
<FilesUnoX11NativeDrag Condition="'$(FilesUnoX11NativeDrag)' == ''">false</FilesUnoX11NativeDrag>
</PropertyGroup>
<PropertyGroup Condition="'$(FilesUseUnoWayland)' == 'true'">
<RestoreConfigFile Condition="'$(RestoreConfigFile)' == ''">$(MSBuildThisFileDirectory)nuget.wayland.config</RestoreConfigFile>
Expand Down
31 changes: 30 additions & 1 deletion docs/linux-port/dnd.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,35 @@ When the pointer leaves the window Uno still calls `StartNativeDrag` and raises
`Application.UnhandledException`. `DesktopRuntimeGuards` marks exactly that exception as handled instead of letting Files' crash
handler exit the app (that was the reported crash). Uno then ends its own drag when the button is released.

## Uno's own X11 drag source (`FilesUnoX11NativeDrag`)

The MemerGamer/uno branch `wayland/host-x11dnd` gives Uno's X11 host an XDND v5 source, built like the Wayland host's
outgoing drag: it takes the drag as soon as Uno's drag starts (`IImmediateDragDropExtension`), moves the pointer grab to a private
X connection (drag icon window from the DragView snapshot, copy/move/link/no-drop cursors, Escape and Shift/Ctrl through a keyboard
grab), routes the pointer back into Uno while it is over the window the drag started in, and offers `text/uri-list` plus the text
targets. Files then only has to put the file list into `e.Data`, as on Wayland (`DesktopFileDragHelper.StartDrag`).

Released packages up to `6.7.135-wayland.6` do not contain it, so `FilesUnoX11NativeDrag` (Directory.Packages.props) defaults to
`false` and Files keeps starting its own X11 drag source. Set it to `true` together with the first `UnoWaylandVersion` that includes
the branch; `UNO_X11_NATIVE_DRAG` then skips `StartExternalDrag` on X11. The old source and `DesktopRuntimeGuards` stay as the path
for packages without it.

Verified with a LinuxFiles build using `-p:FilesUnoX11NativeDrag=true` and the branch's `Uno.UI.Runtime.Skia.X11.dll`:
- private Xvfb with a GTK3 drop target: copy, Shift move, Escape, a rejecting target (no-drop cursor), drop onto a folder in the
same window, and out to the target and back into the window;
- nested KWin with XWayland and a Wayland-native Dolphin: Copy Here from the drop menu, Shift move, Escape, out and back.
On Escape KWin ends its bridged drag without telling the X source and XWayland gets no button release; the Uno source cancels
when its target window disappears under a still pointer.

The same Uno branch fixes drops *into* Files from Wayland-native apps under XWayland (broken in alpha7 too): Uno's selection readers
threw away the host window's other X events while waiting for data, so KWin's `XdndDrop`/`XdndPosition` could be lost, after which
KWin waited for an answer forever and ignored the window for later drags. `XdndFinished` now also waits for the drop handlers.
Verified in a fresh nested KWin: Dolphin to the file list and onto a folder, repeated drops, Escape. Note that Files performs the
operation it accepted in DragOver (move within a file system) even when the source requested a copy; that is Files' own drop logic.

To trace a drag on a real desktop: `UNO_X11_DND_LOG=/tmp/xdnd.log` makes Uno's X11 host append every XDND message it sends and
receives (both directions) to that file.

## Dragging out to Wayland-native apps on KDE (XWayland bridge)

Files runs under XWayland, so a Wayland-native target (Dolphin, Kate) is not a window on the X server and the XDND tree walk never
Expand Down Expand Up @@ -85,7 +114,7 @@ under `dbus-run-session` with a private `XDG_RUNTIME_DIR` (the socket path must

## LINUX-TODO

- `LINUX-TODO(dnd)`: no drag icon or cursor feedback outside the window (the pointer is grabbed by Uno's window; changing it needs
- `LINUX-TODO(dnd)`: (fixed by Uno's X11 source once `FilesUnoX11NativeDrag` is on) no drag icon or cursor feedback outside the window (the pointer is grabbed by Uno's window; changing it needs
`XChangeActivePointerGrab` on that connection, or the Uno extension point). Dropping on a window that answers `XdndStatus` with
"reject" silently does nothing.
- `LINUX-TODO(dnd)`: the guard only covers file lists (`FileList_DragItemsStarting`). Drags from the sidebar, tabs and the shelf leave
Expand Down
1 change: 1 addition & 0 deletions src/Files.App/Files.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
<!-- Native Wayland host (default for the Linux desktop target, see Directory.Build.props); X11 stays the fallback -->
<PropertyGroup Condition="'$(TargetFramework)' == '$(DesktopTargetFramework)' And '$(FilesUseUnoWayland)' == 'true'">
<DefineConstants>$(DefineConstants);UNO_WAYLAND</DefineConstants>
<DefineConstants Condition="'$(FilesUnoX11NativeDrag)' == 'true'">$(DefineConstants);UNO_X11_NATIVE_DRAG</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DesktopTargetFramework)' And '$(FilesUseUnoWayland)' == 'true'">
<PackageReference Include="Uno.WinUI.Runtime.Skia.Wayland" />
Expand Down
15 changes: 11 additions & 4 deletions src/Files.App/Platforms/Desktop/Services/DesktopFileDragHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ public static async Task<bool> TryPasteFilesAsync(string destinationPath, IShell
}

/// <summary>
/// Makes a drag of <paramref name="paths"/> available to other applications. On the native Wayland host the dragged
/// <paramref name="data"/> carries the file list (<c>text/uri-list</c>) and the host offers it to the compositor once the
/// pointer leaves the window; on X11 the Files selection host follows the pointer instead.
/// Makes a drag of <paramref name="paths"/> available to other applications. When the Uno host drags to other clients
/// itself (Wayland, and X11 with <c>UNO_X11_NATIVE_DRAG</c>) the dragged <paramref name="data"/> carries the file list
/// (<c>text/uri-list</c>) and the host offers it; otherwise the Files X11 selection host follows the pointer.
/// </summary>
public static void StartDrag(DataPackage data, IEnumerable<string?> paths)
{
if (!MainWindow.Instance.IsWaylandWindow)
if (!HostDragsToOtherApps)
{
StartExternalDrag(paths);
return;
Expand Down Expand Up @@ -137,6 +137,13 @@ static async Task DragAsync(IFileDragSource source, List<string> existing)
}
}

// FilesUnoX11NativeDrag (Directory.Packages.props) marks Uno packages whose X11 host has its own XDND source.
#if UNO_X11_NATIVE_DRAG
private static bool HostDragsToOtherApps => true;
#else
private static bool HostDragsToOtherApps => MainWindow.Instance.IsWaylandWindow;
#endif

private static List<string> ExistingPaths(IEnumerable<string?> paths) =>
paths
.Where(path => !string.IsNullOrEmpty(path) && path[0] == '/' && (File.Exists(path) || Directory.Exists(path)))
Expand Down
Loading