dioxus-dnd 3.0.0 — multi-window desktop drag and drop
dioxus-dnd 3.0.0
Version 3.0 is the multi-window desktop release. It adds process-wide drag worlds for sibling Dioxus windows, promotes the verified desktop bridge into supported library API, hardens growing event types for future releases, and ships a complete concept-guide and API-reference documentation set.
The crate targets Dioxus 0.7 and requires Rust 1.85 or newer.
Multi-window desktop drag and drop
Enable the host integration explicitly:
dioxus-dnd = { version = "3.0.0", features = ["desktop"] }Multi-window drags carry the original Rust payload between windows of one application. They do not serialize the payload and do not use HTML5 DataTransfer.
The model has two layers:
DndWorld<T>is always available in the dependency-free core.use_dnd_world::<T>()creates a process-lived world containing the sharedDndContext<T>and joined-window table.- The
desktopfeature addsuse_window_geometry_feed()andDragBridge<T>, backed by dioxus-desktop, Tao, a time-only Tokio runtime, tracing, and x11rb on Linux.
Create one world and pass it to each sibling VirtualDom with VirtualDom::with_root_context. In every window, call use_window_geometry_feed() above DndProvider<T> and render one DragBridge<T> inside the provider. Providers discover and join the world automatically; nested providers keep their normal shadowing behavior.
What is coordinated across windows
- Window-qualified zone registration and hit testing.
- Live Rust payload delivery into a zone owned by another
VirtualDom. - Global-physical-pixel to per-window CSS-pixel conversion, including scale factors.
- Exactly one presenting
DragOverlayper frame. - Drop-settle animation in the receiving window, including when the origin window closes during settlement.
- Modifier-aware Move, Copy, and Link effects at host-side release.
- Window visibility, minimization, resize, scale-factor changes, focus order, close, and reopen.
- Safe close ordering: the window that created the world may close first; surviving windows keep dragging.
The host-drive surface is public for non-Tao integrations: begin_from, track_global, drop_at_global, cancel_drag, update_modifiers, window lookup, geometry lookup, and active drag metadata.
Why DragBridge exists
Webviews do not provide one portable event shape outside their viewport. The bridge supplies the missing host-side observations while binding every poller and callback to the originating world/session generation. A delayed callback from drag N cannot drive drag N+1, duplicate reports are idempotent, and an event arriving after completion cannot resurrect a drag.
Bridging is pointer-aware:
- Mouse and pen need host bridging when webview pointer capture is unavailable.
- Touch is implicitly captured by the browser and is never bridged. This avoids double-driving a gesture with Windows' touch-synthesized mouse stream.
- Keyboard drags stay on the normal keyboard path and cannot be hijacked by host pointer input.
Platform support and verified boundaries
Windows 11 / WebView2: verified. WebView2 consumes the window mouse messages Tao would otherwise see, so the Windows leg uses WM_INPUT device events for raw movement, button release, and modifier keys. It enables Tao's DeviceEventFilter::Never once per process. The bridge includes a warning tripwire if a future Tao/WebView2 update begins delivering the supposedly absent window mouse events, while leaving raw input as sole owner to prevent double delivery.
The Windows ARM64 runtime matrix covered cross-window mouse and injected-touch drags, generation-bound raw tracking, desktop-dead-space cancellation and immediate restart, live target resizing, minimized-window exclusion, hovered/origin window closure, close/reopen churn, touch/mouse interleaving, and clean process exit. The tested machine was single-monitor, so mixed-DPI behavior is covered by coordinate tests but has not yet been exercised on a physical mixed-DPI rig.
Linux X11: verified under WSLg forced to X11. The origin polls the global cursor, foreign-window events reconcile release, and an x11rb root-pointer query detects button release over desktop dead space. A transient query miss skips one sample instead of killing the bridge.
Linux Wayland: explicit graceful degradation. Tao's live event-loop backend decision is authoritative. Wayland exposes neither global window placement nor a global cursor, so global geometry and every cross-window bridge leg remain disabled. Local, per-window drag and drop continues normally.
macOS: implemented but not runtime-verified. The current policy uses the portable cursor-poller and release legs. Treat macOS multi-window support as provisional until it receives an AppKit/WKWebView runtime pass.
See the multi-window guide, API reference, platform evidence, and working two-window example.
Operational controls
Cross-window bridging can be disabled without removing local drag behavior:
- Call
DndWorld::set_bridging(false)and inspect it withbridging_enabled(). - Set
DIOXUS_DND_NO_BRIDGE=1before process launch to start with bridging disabled. cancel_drag()remains available while bridging is disabled as an emergency escape hatch.
With tracing at debug, bridge engagement identifies the active leg as cursor-poller, release, x11-deadspace, or raw-input.
Breaking changes and migration
Growing public event types are now #[non_exhaustive] so adding context in future releases does not repeatedly break downstream code.
Add wildcard arms when matching:
GestureEventFileRejectionDragModePointerKind
Use .. when destructuring:
CanvasDropSortEventMoveEventTreeDropEvent
Replace literal construction with:
SortEvent::new(from, to)MoveEvent::new(item, from, to)TreeDropEvent::new(payload, target, intent)
DropEffect, DropIntent, and DropOutcome remain exhaustive by design.
GestureEvent::Hold is also part of the 3.0 input vocabulary. Custom state-machine drivers must handle it or use a wildcard arm.
Other major additions
- Typed JSON transport:
TypedDragSource<T>andTypedDropZone<T>under theserdefeature, with atext/plainfallback for non-typed consumers. PointerKindis recorded for every pointer drag and exposesimplicitly_captured()for safe host-bridge policy.- Runtime bridge diagnostics and a platform-model warning tripwire.
- Scheduled compatibility canaries for the latest published Dioxus 0.7 patch and Dioxus git
maincross-VirtualDomcontracts. - A complete
docs/tree: 22 concept guides and 19 API references. API Markdown is included directly as module Rustdoc, packaged with the crate, and built on docs.rs with all features. - CI Markdown linting, semver reporting, and a guard preventing Tao/Wry implementation types from leaking into the public desktop API.
Verification
The release commit passed both local and GitHub gates:
- Core plus serde tests: 103 unit tests, 28 multi-window tests, 2 cross-
VirtualDomseam tests, 60 runtime tests, and 5 typed-transport tests. - Desktop-feature tests: 115 unit tests plus the same integration suites.
- Strict Clippy across all targets with
serde desktopand warnings denied. - Rustdoc with all features and warnings denied.
- Markdown linting through pinned rumdl 0.2.30.
cargo-semver-checksagainst 2.4.0.- Packaged-crate build verification.
The complete change inventory is in the 3.0.0 changelog.