From 8b12f46bc20c9c6e499f5a673bbb2c4fa893bada Mon Sep 17 00:00:00 2001 From: alonalbert Date: Tue, 7 May 2024 14:08:50 -0700 Subject: [PATCH] Saves and Restores the Focus Owner Before and After a Dialog is Shown (#39) * Saves and Restores the Focus Owner Before and After a Dialog is Shown This is probably related to `DialogSupportingSwingPanel` and sometimes causes a crash on Linux when: * Click in a code panel to set focus * Open Settings * Close Settings * Press any key I'm pretty sure this fixes it. I was able to repro very frequently before, and now I can't repro. That said, I was never able to get a 100% repro case. * Remove print statement --------- Co-authored-by: Romain Guy --- .../romainguy/kotlin/explorer/DialogState.kt | 53 +++++++++++++++++++ .../kotlin/explorer/KotlinExplorer.kt | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/DialogState.kt diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/DialogState.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/DialogState.kt new file mode 100644 index 00000000..897dcf9f --- /dev/null +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/DialogState.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 Romain Guy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.romainguy.kotlin.explorer + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import java.awt.Component +import javax.swing.FocusManager + +/** + * A [MutableState]<[Boolean]> that saves and restores the focus owner before and after a dialog is shown. + * + * This is probably related to [DialogSupportingSwingPanel] and sometimes causes a crash on Linux when: + * * Click in a code panel to set focus + * * Open Settings + * * Close Settings + * * Press any key + * + * TODO: Remove all this code + * See https://github.com/JetBrains/compose-multiplatform-core/pull/915 + */ +class DialogState(initial: Boolean) : MutableState { + private var state = mutableStateOf(initial) + private var focusOwner: Component? = null + override var value: Boolean + get() = state.value + set(value) { + if (value) { + focusOwner = FocusManager.getCurrentManager().focusOwner + } else { + focusOwner?.requestFocus() + } + state.value = value + } + + override fun component1() = state.component1() + + override fun component2() = state.component2() +} diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt index 35b996ef..ced0f553 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt @@ -127,7 +127,7 @@ private fun FrameWindowScope.KotlinExplorer( val codeTextAreas = listOf(byteCodeTextArea, dexTextArea, oatTextArea) val findDialog = remember { FindDialog(window, searchListener).apply { searchContext.searchWrap = true } } - var showSettings by remember { mutableStateOf(!explorerState.toolPaths.isValid) } + var showSettings by remember { DialogState(!explorerState.toolPaths.isValid) } val sourcePanel: @Composable () -> Unit = { SourcePanel(sourceTextArea, explorerState, showSettings) } val byteCodePanel: @Composable () -> Unit = { TextPanel("Byte Code", byteCodeTextArea, explorerState, showSettings) }