Skip to content

Commit 37806e6

Browse files
authored
Merge pull request #357 from kdroidFilter/fix/macos-tray-popup-latency
Pre-compute tray position at click time to remove display latency
2 parents 635815f + 3b5118f commit 37806e6

1 file changed

Lines changed: 30 additions & 9 deletions

File tree

  • src/commonMain/kotlin/com/kdroid/composetray/tray/api

src/commonMain/kotlin/com/kdroid/composetray/tray/api/TrayApp.kt

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)