Handle dropped files - fakeivchenko/lwjwae GitHub Wiki
Users drag files onto applications: a photo into an editor, a PDF into a reader, a folder into a project window. A page can read the names and the bytes of the files that a drop gives it, but never their paths, and the path is what a desktop application needs to open, move, or watch a file. lwjwae reads the paths natively and tells Java and the page. In this guide, a page has a drop zone that lists what lands on it, and Java counts the files.

Hear a drop in Java
window.onFileDrop calls a listener with a FileDropEvent when the user drops files from the file
manager onto the page:
public class Drops {
public static void main(String[] args) {
Application.launch(
WindowParameters.of("Drop", 560, 400),
window -> {
window.onFileDrop(
event ->
window.emit(
"heard",
"Java heard %d files at %d, %d"
.formatted(event.paths().size(), event.x(), event.y())));
window.loadResource("drop/index.html");
});
}
}
| Component | What it is |
|---|---|
paths() |
The files and folders, as absolute Paths, in the order that the file manager gave them. Never empty |
window() |
The window that the files landed on |
x(), y() |
Where the pointer was when the user let go, from the top left of the page |
The listener runs on a virtual thread, so it may read the files, or wait for something, without
blocking the window. onFileDrop returns an EventSubscription, and unlisten() stops it.
Hear a drop on the page
The page has no paths in the files of a drop event, so it asks lwjwae.files:
const zone = document.querySelector("#zone");
lwjwae.files.listen(({ paths, x, y }) => {
document.querySelector("#list").replaceChildren(...paths.map((path) => {
const item = document.createElement("li");
item.textContent = path;
return item;
}));
zone.textContent = paths.length + " files dropped";
});
listen resolves to the function that stops the listener. The payload has the same paths, x,
and y as the Java event. The ordinary events of the page, dragenter, dragover, dragleave,
and drop, still come, and are the place to light up the drop zone:
addEventListener("dragenter", () => zone.classList.add("over"));
addEventListener("dragleave", () => zone.classList.remove("over"));
addEventListener("drop", () => zone.classList.remove("over"));
What the window does with the file
Without help, an engine opens a file that lands on its page, and the application is gone from the
window. lwjwae stops that: it takes a dragover or a drop of files that the page leaves alone,
so the window stays where it is and the file goes to the listeners only.
- A page that handles
dragoveranddropitself, and callspreventDefault(), keeps its way, and Java still hears the drop. - A text field, a text area, or an editable element keeps its own drop, so dragging a link into a field still inserts the text.
- A drop of anything but files, such as selected text, is not a file drop and isn't reported.
Where it works
| Platform | How the paths come |
|---|---|
| Windows | The script that lwjwae adds to every page posts the files of each drop to the host, and WebView2 gives the host their full paths. The runtime must be 1.0.1264 or later |
| macOS | The web view reads the file URLs on the pasteboard of the drag as it takes the drop, and the place comes from the drop event of the page. Finder hands references to files, which arrive as their paths |
| Linux, GTK 3 | The text/uri-list of the drop. A file that lives only in a remote location, which the file manager mounted, is left out |
| Linux, GTK 4 | The window reads the files that the drag offers as it comes over the page, and the place comes from the drop event of the page. A file that isn't local is left out |
Good to know
xandyare where the pointer was, from the top left of the page. On Windows, macOS, and GTK 4 they are theclientXandclientYof thedropevent, sodocument.elementFromPoint(x, y)finds the element that got the files at any zoom. GTK 3 measures them in the pixels of the window, which are the pixels of the page only at a zoom of 1.- A folder arrives as one path. Walk it in Java, with
Files.walk, to get its files. - Paths with spaces,
#,%, and&arrive the way they are on the disk.