@@ -508,6 +508,9 @@ private fun ApplicationScope.TrayAppImplOriginal(
508508 var lastFocusLostAt by remember { mutableStateOf(0L ) }
509509 var autoHideEnabledAt by remember { mutableStateOf(0L ) }
510510
511+ // Position pre-computed at click time so the LaunchedEffect can use it immediately.
512+ var pendingPosition by remember { mutableStateOf<WindowPosition ?>(null ) }
513+
511514 val dialogState = rememberDialogState(size = currentWindowSize)
512515 LaunchedEffect (currentWindowSize) { dialogState.size = currentWindowSize }
513516
@@ -541,6 +544,15 @@ private fun ApplicationScope.TrayAppImplOriginal(
541544 if (getOperatingSystem() == WINDOWS && (now - lastFocusLostAt) < 300 ) {
542545 // ignore immediate re-show after focus loss on Windows
543546 } else {
547+ // Pre-compute position at click time: the native status item
548+ // geometry is guaranteed to be available right now.
549+ runCatching {
550+ val widthPx = currentWindowSize.width.value.toInt()
551+ val heightPx = currentWindowSize.height.value.toInt()
552+ pendingPosition = getTrayWindowPositionForInstance(
553+ tray.instanceKey(), widthPx, heightPx, horizontalOffset, verticalOffset
554+ )
555+ }
544556 trayAppState.show()
545557 }
546558 }
@@ -554,16 +566,25 @@ private fun ApplicationScope.TrayAppImplOriginal(
554566
555567 if (isVisible) {
556568 if (! shouldShowWindow) {
557- delay(250 ) // let tray click/dock settle (macOS)
558- val widthPx = currentWindowSize.width.value.toInt()
559- val heightPx = currentWindowSize.height.value.toInt()
560- var position: WindowPosition = WindowPosition .PlatformDefault
561- val deadline = System .currentTimeMillis() + 3000
562- while (position is WindowPosition .PlatformDefault && System .currentTimeMillis() < deadline) {
563- position = getTrayWindowPositionForInstance(
564- tray.instanceKey(), widthPx, heightPx, horizontalOffset, verticalOffset
565- )
569+ val preComputed = pendingPosition
570+ pendingPosition = null
571+
572+ val position = if (preComputed != null && preComputed !is WindowPosition .PlatformDefault ) {
573+ preComputed
574+ } else {
575+ // Fallback: poll for position (e.g. initiallyVisible or programmatic show)
566576 delay(250 )
577+ val widthPx = currentWindowSize.width.value.toInt()
578+ val heightPx = currentWindowSize.height.value.toInt()
579+ var pos: WindowPosition = WindowPosition .PlatformDefault
580+ val deadline = System .currentTimeMillis() + 3000
581+ while (pos is WindowPosition .PlatformDefault && System .currentTimeMillis() < deadline) {
582+ pos = getTrayWindowPositionForInstance(
583+ tray.instanceKey(), widthPx, heightPx, horizontalOffset, verticalOffset
584+ )
585+ if (pos is WindowPosition .PlatformDefault ) delay(250 )
586+ }
587+ pos
567588 }
568589 dialogState.position = position
569590
0 commit comments