diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt index b01bf993a979b..c3e807cb0a5f0 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/util/Windows.desktop.kt @@ -156,3 +156,13 @@ private val iconSize = Size(32f, 32f) internal fun Window.setIcon(painter: Painter?) { setIconImage(painter?.toAwtImage(density, layoutDirection, iconSize)) } + +internal fun Window.makeDisplayable() { + val oldPreferredSize = preferredSize + preferredSize = size + try { + pack() + } finally { + preferredSize = oldPreferredSize + } +} \ No newline at end of file diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt index d3449585bd6b0..8e924a1a5cc7c 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Dialog.desktop.kt @@ -17,7 +17,6 @@ package androidx.compose.ui.window import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Stable import androidx.compose.runtime.currentCompositionLocalContext import androidx.compose.runtime.getValue @@ -30,6 +29,7 @@ import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.util.ComponentUpdater +import androidx.compose.ui.util.makeDisplayable import androidx.compose.ui.util.setIcon import androidx.compose.ui.util.setPositionSafely import androidx.compose.ui.util.setSizeSafely @@ -261,6 +261,11 @@ fun Dialog( it.compositionLocalContext = compositionLocalContext it.exceptionHandler = windowExceptionHandlerFactory.exceptionHandler(it) update(it) + + if (!it.isDisplayable) { + it.makeDisplayable() + it.contentPane.paint(it.graphics) + } } ) } diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt index dc97c2fd38b8a..76286a5ddb095 100644 --- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt +++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt @@ -17,7 +17,6 @@ package androidx.compose.ui.window import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable @@ -33,6 +32,7 @@ import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.util.ComponentUpdater +import androidx.compose.ui.util.makeDisplayable import androidx.compose.ui.util.setIcon import androidx.compose.ui.util.setPositionSafely import androidx.compose.ui.util.setSizeSafely @@ -375,6 +375,11 @@ fun Window( it.compositionLocalContext = compositionLocalContext it.exceptionHandler = windowExceptionHandlerFactory.exceptionHandler(it) update(it) + + if (!it.isDisplayable) { + it.makeDisplayable() + it.contentPane.paint(it.graphics) + } } ) } diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/TestUtils.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/TestUtils.kt index 7439c137003c3..d212b0a67e125 100644 --- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/TestUtils.kt +++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/TestUtils.kt @@ -16,6 +16,7 @@ package androidx.compose.ui.window +import androidx.compose.runtime.Composable import androidx.compose.runtime.Recomposer import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -55,10 +56,7 @@ internal fun runApplicationTest( withTimeout(30000) { val exceptionHandler = TestExceptionHandler() withExceptionHandler(exceptionHandler) { - val testScope = WindowTestScope(this, useDelay, exceptionHandler) - if (testScope.isOpen) { - testScope.body() - } + WindowTestScope(this, useDelay, exceptionHandler).body() } exceptionHandler.throwIfCaught() } @@ -142,10 +140,25 @@ internal class WindowTestScope( var isOpen by mutableStateOf(true) private val initialRecomposers = Recomposer.runningRecomposers.value + // TODO(demin) replace launchApplication to launchTestApplication in all tests, + // because we don't close the window with simple launchApplication + fun launchTestApplication( + content: @Composable ApplicationScope.() -> Unit + ) = launchApplication { + if (isOpen) { + content() + } + } + + // TODO(demin) remove when we migrate from launchApplication to launchTestApplication (see TODO above) fun exitApplication() { isOpen = false } + fun exitTestApplication() { + isOpen = false + } + suspend fun awaitIdle() { if (useDelay) { delay(500) diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt index 461d9e11ba7b2..89dedf5def1f8 100644 --- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt +++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/dialog/DialogTest.kt @@ -16,8 +16,10 @@ package androidx.compose.ui.window.dialog +import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.DisposableEffect @@ -520,4 +522,35 @@ class DialogTest { exitApplication() } + + + @Test(timeout = 30000) + fun `should draw before dialog is visible`() = runApplicationTest { + var isComposed = false + var isDrawn = false + var isVisibleOnFirstComposition = false + var isVisibleOnFirstDraw = false + + launchTestApplication { + Dialog(onCloseRequest = ::exitApplication) { + if (!isComposed) { + isVisibleOnFirstComposition = window.isVisible + isComposed = true + } + + Canvas(Modifier.fillMaxSize()) { + if (!isDrawn) { + isVisibleOnFirstDraw = window.isVisible + isDrawn = true + } + } + } + } + + awaitIdle() + assertThat(isVisibleOnFirstComposition).isFalse() + assertThat(isVisibleOnFirstDraw).isFalse() + + exitTestApplication() + } } \ No newline at end of file diff --git a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt index 9548930234bee..dca8884470174 100644 --- a/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt +++ b/compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt @@ -16,8 +16,10 @@ package androidx.compose.ui.window.window +import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.material.Button import androidx.compose.material.Slider @@ -490,4 +492,34 @@ class WindowTest { exitApplication() } + + @Test(timeout = 30000) + fun `should draw before window is visible`() = runApplicationTest { + var isComposed = false + var isDrawn = false + var isVisibleOnFirstComposition = false + var isVisibleOnFirstDraw = false + + launchTestApplication { + Window(onCloseRequest = ::exitApplication) { + if (!isComposed) { + isVisibleOnFirstComposition = window.isVisible + isComposed = true + } + + Canvas(Modifier.fillMaxSize()) { + if (!isDrawn) { + isVisibleOnFirstDraw = window.isVisible + isDrawn = true + } + } + } + } + + awaitIdle() + assertThat(isVisibleOnFirstComposition).isFalse() + assertThat(isVisibleOnFirstDraw).isFalse() + + exitTestApplication() + } } \ No newline at end of file