Unverified Commit 8b73b678 authored by Alexander Maryanovsky's avatar Alexander Maryanovsky Committed by GitHub

Fix FullscreenAdapter to be independent of the order of its listener calls (#689)

parent 7cdd091d
...@@ -6,34 +6,52 @@ import java.awt.event.ComponentAdapter ...@@ -6,34 +6,52 @@ import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent import java.awt.event.ComponentEvent
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
internal open class FullscreenAdapter( /**
* A proxy between [SkiaLayer] and [HardwareLayer] that keeps the assigned "fullscreen" state while the layer doesn't
* exist, and applies it once it does.
*/
internal class FullscreenAdapter(
val backedLayer: HardwareLayer val backedLayer: HardwareLayer
): ComponentAdapter() { ): ComponentAdapter() {
private var _isFullscreenDispatched = false
private var _isFullscreen: Boolean = false // Keep a `localFullscreen` flag which stores the virtual fullscreen state when the window is not actually
// visible, and apply it when the window does become visible.
private var localFullscreen = false
// Additionally, keep an `isWindowShown` flag that says whether `backedLayer` or `localFullscreen` is currently
// the source of truth. This flag must be used, rather than the real state (e.g. with `window.isVisible)
// because otherwise the code becomes dependent on the order of listener calls. For example, `componentResized`
// can be called when the window is already visible but before `componentShown` has been called. If the test
// in `componentResized` was on `window.isVisible`, it would reset the value of `localFullscreen` before it had
// applied in `componentShown`.
private var isWindowShown = false
var fullscreen: Boolean var fullscreen: Boolean
get() = _isFullscreen // If window is shown, return backedLayer.fullscreen; localFullscreen may not have updated yet
get() = if (isWindowShown) backedLayer.fullscreen else localFullscreen
set(value) { set(value) {
_isFullscreen = value localFullscreen = value
val window = SwingUtilities.getRoot(backedLayer) if (isWindowShown) {
if ( window == null || !window.isVisible) {
_isFullscreenDispatched = value
} else {
backedLayer.fullscreen = value backedLayer.fullscreen = value
} }
} }
override fun componentShown(e: ComponentEvent) { override fun componentShown(e: ComponentEvent) {
backedLayer.fullscreen = _isFullscreenDispatched isWindowShown = true
backedLayer.fullscreen = localFullscreen
} }
override fun componentHidden(e: ComponentEvent) { override fun componentHidden(e: ComponentEvent?) {
_isFullscreenDispatched = _isFullscreen isWindowShown = false
localFullscreen = backedLayer.fullscreen
} }
override fun componentResized(e: ComponentEvent) { override fun componentResized(e: ComponentEvent) {
_isFullscreen = backedLayer.fullscreen if (isWindowShown) {
localFullscreen = backedLayer.fullscreen
}
} }
} }
internal interface PlatformOperations { internal interface PlatformOperations {
......
...@@ -4,7 +4,6 @@ import org.jetbrains.skia.* ...@@ -4,7 +4,6 @@ import org.jetbrains.skia.*
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
import java.awt.Color import java.awt.Color
import java.awt.Component import java.awt.Component
import java.awt.Window
import java.awt.event.* import java.awt.event.*
import java.awt.geom.AffineTransform import java.awt.geom.AffineTransform
import java.awt.im.InputMethodRequests import java.awt.im.InputMethodRequests
...@@ -146,7 +145,7 @@ actual open class SkiaLayer internal constructor( ...@@ -146,7 +145,7 @@ actual open class SkiaLayer internal constructor(
override fun removeNotify() { override fun removeNotify() {
Logger.debug { "SkiaLayer.awt#removeNotify $this" } Logger.debug { "SkiaLayer.awt#removeNotify $this" }
val window = SwingUtilities.getRoot(this) as Window val window = SwingUtilities.getWindowAncestor(this)
window.removeComponentListener(fullscreenAdapter) window.removeComponentListener(fullscreenAdapter)
dispose() dispose()
super.removeNotify() super.removeNotify()
...@@ -155,7 +154,7 @@ actual open class SkiaLayer internal constructor( ...@@ -155,7 +154,7 @@ actual open class SkiaLayer internal constructor(
override fun addNotify() { override fun addNotify() {
Logger.debug { "SkiaLayer.awt#addNotify $this" } Logger.debug { "SkiaLayer.awt#addNotify $this" }
super.addNotify() super.addNotify()
val window = SwingUtilities.getRoot(this) as Window val window = SwingUtilities.getWindowAncestor(this)
window.addComponentListener(fullscreenAdapter) window.addComponentListener(fullscreenAdapter)
checkShowing() checkShowing()
init(isInited) init(isInited)
......
...@@ -23,6 +23,8 @@ import org.junit.Rule ...@@ -23,6 +23,8 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import java.awt.Color import java.awt.Color
import java.awt.Dimension import java.awt.Dimension
import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent
import java.awt.event.WindowEvent import java.awt.event.WindowEvent
import javax.swing.JFrame import javax.swing.JFrame
import javax.swing.JLayeredPane import javax.swing.JLayeredPane
...@@ -244,6 +246,34 @@ class SkiaLayerTest { ...@@ -244,6 +246,34 @@ class SkiaLayerTest {
} }
} }
@Test
fun `window fullscreen state in componentResized`() = uiTest {
val window = UiTestWindow()
try {
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.layer.fullscreen = true
var stateRemainsFullscreen = true
window.addComponentListener(object: ComponentAdapter(){
override fun componentResized(e: ComponentEvent?) {
if (!window.layer.fullscreen)
stateRemainsFullscreen = false
}
})
window.isVisible = true
delay(1000)
assertEquals(true, stateRemainsFullscreen)
} finally {
window.close()
// Delay before starting next test to let the window animation to complete, and allow the next window
// to become fullscreen
if (hostOs == OS.MacOS) {
delay(1000)
}
}
}
@Test @Test
fun `should call onRender after init, after resize, and only once after needRedraw`() = uiTest { fun `should call onRender after init, after resize, and only once after needRedraw`() = uiTest {
var renderCount = 0 var renderCount = 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment