From 64a37f4e7b16eaf8c405e60b98ab1a7f03c1719a Mon Sep 17 00:00:00 2001 From: Ivan Matkov Date: Wed, 18 Dec 2024 15:45:04 +0100 Subject: [PATCH] Add missing type checks to interop container listener --- .../compose/ui/awt/SwingPanel.desktop.kt | 2 +- .../ui/scene/ComposeSceneMediator.desktop.kt | 24 ++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt index e98b2a4f2237d..f08c15c86505a 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/awt/SwingPanel.desktop.kt @@ -119,7 +119,7 @@ internal fun FocusEvent.isFocusGainedHandledBySwingPanel(container: Container) = * @param key The unique identifier for the panel container. * @param focusComponent The component that should receive focus. */ -private class SwingInteropViewGroup( +internal class SwingInteropViewGroup( key: Int, private val focusComponent: Component ) : JPanel() { diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt index c00f9ed82bdfc..779a57b27621e 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/scene/ComposeSceneMediator.desktop.kt @@ -25,6 +25,7 @@ import androidx.compose.ui.SessionMutex import androidx.compose.ui.awt.AwtEventListener import androidx.compose.ui.awt.AwtEventListeners import androidx.compose.ui.awt.OnlyValidPrimaryMouseButtonFilter +import androidx.compose.ui.awt.SwingInteropViewGroup import androidx.compose.ui.awt.isFocusGainedHandledBySwingPanel import androidx.compose.ui.awt.runOnEDTThread import androidx.compose.ui.focus.FocusDirection @@ -171,11 +172,13 @@ internal class ComposeSceneMediator( requestRedraw = ::onComposeInvalidation ) - private val containerListener = object : ContainerListener { - private val clipMap = mutableMapOf() + private val interopContainerListener = object : ContainerListener { + private val clipMap = mutableMapOf() override fun componentAdded(e: ContainerEvent) { val component = e.child + if (component !is SwingInteropViewGroup) return + if (useInteropBlending) { // In case of interop blending, compose might draw content above this [component]. // But due to implementation of [JLayeredPane]'s lightweight/heavyweight mixing @@ -192,17 +195,19 @@ internal class ComposeSceneMediator( override fun componentRemoved(e: ContainerEvent) { val component = e.child + if (component !is SwingInteropViewGroup) return + removeClipComponent(component) component.unsubscribeFromMouseEvents(mouseListener) } - private fun addClipComponent(component: Component) { + private fun addClipComponent(component: SwingInteropViewGroup) { val clipRectangle = interopContainer.getClipRectForComponent(component) clipMap[component] = clipRectangle skiaLayerComponent.clipComponents.add(clipRectangle) } - private fun removeClipComponent(component: Component) { + private fun removeClipComponent(component: SwingInteropViewGroup) { clipMap.remove(component)?.let { skiaLayerComponent.clipComponents.remove(it) } @@ -350,9 +355,9 @@ internal class ComposeSceneMediator( container.add(invisibleComponent) container.add(contentComponent) - // Adding a listener after adding [invisibleComponent] and [contentComponent] - // to react only on changes with [interopLayer]. - container.addContainerListener(containerListener) + // Because interopContainer.root == container, add a listener only after adding + // [invisibleComponent] and [contentComponent] to react only on changes with [interopLayer]. + interopContainer.root.addContainerListener(interopContainerListener) // AwtDragAndDropManager support container.transferHandler = dragAndDropManager.transferHandler @@ -475,9 +480,10 @@ internal class ComposeSceneMediator( unsubscribe(contentComponent) - // Since rendering will not happen after, we needs to execute all scheduled updates + interopContainer.root.removeContainerListener(interopContainerListener) + // Since rendering will not happen after, we need to execute all scheduled updates interopContainer.dispose() - container.removeContainerListener(containerListener) + container.remove(contentComponent) container.remove(invisibleComponent) container.transferHandler = null