Skip to content

Type file paths into the terminal for X11/pgtk drops and clipboard-image pastes - #626

Merged
dakra merged 3 commits into
mainfrom
fix/x11-drag-and-drop
Aug 13, 2026
Merged

dakra merged 3 commits into
mainfrom
fix/x11-drag-and-drop

Conversation

@dakra

@dakra dakra commented Aug 12, 2026 •

Copy link
Copy Markdown
Owner

Problem

On X11 and pgtk, dropping a file onto a ghostel buffer opened it with find-file instead of typing its path into the terminal. Those ports dispatch drag-n-drop through special-event-map, which is handled inside read_char before any key-sequence lookup — so the <drag-n-drop> binding in ghostel-mode-map never fires there. (NS and w32 bind the event in the global map instead, which the mode map shadows; that's why drops always worked on macOS.)

Relatedly, there was no way to paste a clipboard image (e.g. a screenshot) into the terminal at all: a PTY has no inbound image channel, so an image can only reach a terminal program as a file path.

File drops (commit 1)

Register a buffer-local dnd-protocol-alist handler in ghostel-mode (the same mechanism dired uses). The handler:

  • shell-quotes the dropped path and sends it to the PTY, followed by a separating space (also how ghostty/Terminal.app behave); multi-file drops arrive space-separated
  • converts hostname-qualified local URIs (file://<localhost>/path) via dnd-get-local-file-uri, mirroring the stock dnd-open-file chain
  • ignores foreign-host URIs with a message
  • falls back to dnd-open-local-file when the terminal has no live process, so drops into a [Process exited] buffer behave like stock Emacs instead of vanishing into a retired PTY

The existing <drag-n-drop> keymap binding stays for NS/w32; its file branch now shares the same sending helper, so file drops end with a separating space on all ports.

Clipboard images and PDFs via yank-media (commits 2-3)

Register a buffer-local yank-media handler (Emacs 29+) for image/.* and application/pdf that writes the clipboard bytes to a temp file and types its shell-quoted path, sharing the send path with drag-and-drop. The file is created in the temp directory of the host the shell runs on, so TRAMP terminals receive a valid host-side path; the bytes are written in the exclusive-create call under a binary coding system so a dos-EOL default cannot corrupt them. A paste into a dead terminal signals user-error.

Emacs 31's autoselect only prefers png/jpeg, which strands TIFF-only clipboards (Qt applications like Flameshot declare TIFF on macOS) with "No preferred MIME type to yank" — ghostel-mode appends a buffer-local catch-all to yank-media-preferred-types so any image flavor (and PDF, after images) autoselects while stock priorities still win.

Verification

  • Drag-and-drop verified live on Linux (Emacs 30.2 X11/GTK3 under Xvfb, real XDND ClientMessage drops); yank-media verified live on macOS (GUI Emacs 31 NS), including a genuinely TIFF-only pasteboard (NSPasteboard declareTypes: — AppleScript-set clipboards advertise synthesized flavors and don't reproduce the bug).
  • 8 new ERT tests drive the real dnd-handle-multiple-urls entry point; 6 new ERT tests cover the yank-media handler (byte round-trip across all 256 byte values under a dos-EOL default, remote localname, autoselect, dead-terminal guard).

Known limitations, deliberately out of scope: Emacs 29 pgtk consults dnd-protocol-alist in the wrong buffer (no with-selected-window before Emacs 30; main supported version is 30+), Emacs 30+'s dnd-handle-multiple-urls delivers 3+-URI drops out of source order (upstream quirk in its collection loop), text/URL drops on X11 keep their stock behavior, and pasted temp files are left to OS temp reaping (the shell consumes the path after every ghostel-visible event has passed).

dakra added 2 commits August 12, 2026 21:41
X11 and pgtk dispatch drag-and-drop through special-event-map and the
dnd-protocol-alist machinery, so the <drag-n-drop> binding in
ghostel-mode-map never fires there and a dropped file opened with
find-file instead of typing its path.  Register a buffer-local
dnd-protocol-alist handler (the dired pattern) that shell-quotes the
dropped path into the terminal, converts hostname-qualified local
URIs, ignores foreign-host URIs, and falls back to opening the file
when the terminal has no live process.  File drops now end with a
separating space on all ports.
A PTY has no inbound image channel, so a clipboard image can only
reach a terminal program as a file path.  Register a buffer-local
yank-media handler (Emacs 29+) that writes the clipboard image to a
temp file and types its shell-quoted path, sharing the send path with
drag-and-drop.  The file is created in the temp directory of the host
the shell runs on, so TRAMP terminals receive a valid host-side path;
the bytes are written in the exclusive-create call under a binary
coding system so a dos-EOL default cannot corrupt them.  A drop into
a dead terminal signals user-error.  The extension mapping inlines
the MIME-subtype rule because mailcap-mime-type-to-extension is
Emacs 29+ and package-lint rejects the unguarded call.
@dakra dakra changed the title Intercept file drops via dnd-protocol-alist for X11 and pgtk Type file paths into the terminal for X11/pgtk drops and clipboard-image pastes Aug 12, 2026
The yank-media handler already writes arbitrary clipboard bytes to a
temp file, so register it for application/pdf as well and rename it to
ghostel--yank-media-data.  The autoselect catch-all also accepts PDF,
after image flavors, so a PDF-only clipboard pastes while an image
still wins when both are offered.
@dakra
dakra merged commit ad64eb4 into main Aug 13, 2026
29 checks passed
@dakra
dakra deleted the fix/x11-drag-and-drop branch August 13, 2026 07:19

This branch was previously deployed

1 inactive deployment
github-pages — ad64eb44 Deployed Aug 13, 2026 by dakra via deploy #156
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant