JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.93k stars 1.16k forks source link

Scroll stops working after Alt-Tab #1317

Open igordmn opened 2 years ago

igordmn commented 2 years ago

Compose 1.0.0-beta3, Windows 11

import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
import kotlinx.coroutines.delay

@Composable
private fun App() {
    val state = rememberScrollState()
    Column(Modifier.size(300.dp).verticalScroll(state)) {
        repeat(20) {
            Item(it)
        }
    }
}

@Composable
private fun Item(num: Int) {
    var isHovered by remember { mutableStateOf(false) }
    Box(
        Modifier
            .fillMaxWidth()
            .height(50.dp)
            .padding(8.dp)
            .background(if (isHovered) Color.Red else Color.Green)
            .pointerInput(Unit) {
                while (true) {
                    awaitPointerEventScope<Unit> {
                        val event = awaitPointerEvent()
                        when (event.type) {
                            PointerEventType.Enter -> {
                                isHovered = true
                            }
                            PointerEventType.Exit -> {
                                isHovered = false
                            }
                        }
                    }
                }
            }
    ) {
        Text(num.toString())
    }
}

fun main() {
    singleWindowApplication {
        App()
    }
}
  1. Run the application
  2. Move cursor into the scrollable content
  3. Press Alt-Tab to switch to another application
  4. Don't move the cursor
  5. Press Alt-Tab to switch to Compose window
  6. Try to scroll the content with mouse wheel

Result: content isn't scrolling.

igordmn commented 2 years ago

Pure Swing reproducer (JDK 15):

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import java.awt.Dimension
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionListener
import javax.swing.JFrame

fun main() {
    runBlocking(Dispatchers.Swing) {
        val window = JFrame().apply {
            addMouseMotionListener(object : MouseMotionListener {
                override fun mouseDragged(e: MouseEvent?) = Unit
                override fun mouseMoved(e: MouseEvent?) = println("mouseMoved")
            })
            addMouseWheelListener {
                println("mouseWheelMoved")
            }

            size = Dimension(500, 500)
            isVisible = true
        }

        launch {
            while(true) {
                delay(500)
                println(window.focusOwner)
            }
        }
    }
}

IDEA has this issue too

igordmn commented 2 years ago

The issue in the Alt key. When we press it, usually the top menu receives the focus. I checked other applications (Fork, default Windows notepad) and they move focus to the top menu when we press Alt. So they have similar issue, when we return to the application again.

But Swing/Compose applications don't have top menu by default

igordmn commented 2 years ago

Window 10 consumes Alt if press Tab after it. Windows 11 seems doesn't consume it

okushnikov commented 3 weeks ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.