https://kotlinlang.org logo
#compose-desktop
Title
# compose-desktop
k

K

10/16/2023, 11:06 AM
How can I use multiple
java.awt.FileDialog
at the same time? For example, keep a
FileDialog
open, and open another one later, JVM will crashes if the first one close first.
Copy code
java.awt.EventQueue.invokeLater {
    val dialog1 = java.awt.FileDialog(window)
    dialog1.isVisible = true
}
delay(1000)
java.awt.EventQueue.invokeLater {
    val dialog2 = java.awt.FileDialog(window)
    dialog2.isVisible = true
}
a

Alexander Maryanovsky

10/16/2023, 12:09 PM
I don’t see any Compose code in that sample.
k

K

10/16/2023, 12:17 PM
Well yes, but is there any file chooser implemented in Compose?
The section about Swing interoperability
k

K

10/16/2023, 12:48 PM
Thanks for your help. The problem is not how to control window state, unlike window,
fileDialog.setVisible(Boolean)
is a blocking call.
a

Alexander Maryanovsky

10/16/2023, 12:49 PM
Can you make it non-modal?
k

K

10/16/2023, 12:50 PM
I don't know much about AWT, but Compose desktop is based on AWT, and I want to use file chooser with Compose desktop.
Can you make it non-modal?
Possible a right way to do non-modal? but no luck.
Copy code
val d = java.awt.FileDialog(null as java.awt.Frame?)
d.isModal = false
d.isVisible = true
a

Alexander Maryanovsky

10/16/2023, 1:07 PM
Can you post a complete example?
k

K

10/16/2023, 1:08 PM
OK, I'll post a example with the code of Swing interoperability section.
> Can you post a complete example?
Copy code
@Composable
    private fun FileDialog(
        title: String? = "Choose a file",
        parent: Frame? = null,
        onCloseRequest: (result: String?) -> Unit
    ) = AwtWindow(
        create = {
            object : java.awt.FileDialog(parent, title) {
                override fun setVisible(value: Boolean) {
                    super.setVisible(value)
                    if (value) {
                        onCloseRequest(file)
                    }
                }
            }
        },
        dispose = java.awt.FileDialog::dispose
    )

    @JvmStatic
    fun main(args: Array<String>) {
        application {
            Window(onCloseRequest = ::exitApplication) {
                MaterialTheme {
                    Surface {
                        var isOpen by remember { mutableStateOf(false) }
                        Column {
                            // uncomment for recompose.
//                            val num by produceState(0) {
//                                var i = 1
//                                while (true) {
//                                    delay(1000)
//                                    value = i++
//                                }
//                            }
//                            Text(text = "num = $num") //test if UI thread blocking.

                            Button(
                                onClick = { isOpen = !isOpen },
                            ) {
                                Text("FileDialog isOpen = $isOpen")
                            }
                        }

                        if (isOpen) {
                            println("recompose!!")
                            FileDialog(
                                title = "1",
                                parent = window,
                                onCloseRequest = { isOpen = false }
                            )
                            FileDialog(
                                title = "2",
                                parent = window,
                                onCloseRequest = { isOpen = false }
                            )
                        }
                    }
                }
            }
        }
    }
The comments inside
AwtWindow
pointed out this problem already. UI freezing due to the blocking call inside it, so I can't press two button for two different FileDialog.
a

Alexander Maryanovsky

10/16/2023, 1:43 PM
What’s the issue? Seems to work ok for me.
k

K

10/16/2023, 1:43 PM
Anther problem is AwtWindow works bad if scope recomposed.
What’s the issue? Seems to work ok for me.
Close "1" then close "2", JVM crash.
a

Alexander Maryanovsky

10/16/2023, 1:45 PM
I can’t close 1 because 2 is modal
k

K

10/16/2023, 1:45 PM
?.. I'm using linux x64.
d

dhia chemingui

10/16/2023, 1:45 PM
@K @Alexander Maryanovsky me to I am getting this error and i cant understand why ? 2023-10-16 144440.286 java[4309:89991] * Assertion failure in -[NSEvent subtype], NSEvent.m:3051
k

K

10/16/2023, 1:47 PM
@dhia chemingui Does this explains something? I'm bad at English. https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/awt006.html
a

Alexander Maryanovsky

10/16/2023, 1:47 PM
@K Looks like a bug in the JVM or your window manager.
On Mac OS X I can’t close 1 even if they’re not modal.
k

K

10/16/2023, 1:48 PM
What if
parent = null,
?
a

Alexander Maryanovsky

10/16/2023, 1:50 PM
Looks like it’s a Mac OS X thing. The first dialog can’t be interacted with at all.
k

K

10/16/2023, 1:55 PM
> Anther problem is AwtWindow works bad if scope recomposed. Don't forget this problem. I just found that Dialog flashing, because recompose. Uncomment
uncomment for recompose
for test.
👀 1
a

Alexander Maryanovsky

10/16/2023, 1:57 PM
k

K

10/16/2023, 1:59 PM
.. He's not me.
a

Alexander Maryanovsky

10/16/2023, 2:00 PM
Sorry, linked the fix now.
k

K

10/16/2023, 2:16 PM
I think it's JVM problem. Is event dispatching thread not a normal thread?
Copy code
private val lock = Any()

fun java.awt.Window.blockingVisible(value: Boolean = true) {
    synchronized(lock) {
        println("inside lock")
        isVisible = value
    }
    println("outside lock ")
}
inside lock inside lock outside lock dialog2 closed outside lock dialog1 closed
a

Alexander Maryanovsky

10/16/2023, 2:23 PM
Making a modal dialog visible blocks and starts another event loop inside. That’s why you’re seeing this strange order of calls.
a

Alexander Maryanovsky

10/16/2023, 2:46 PM
That’s not what’s happening here
Here it’s the same thread
d

dhia chemingui

10/16/2023, 2:56 PM
how to deal with this error and what it mean java[5940:193234] * Assertion failure in -[NSEvent subtype], NSEvent.m:3051
k

K

10/16/2023, 3:59 PM
Here it’s the same thread
Seems not the same thread to me. That's why when one setVisible blocking, other one setVisible get called.
Copy code
private val mainSingleDispatcher = MainUIDispatcher.limitedParallelism(1)

suspend fun java.awt.Window.blockingSetVisible(value: Boolean = true) {
    withContext(mainSingleDispatcher) {
        isVisible = value
    }
}
Now I can fix it by this code. Always limit only one dialog to open.
a

Alexander Maryanovsky

10/16/2023, 4:02 PM
Print the thread to see
k

K

10/16/2023, 4:22 PM
Looks like it's the same thread. But could you please tell me the difference between limitedParallelism(2) and limitedParallelism(1) if there is only one thread? I can use limitedParallelism(1) to limit the second dialog not opening.
Inside the fileDialog.setVisible method, event dispatcher thread invokes next event, that's the reason seeing that strange order of calls. So this also breaks the window state due to stack calls. Open dialog 1 Open dialog 2 Close dialog 1 Close dialog 2
m

Michael Paus

10/17/2023, 9:06 AM
Another question is whether this is a good UX anyway. Do you know any application where you can open two files at the same time with two separate file dialogs?
k

K

10/17/2023, 10:48 AM
No two separate file dialogs needed, but it should not crashes when two dialogs opened, or prevent two dialogs opened.
After switch JVM from JBR to OpenJDK, no crash anymore!
a

Alexander Maryanovsky

10/17/2023, 10:49 AM
Then file a bug with JBR
😮‍💨 1
8 Views