jvm: fix macOS accessibility crash and update Compose to 1.10.3#451
jvm: fix macOS accessibility crash and update Compose to 1.10.3#451rainxchzed merged 1 commit intomainfrom
Conversation
- Introduce `A11yCrashGuard` to prevent app freezes on macOS caused by a known `NullPointerException` in the Compose Multiplatform 1.10.x accessibility bridge. - Initialize `A11yCrashGuard` in `DesktopApp.kt` to catch and suppress the specific NPE within the AWT EventDispatchThread. - Upgrade Compose Multiplatform and related JetBrains dependencies from 1.10.1 to 1.10.3. - Expand allowed capabilities in `.claude/settings.local.json` to include web search and specific JetBrains/GitHub domains.
WalkthroughThe PR introduces a macOS-specific crash guard to handle Compose accessibility-related Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/A11yCrashGuard.kt (1)
35-50: Suppressing the NPE leaves the current event partially dispatched.When
super.dispatchEvent(event)throws, any listeners registered after the failing one for the same event are skipped. That's the intended trade-off per the docstring (VoiceOver may miss updates), but it also means non-a11y listeners on the same event are silently dropped. Worth calling out explicitly in the KDoc so future readers don't widen the catch.Also consider narrowing the match further — e.g., require
SemanticsOwnerAccessibilityin the class name — to reduce the chance of swallowing unrelated a11y NPEs introduced by future Compose releases.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/A11yCrashGuard.kt` around lines 35 - 50, The catch in dispatchEvent currently suppresses Compose accessibility NPEs (detected by isComposeA11yNpe) which leaves the current AWTEvent partially dispatched and silently drops subsequent non-a11y listeners; update the KDoc for dispatchEvent/A11yCrashGuard to explicitly state this trade‑off (that suppressing the exception skips later listeners for the same event) and narrow the isComposeA11yNpe matcher to be more specific (e.g., require "SemanticsOwnerAccessibility" in the exception stack/class name check) to avoid swallowing unrelated NPEs; keep the warned AtomicBoolean behavior unchanged but document the rationale and narrowed matching in the KDoc.gradle/libs.versions.toml (1)
36-48: Consider consolidatingresourceswithcompose-jetbrains.The
resourceskey (line 48) now holds the same value ascompose-jetbrains(line 36) and is used by a single Compose UI tooling artifact (line 131). Having two separately named keys pinned to the same version makes it easy for them to drift on the next bump. Consider reusingcompose-jetbrainsforui-tooling-previewunless there is a specific reason the Compose tooling artifact needs an independent version axis.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gradle/libs.versions.toml` around lines 36 - 48, The TOML defines both resources and compose-jetbrains with the same version; remove the duplicate resources key and update any dependency that uses resources (notably the Compose UI tooling artifact/ui-tooling-preview) to reference compose-jetbrains instead so version bumps stay unified; touch the libs.versions.toml entries (remove resources) and the build files where ui-tooling-preview is declared to point to the compose-jetbrains version key.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/A11yCrashGuard.kt`:
- Around line 26-30: install() currently pushes a new FilteringEventQueue every
call which stacks handlers; make it idempotent by adding a private AtomicBoolean
(e.g., "installed") checked at the start of install(): if already true return,
otherwise set it to true and proceed to push the FilteringEventQueue; reference
the existing install() function and the FilteringEventQueue class so future
calls become no-ops and avoid stacking multiple event queues.
---
Nitpick comments:
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/A11yCrashGuard.kt`:
- Around line 35-50: The catch in dispatchEvent currently suppresses Compose
accessibility NPEs (detected by isComposeA11yNpe) which leaves the current
AWTEvent partially dispatched and silently drops subsequent non-a11y listeners;
update the KDoc for dispatchEvent/A11yCrashGuard to explicitly state this
trade‑off (that suppressing the exception skips later listeners for the same
event) and narrow the isComposeA11yNpe matcher to be more specific (e.g.,
require "SemanticsOwnerAccessibility" in the exception stack/class name check)
to avoid swallowing unrelated NPEs; keep the warned AtomicBoolean behavior
unchanged but document the rationale and narrowed matching in the KDoc.
In `@gradle/libs.versions.toml`:
- Around line 36-48: The TOML defines both resources and compose-jetbrains with
the same version; remove the duplicate resources key and update any dependency
that uses resources (notably the Compose UI tooling artifact/ui-tooling-preview)
to reference compose-jetbrains instead so version bumps stay unified; touch the
libs.versions.toml entries (remove resources) and the build files where
ui-tooling-preview is declared to point to the compose-jetbrains version key.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bada8158-27f1-4185-b165-f955abb80728
📒 Files selected for processing (4)
.claude/settings.local.jsoncomposeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/A11yCrashGuard.ktcomposeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/DesktopApp.ktgradle/libs.versions.toml
| fun install() { | ||
| val osName = System.getProperty("os.name")?.lowercase().orEmpty() | ||
| if (!osName.contains("mac")) return | ||
| Toolkit.getDefaultToolkit().systemEventQueue.push(FilteringEventQueue()) | ||
| } |
There was a problem hiding this comment.
install() is not idempotent.
Every call pushes another FilteringEventQueue on top of the current system event queue. If startup ever invokes this twice (tests, hot-reload, restart paths), you'll stack filtering queues and each event will traverse multiple dispatchEvent frames. Consider guarding with an AtomicBoolean so subsequent calls are no-ops.
Proposed fix
object A11yCrashGuard {
+ private val installed = java.util.concurrent.atomic.AtomicBoolean(false)
+
fun install() {
val osName = System.getProperty("os.name")?.lowercase().orEmpty()
if (!osName.contains("mac")) return
+ if (!installed.compareAndSet(false, true)) return
Toolkit.getDefaultToolkit().systemEventQueue.push(FilteringEventQueue())
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@composeApp/src/jvmMain/kotlin/zed/rainxch/githubstore/A11yCrashGuard.kt`
around lines 26 - 30, install() currently pushes a new FilteringEventQueue every
call which stacks handlers; make it idempotent by adding a private AtomicBoolean
(e.g., "installed") checked at the start of install(): if already true return,
otherwise set it to true and proceed to push the FilteringEventQueue; reference
the existing install() function and the FilteringEventQueue class so future
calls become no-ops and avoid stacking multiple event queues.
A11yCrashGuardto prevent app freezes on macOS caused by a knownNullPointerExceptionin the Compose Multiplatform 1.10.x accessibility bridge.A11yCrashGuardinDesktopApp.ktto catch and suppress the specific NPE within the AWT EventDispatchThread..claude/settings.local.jsonto include web search and specific JetBrains/GitHub domains.Summary by CodeRabbit
Bug Fixes
Chores