Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clicking a clickable component inside another disabled clickable component throws IllegalStateException #5064

Open
mgroth0 opened this issue Jul 4, 2024 · 1 comment
Assignees
Labels
bug Something isn't working desktop input Touch, mouse, keyboard input related p:critical Critical priority regression reproduced

Comments

@mgroth0
Copy link

mgroth0 commented Jul 4, 2024

Describe the bug

When a clickable component is contained inside of another clickable component it can cause an error.

Affected platforms

  • Desktop (macOS)

Versions

  • Libraries:

    • Compose Multiplatform version: 1.7.0-dev1703
  • Kotlin version: 2.0.0

  • OS version(s) (required for Desktop and iOS issues): Mac 14.5

  • OS architecture (x86 or arm64): arm64

  • JDK (for desktop issues): 20

To Reproduce

I am including two reproducers. One in which I use the clickable modifier, and another with Button components.

Reproducer 1

  1. Run this code
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application


fun main() {
    application {
        Window(
            onCloseRequest = ::exitApplication
        ) {
            Box(
                Modifier.clickable(
                    enabled = false
                ) {
                }
            ) {
                Box(
                    Modifier
                        .fillMaxSize()
                        .clickable {
                        }
                )
            }
        }
    }
}
  1. Click the window anywhere
  2. Observe error

Reproducer 2

import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application


fun main() {
    application {
        Window(
            onCloseRequest = ::exitApplication
        ) {
            Button(
                enabled = false,
                onClick = {},
                content = {
                    Button(
                        onClick = {
                        }
                    ) {
                        Text("Click")
                    }
                }
            )
        }
    }
}

Context

I am trying to create a custom tab pane. The tab should be a clickable element, so that the user can select a tab. The currently selected tab has its clickable modifier disabled because it is already selected. Each tab also has an "x" icon for removing the tab. Basically, just like the tabs in any web browser which also have a clickable "x" inside of the clickable tab itself.

Expected behavior

No exception to be thrown. Or if an exception must be thrown, make it more informative and actionable.

Observed behavior

An exception is thrown with a popup message. Note the exception includes only internal stack trace elements.

This exception is thrown. Click here to expand and see the full stack trace.

Exception in thread "AWT-EventQueue-0 @coroutine#64" java.lang.IllegalStateException: Cannot obtain node coordinator. Is the Modifier.Node attached?
	at androidx.compose.ui.internal.InlineClassHelperKt.throwIllegalStateExceptionForNullCheck(InlineClassHelper.kt:30)
	at androidx.compose.ui.node.DelegatableNodeKt.requireLayoutNode(DelegatableNode.kt:1389)
	at androidx.compose.ui.node.DelegatableNodeKt.requireOwner(DelegatableNode.kt:336)
	at androidx.compose.ui.Modifier$Node.getCoroutineScope(Modifier.kt:198)
	at androidx.compose.foundation.FocusableNode.onFocusEvent(Focusable.kt:227)
	at androidx.compose.foundation.AbstractClickableNode.onFocusEvent(Clickable.kt:1102)
	at androidx.compose.ui.focus.FocusEventModifierNodeKt.refreshFocusEventNodes(FocusEventModifierNode.kt:68)
	at androidx.compose.ui.focus.FocusTransactionsKt.performRequestFocus(FocusTransactions.kt:82)
	at androidx.compose.ui.focus.FocusTransactionsKt.requestFocus-Mxy_nc0(FocusTransactions.kt:50)
	at androidx.compose.ui.focus.FocusTransactionsKt.requestFocus(FocusTransactions.kt:43)
	at androidx.compose.ui.focus.FocusRequesterModifierNodeKt.requestFocus(FocusRequesterModifierNode.kt:43)
	at androidx.compose.foundation.ClickableKt.requestFocusWhenInMouseInputMode(Clickable.kt:1302)
	at androidx.compose.foundation.ClickableKt.access$requestFocusWhenInMouseInputMode(Clickable.kt:1)
	at androidx.compose.foundation.ClickableNode$clickPointerInput$2.invokeSuspend(Clickable.kt:638)
	at androidx.compose.foundation.ClickableNode$clickPointerInput$2.invoke-d-4ec7I(Clickable.kt)
	at androidx.compose.foundation.ClickableNode$clickPointerInput$2.invoke(Clickable.kt)
	at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1$2.invokeSuspend(TapGestureDetector.kt:244)
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:42)
	at androidx.compose.foundation.AbstractClickableNode$onPointerEvent$3.invokeSuspend(Clickable.kt:1042)
	at androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNodeImpl$onPointerEvent$1.invokeSuspend(SuspendingPointerInputFilter.kt:622)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.scene.ComposeContainer$DesktopCoroutineExceptionHandler@124995dc, androidx.compose.runtime.BroadcastFrameClock@33358fcb, CoroutineId(64), "coroutine#64":StandaloneCoroutine{Cancelling}@32ee92be, FlushCoroutineDispatcher@20dbd708]
