Skip to content

Commit bef00f9

Browse files
committed
Add unique window handling to prevent duplicates
Introduces a 'unique' parameter to PDESwingWindow and PDEComposeWindow, allowing windows to be identified by a KClass and preventing multiple instances of the same window. If a window with the same unique identifier exists, it is brought to the front and the new one is disposed. This helps avoid duplicate welcome or other singleton windows.
1 parent 3b5ea1d commit bef00f9

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

app/src/processing/app/ui/PDEWelcome.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,15 @@ fun noBaseWarning() {
613613

614614
val size = DpSize(970.dp, 600.dp)
615615
const val titleKey = "menu.help.welcome"
616+
class WelcomeScreen
616617

617618
fun showWelcomeScreen(base: Base? = null) {
618-
PDESwingWindow(titleKey = titleKey, size = size.toDimension(), fullWindowContent = true) {
619+
PDESwingWindow(
620+
titleKey = titleKey,
621+
size = size.toDimension(),
622+
unique = WelcomeScreen::class,
623+
fullWindowContent = true
624+
) {
619625
PDEWelcome(base)
620626
}
621627
}

app/src/processing/app/ui/theme/Window.kt

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,24 @@ import androidx.compose.foundation.layout.*
55
import androidx.compose.material3.Text
66
import androidx.compose.runtime.Composable
77
import androidx.compose.runtime.CompositionLocalProvider
8-
import androidx.compose.runtime.LaunchedEffect
8+
import androidx.compose.runtime.DisposableEffect
99
import androidx.compose.runtime.compositionLocalOf
1010
import androidx.compose.runtime.remember
1111
import androidx.compose.ui.Alignment
1212
import androidx.compose.ui.Modifier
13-
import androidx.compose.ui.awt.ComposePanel
1413
import androidx.compose.ui.awt.ComposeWindow
1514
import androidx.compose.ui.graphics.Color
1615
import androidx.compose.ui.unit.DpSize
1716
import androidx.compose.ui.unit.dp
1817
import androidx.compose.ui.window.Window
19-
import androidx.compose.ui.window.WindowPlacement
2018
import androidx.compose.ui.window.WindowPosition
2119
import androidx.compose.ui.window.application
2220
import androidx.compose.ui.window.rememberWindowState
2321
import com.formdev.flatlaf.util.SystemInfo
2422
import java.awt.Dimension
2523

26-
import java.awt.event.KeyAdapter
27-
import java.awt.event.KeyEvent
2824
import javax.swing.JFrame
29-
import javax.swing.UIManager
25+
import kotlin.reflect.KClass
3026

3127
val LocalWindow = compositionLocalOf<JFrame> { error("No Window Set") }
3228

@@ -48,6 +44,8 @@ val LocalWindow = compositionLocalOf<JFrame> { error("No Window Set") }
4844
* @param size The desired size of the window. If null, the window will use its default size.
4945
* @param minSize The minimum size of the window. If null, no minimum size is set.
5046
* @param maxSize The maximum size of the window. If null, no maximum size is set.
47+
* @param unique An optional unique identifier for the window to prevent duplicates.
48+
* @param onClose A lambda function to be called when the window is requested to close.
5149
* @param fullWindowContent If true, the content will extend into the title bar area on macOS.
5250
* @param content The composable content to be displayed in the window.
5351
*/
@@ -56,6 +54,7 @@ class PDESwingWindow(
5654
size: Dimension? = null,
5755
minSize: Dimension? = null,
5856
maxSize: Dimension? = null,
57+
unique: KClass<*>? = null,
5958
fullWindowContent: Boolean = false,
6059
onClose: () -> Unit = {},
6160
content: @Composable () -> Unit
@@ -75,7 +74,13 @@ class PDESwingWindow(
7574
}
7675
setLocationRelativeTo(null)
7776
setContent {
78-
PDEWindowContent(window, titleKey, fullWindowContent, content)
77+
PDEWindowContent(
78+
window = window,
79+
titleKey = titleKey,
80+
unique = unique,
81+
fullWindowContent = fullWindowContent,
82+
content = content
83+
)
7984
}
8085
window.addWindowStateListener {
8186
if(it.newState == JFrame.DISPOSE_ON_CLOSE){
@@ -87,19 +92,23 @@ class PDESwingWindow(
8792
}
8893
}
8994

95+
private val windows = mutableMapOf<KClass<*>, ComposeWindow>()
96+
9097
/**
9198
* Internal Composable function to set up the window content with theming and localization.
9299
* It also handles macOS specific properties for full window content.
93100
*
94101
* @param window The JFrame instance to be configured.
95102
* @param titleKey The key for the window title, which will be localized.
103+
* @param unique An optional unique identifier for the window to prevent duplicates.
96104
* @param fullWindowContent If true, the content will extend into the title bar area on macOS.
97105
* @param content The composable content to be displayed in the window.
98106
*/
99107
@Composable
100108
private fun PDEWindowContent(
101109
window: ComposeWindow,
102110
titleKey: String,
111+
unique: KClass<*>? = null,
103112
fullWindowContent: Boolean = false,
104113
content: @Composable () -> Unit
105114
){
@@ -108,6 +117,20 @@ private fun PDEWindowContent(
108117
window.rootPane.putClientProperty("apple.awt.fullWindowContent", mac && fullWindowContent)
109118
window.rootPane.putClientProperty("apple.awt.transparentTitleBar", mac && fullWindowContent)
110119
}
120+
if(unique != null && windows.contains(unique) && windows[unique] != null){
121+
windows[unique]?.toFront()
122+
window.dispose()
123+
return
124+
}
125+
126+
DisposableEffect(unique){
127+
unique?.let {
128+
windows[it] = window
129+
}
130+
onDispose {
131+
windows.remove(unique)
132+
}
133+
}
111134

112135
CompositionLocalProvider(LocalWindow provides window) {
113136
PDETheme{
@@ -148,20 +171,18 @@ private fun PDEWindowContent(
148171
* fullscreen if it contains any of [fillMaxWidth]/[fillMaxSize]/[fillMaxHeight] etc.
149172
* @param minSize The minimum size of the window. Defaults to unspecified size which means no minimum size is set.
150173
* @param maxSize The maximum size of the window. Defaults to unspecified size which means no maximum size is set.
151-
* @param fullWindowContent If true, the content will extend into the title bar area on
152-
* macOS.
174+
* @param unique An optional unique identifier for the window to prevent duplicates.
175+
* @param fullWindowContent If true, the content will extend into the title bar area on macOS.
153176
* @param onClose A lambda function to be called when the window is requested to close.
154177
* @param content The composable content to be displayed in the window.
155-
*
156-
*
157-
*
158178
*/
159179
@Composable
160180
fun PDEComposeWindow(
161181
titleKey: String,
162182
size: DpSize = DpSize.Unspecified,
163183
minSize: DpSize = DpSize.Unspecified,
164184
maxSize: DpSize = DpSize.Unspecified,
185+
unique: KClass<*>? = null,
165186
fullWindowContent: Boolean = false,
166187
onClose: () -> Unit = {},
167188
content: @Composable () -> Unit
@@ -175,7 +196,13 @@ fun PDEComposeWindow(
175196
window.minimumSize = minSize.toDimension()
176197
window.maximumSize = maxSize.toDimension()
177198
}
178-
PDEWindowContent(window, titleKey, fullWindowContent, content)
199+
PDEWindowContent(
200+
window = window,
201+
titleKey = titleKey,
202+
unique = unique,
203+
fullWindowContent = fullWindowContent,
204+
content = content
205+
)
179206
}
180207
}
181208

0 commit comments

Comments
 (0)