JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.22k stars 1.18k forks source link

`AwtWindow`/`FileDialog` Closes When Parent Recomposes in Specific Situations #3821

Closed ScottHamper closed 1 year ago

ScottHamper commented 1 year ago

Describe the bug When using a composable function that abstracts around AwtWindow/FileDialog and accepts a parameter for the FileDialog parent, any composition changes in the parent Window seem to cause the FileDialog to close (via setVisible(false)).

Affected platforms Select one of the platforms below:

Versions

To Reproduce

@Composable
fun FileDialog(
    parent: Frame,
    onCloseRequest: () -> Unit,
) = AwtWindow(
    create = {
        // Replacing `parent` usage here with `null as Frame?` prevents the bug from occurring.
        object : FileDialog(parent, "Load File", LOAD) {
            override fun setVisible(isVisible: Boolean) {
                if (isVisible) {
                    println("AWT FileDialog opening")
                }

                super.setVisible(isVisible)

                if (!isVisible) return

                println("AWT FileDialog closing")
                onCloseRequest()
            }
        }
    },
    dispose = FileDialog::dispose,
)

fun main() = application {
    Window(
        onCloseRequest = ::exitApplication,
        state = rememberWindowState(size = DpSize(width = 400.dp, height = 400.dp)),
        title = "AwtWindow Close On Recomposition Bug",
        resizable = false,
    ) {
        var count by remember { mutableStateOf(0) }
        var isFileDialogOpen by remember { mutableStateOf(false) }

        Column {
            // Commenting out the `Text` component prevents the bug from occurring.
            Text("$count")

            Button(
                onClick = {
                    println("Setting isFileDialogOpen to true")
                    isFileDialogOpen = true
                },
            ) {
                Text("Load")
            }
        }

        if (isFileDialogOpen) {
            LaunchedEffect(Unit) {
                delay(2000)
                println("Incrementing count")
                count++
            }

            // Replacing the `FileDialog` function call with its body will prevent the bug from
            // occurring.
            FileDialog(
                parent = window,
                onCloseRequest = {
                    println("Setting isFileDialogOpen to false")
                    isFileDialogOpen = false
                },
            )
        }
    }
}
  1. Launch the program.
  2. Click the "Load" button.
  3. Wait two seconds.

Expected behavior The FileDialog remains open while the main window behind it recomposes to display the updated count value.

Screenshots awtwindow-bug

Additional context Any one of a few small tweaks to the code can prevent the bug from occurring. Each of these can be done independently of each other to work around the issue:

I've also set up a number of print statements to trace order of execution. Here's the output for a sample run:

Setting isFileDialogOpen to true
AWT FileDialog opening
Incrementing count
AWT FileDialog opening
AWT FileDialog closing
Setting isFileDialogOpen to false
AWT FileDialog closing
Setting isFileDialogOpen to false
m-sasha commented 1 year ago

This sounds like it's been fixed by https://github.com/JetBrains/compose-multiplatform-core/pull/863

Please try it in Compose 1.5.10-rc01

ScottHamper commented 1 year ago

Yes! The issue no longer occurs in 1.5.10-rc01. Sorry for the extraneous issue, but thanks for your time!

okushnikov commented 3 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.