Caused by: java.lang.IllegalStateException: Cannot obtain node coordinator. Is the Modifier.Node attached?
	at androidx.compose.ui.internal.InlineClassHelperKt.throwIllegalStateExceptionForNullCheck(InlineClassHelper.kt:30)
	at androidx.compose.ui.node.DelegatableNodeKt.requireLayoutNode(DelegatableNode.kt:1389)
	at androidx.compose.ui.node.DelegatableNodeKt.requireOwner(DelegatableNode.kt:336)
	at androidx.compose.ui.Modifier$Node.getCoroutineScope(Modifier.kt:198)
	at androidx.compose.foundation.FocusableNode.onFocusEvent(Focusable.kt:227)
	at androidx.compose.foundation.AbstractClickableNode.onFocusEvent(Clickable.kt:1102)
	at androidx.compose.ui.focus.FocusEventModifierNodeKt.refreshFocusEventNodes(FocusEventModifierNode.kt:68)
	at androidx.compose.ui.focus.FocusTransactionsKt.performRequestFocus(FocusTransactions.kt:82)
	at androidx.compose.ui.focus.FocusTransactionsKt.requestFocus-Mxy_nc0(FocusTransactions.kt:50)
	at androidx.compose.ui.focus.FocusTransactionsKt.requestFocus(FocusTransactions.kt:43)
	at androidx.compose.ui.focus.FocusRequesterModifierNodeKt.requestFocus(FocusRequesterModifierNode.kt:43)
	at androidx.compose.foundation.ClickableKt.requestFocusWhenInMouseInputMode(Clickable.kt:1302)
	at androidx.compose.foundation.ClickableKt.access$requestFocusWhenInMouseInputMode(Clickable.kt:1)
	at androidx.compose.foundation.ClickableNode$clickPointerInput$2.invokeSuspend(Clickable.kt:638)
	at androidx.compose.foundation.ClickableNode$clickPointerInput$2.invoke-d-4ec7I(Clickable.kt)
	at androidx.compose.foundation.ClickableNode$clickPointerInput$2.invoke(Clickable.kt)
	at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1$2.invokeSuspend(TapGestureDetector.kt:244)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
	at androidx.compose.ui.platform.FlushCoroutineDispatcher$dispatch$2$1.invoke(FlushCoroutineDispatcher.skiko.kt:63)
	at androidx.compose.ui.platform.FlushCoroutineDispatcher$dispatch$2$1.invoke(FlushCoroutineDispatcher.skiko.kt:58)
	at androidx.compose.ui.platform.FlushCoroutineDispatcher.performRun(FlushCoroutineDispatcher.skiko.kt:102)
	at androidx.compose.ui.platform.FlushCoroutineDispatcher.access$performRun(FlushCoroutineDispatcher.skiko.kt:37)
	at androidx.compose.ui.platform.FlushCoroutineDispatcher$dispatch$2.invokeSuspend(FlushCoroutineDispatcher.skiko.kt:58)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.executePrivileged(AccessController.java:778)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

@mgroth0 mgroth0 added bug Something isn't working submitted labels Jul 4, 2024
@igordmn
Copy link
Collaborator

igordmn commented Jul 4, 2024

Thanks!

Reproduced on 1.7.0-alpha01, Desktop.

Isn't reproduced on 1.6.10 or Android.

@igordmn igordmn added input Touch, mouse, keyboard input related p:critical Critical priority regression and removed submitted labels Jul 4, 2024
@igordmn igordmn self-assigned this Jul 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working desktop input Touch, mouse, keyboard input related p:critical Critical priority regression reproduced
Projects
None yet
Development

No branches or pull requests

2 participants