Draggable for GUI apps
APACHE-2.0 License
Start a drag operation out of a window on macOS, Windows and Linux (via GTK).
Tested for tao (latest), winit (latest), wry (v0.24) and tauri (v1) windows. Due to the GTK-based implementation, winit currently cannot leverage this crate on Linux yet.
This project also includes a Tauri plugin for simplified usage on Tauri apps.
There's two ways to consume this crate API: from Rust code via the drag
crate or from Tauri's frontend via tauri-plugin-drag
or tauri-plugin-drag-as-window
.
drag
dependency:$ cargo add drag
Define the drag item and preview icon:
let item = drag::DragItem::Files(vec![std::fs::canonicalize("./examples/icon.png").unwrap()]);
let preview_icon = drag::Image::Raw(include_bytes!("../../icon.png").to_vec());
Use the drag::start_drag
function. It takes a &T: raw_window_handle::HasRawWindowHandle
type on macOS and Windows, and a >k::ApplicationWindow
on Linux:
let event_loop = tao::event_loop::EventLoop::new();
let window = tao::window::WindowBuilder::new().build(&event_loop).unwrap();
drag::start_drag(
#[cfg(target_os = "linux")]
{
use tao::platform::unix::WindowExtUnix;
window.gtk_window()
},
#[cfg(not(target_os = "linux"))]
&window,
item,
preview_icon,
);
let event_loop = wry::application::event_loop::EventLoop::new();
let window = wry::application::window::WindowBuilder::new().build(&event_loop).unwrap();
let webview = wry::webview::WebViewBuilder::new(window).unwrap().build().unwrap();
drag::start_drag(
#[cfg(target_os = "linux")]
{
use wry::application::platform::unix::WindowExtUnix;
webview.window().gtk_window()
},
#[cfg(not(target_os = "linux"))]
&webview.window(),
item,
preview_icon,
);
let event_loop = winit::event_loop::EventLoop::new().unwrap();
let window = winit::window::WindowBuilder::new().build(&event_loop).unwrap();
let _ = drag::start_drag(&window, item, preview_icon);
tauri::Builder::default()
.setup(|app| {
let window = app.get_window("main").unwrap();
drag::start_drag(
#[cfg(target_os = "linux")]
&window.gtk_window()?,
#[cfg(not(target_os = "linux"))]
&window,
item,
preview_icon
);
Ok(())
})
tauri-plugin-drag
dependency:$ cargo add tauri-plugin-drag
@crabnebula/tauri-plugin-drag
NPM package containing the API bindings:pnpm add @crabnebula/tauri-plugin-drag
# or
npm add @crabnebula/tauri-plugin-drag
# or
yarn add @crabnebula/tauri-plugin-drag
src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_drag::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
import { startDrag } from "@crabnebula/tauri-plugin-drag";
startDrag({ item: ['/path/to/drag/file'], icon: '/path/to/icon/image' })
tauri-plugin-drag-as-window
dependency:$ cargo add tauri-plugin-drag-as-window
@crabnebula/tauri-plugin-drag-as-window
NPM package containing the API bindings:pnpm add @crabnebula/tauri-plugin-drag-as-window
# or
npm add @crabnebula/tauri-plugin-drag-as-window
# or
yarn add @crabnebula/tauri-plugin-drag-as-window
src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_drag_as_window::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
import { dragAsWindow, dragBack } from "@crabnebula/tauri-plugin-drag-as-window";
import { appWindow, WebviewWindow } from "@tauri-apps/api/window";
// alternatively you can pass a DOM element instead of its selector
dragAsWindow('#my-drag-element', (payload) => {
console.log('dropped!')
// create the window with the content from the current element (that's is up to you!)
new WebviewWindow('label', {
x: payload.cursorPos.x,
y: payload.cursorPos.y,
})
})
const el = document.querySelector('#my-drag-element')
el.ondragstart = (event) => {
event.preventDefault()
dragBack(event.target, { data: 'some data' }, (payload) => {
appWindow.close()
})
}
Running the examples:
cargo run --bin [tauri-app|winit-app|tao-app|wry-app]
Additional drag as window examples are available for tauri and wry:
cargo run --bin [tauri-app-dragout|wry-app-dragout]
MIT or MIT/Apache 2.0 where applicable.