From 770b8133a4f9ae876e1db994df0aaea484981c2e Mon Sep 17 00:00:00 2001 From: Elie Gambache Date: Sun, 31 May 2026 19:22:09 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Run=20JVM=20file=20picker=20off?= =?UTF-8?q?=20the=20main=20thread?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platformOpenFilePicker (JVM) ran PlatformFilePicker.openFilePicker / openFilesPicker directly on the caller's dispatcher, unlike openDirectoryPicker and openFileSaver which already wrap their blocking work in withContext(Dispatchers.IO). When a file picker is launched from a Compose Multiplatform desktop app whose Dispatchers.Main is the UI/event-loop thread, this blocks that thread: on Linux the picker's synchronous D-Bus work (xdg-desktop-portal connection build + OpenFile round-trip) freezes — and can deadlock — the UI before the first suspension point. AWT-only apps tolerate it because the portal handshake is driven by a separate toolkit thread, but no-AWT backends (e.g. Tao/winit on GTK) freeze. Wrap the picker body in withContext(Dispatchers.IO), matching the directory picker and file saver. --- .../kotlin/io/github/vinceglb/filekit/dialogs/FileKit.jvm.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.jvm.kt b/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.jvm.kt index add6127f..8d3f90a5 100644 --- a/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.jvm.kt +++ b/filekit-dialogs/src/jvmMain/kotlin/io/github/vinceglb/filekit/dialogs/FileKit.jvm.kt @@ -13,7 +13,7 @@ internal actual suspend fun FileKit.platformOpenFilePicker( mode: PickerMode, directory: PlatformFile?, dialogSettings: FileKitDialogSettings, -): Flow>> { +): Flow>> = withContext(Dispatchers.IO) { // Filter by extension val extensions = when (type) { FileKitType.Image -> imageExtensions @@ -42,7 +42,7 @@ internal actual suspend fun FileKit.platformOpenFilePicker( } } - return files.toPickerStateFlow() + files.toPickerStateFlow() } /**