@@ -468,6 +468,7 @@ fun ApplicationScope.TrayApp(
468468 ) { }
469469
470470 // === Main popup window (ALWAYS MOUNTED) ===
471+ // === Main popup window (ALWAYS MOUNTED) ===
471472 DialogWindow (
472473 onCloseRequest = { requestHide() },
473474 title = " " ,
@@ -476,12 +477,21 @@ fun ApplicationScope.TrayApp(
476477 focusable = true ,
477478 alwaysOnTop = true ,
478479 transparent = true ,
479- visible = shouldShowWindow, // <- Toujours contrôlé par notre variable sécurisée
480+ visible = shouldShowWindow,
480481 state = dialogState,
481482 ) {
482- // Assure le positionnement correct au moment précis où on décide de montrer la fenêtre
483+ // Ensure proper initial position exactly WHEN we decide to show the window
483484 LaunchedEffect (shouldShowWindow, currentWindowSize) {
484485 if (shouldShowWindow) {
486+ // ================== CORRECTION POUR MACOS ==================
487+ // Sur macOS, il y a une condition de concurrence. On doit attendre un
488+ // instant pour que les coordonnées du clic soient mises à jour
489+ // avant de tenter de positionner la fenêtre.
490+ if (os == MACOS ) {
491+ delay(30 ) // 30ms est suffisant et imperceptible.
492+ }
493+ // =========================================================
494+
485495 val widthPx = currentWindowSize.width.value.toInt()
486496 val heightPx = currentWindowSize.height.value.toInt()
487497 dialogState.position = getTrayWindowPositionForInstance(
@@ -490,16 +500,18 @@ fun ApplicationScope.TrayApp(
490500 }
491501 }
492502
493- // Le reste de votre code est correct...
503+ // Attach/Detach platform listeners only while window is actually visible
494504 DisposableEffect (shouldShowWindow) {
495505 if (! shouldShowWindow) {
496506 onDispose { }
497507 return @DisposableEffect onDispose { }
498508 }
499509
510+ // Mark this as the tray popup (macOS visibility monitor)
500511 try { window.name = WindowVisibilityMonitor .TRAY_DIALOG_NAME } catch (_: Throwable ) {}
501512 runCatching { WindowVisibilityMonitor .recompute() }
502513
514+ // Bring to front on open
503515 invokeLater {
504516 try {
505517 window.toFront()
@@ -513,6 +525,7 @@ fun ApplicationScope.TrayApp(
513525 override fun windowLostFocus (e : WindowEvent ? ) {
514526 lastFocusLostAt = System .currentTimeMillis()
515527 if (os == WINDOWS && lastFocusLostAt < autoHideEnabledAt) {
528+ // Ignore focus loss during startup grace period on Windows
516529 return
517530 }
518531 requestHide()
@@ -543,6 +556,7 @@ fun ApplicationScope.TrayApp(
543556 }
544557 }
545558
559+ // Content wrapper with fade animation (state is preserved across show/hide)
546560 Box (
547561 modifier = Modifier
548562 .fillMaxSize()
0 commit comments