Skip to content

✨ Add Windows native lazy file clipboard write via JNA delayed rendering#3931

Merged
guiyanakuang merged 3 commits intomainfrom
feat/windows-native-lazy-clipboard
Feb 23, 2026
Merged

✨ Add Windows native lazy file clipboard write via JNA delayed rendering#3931
guiyanakuang merged 3 commits intomainfrom
feat/windows-native-lazy-clipboard

Conversation

@guiyanakuang
Copy link
Copy Markdown
Member

@guiyanakuang guiyanakuang commented Feb 23, 2026

Summary

  • Add WindowsLazyClipboard class implementing Windows delayed rendering for file-type clipboard data via JNA, mirroring the macOS NSPasteboardItemDataProvider approach (PR Add macOS native lazy file pasteboard write via NSPasteboardItemDataProvider #3930)
  • Add WM_RENDERFORMAT / WM_RENDERALLFORMATS constants and RegisterClipboardFormatA to User32 interface
  • Add WindowsNativePasteboardTest with 7 tests covering write, read, marker detection, and laziness verification

Design

Uses Windows delayed rendering: SetClipboardData(CF_HDROP, NULL) registers the format without providing data. When a consumer reads CF_HDROP, Windows sends WM_RENDERFORMAT to the clipboard owner window, which builds a DROPFILES structure with resolved file paths.

Key implementation details:

  • Single-thread architecture: Hidden window + message loop on newSingleThreadContext (Windows requires clipboard owner and message pump on same thread)
  • Cross-thread sync: CompletableDeferred for write results, PostMessage(WM_USER+1) to dispatch work to window thread
  • Eager CrossPaste marker: Custom clipboard format set immediately to prevent self-consumption
  • Correct GetMessage handling: Uses Function.getFunction("user32", "GetMessageW") with Int return to handle tri-state (>0/0/-1) properly, avoiding JNA's boolean mapping issue

Test plan

  • writeFilesToClipboard returns valid sequence number for single file
  • writeFilesToClipboard returns valid sequence number for multiple files
  • writeFilesToClipboard returns -1 for zero count
  • native clipboard single file is readable from JVM clipboard
  • native clipboard multiple files are readable from JVM clipboard
  • writeFilesToClipboard sets CrossPaste marker
  • data provider is NOT called during write - only on read (laziness proof)

Tests are @EnabledOnOs(OS.WINDOWS) — run with ./gradlew app:desktopTest --tests "com.crosspaste.paste.WindowsNativePasteboardTest" on Windows.

Use native API (OpenClipboard/EmptyClipboard/CloseClipboard) for inter-test
cleanup instead of JVM's setContents(StringSelection("")) which makes the
JVM the clipboard owner. Add awaitClipboardReady() to flush the AWT event
queue after native writes so WM_DESTROYCLIPBOARD is processed before reads.
@guiyanakuang guiyanakuang merged commit 5f766dd into main Feb 23, 2026
2 checks passed
@guiyanakuang guiyanakuang deleted the feat/windows-native-lazy-clipboard branch February 23, 2026 09:42
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