Apps ancrées au tray
Une fenêtre popup Compose ancrée à l'icône du tray — apps menu bar style Bartender / iStat, en Kotlin.
TrayApp transforme l'icône du tray en une vraie fenêtre Compose qui apparaît juste à côté — le pattern menu bar app rendu populaire par Bartender, iStat Menus, Hidden Bar. On clique sur l'icône, une fenêtre glisse ; on clique ailleurs, elle disparaît.
Expérimental
TrayApp est en alpha. L'API peut bouger. Opt-in avec @OptIn(ExperimentalTrayAppApi::class).
En bref
- Toute la popup est un canvas Compose — si l'on sait le dessiner, on peut l'ancrer.
- Visibilité, taille, mode de dismiss pilotables via
TrayAppState. - Combinable avec un menu contextuel au clic droit.
- Animations d'entrée / sortie avec valeurs par défaut par plateforme.
Installation
TrayApp est inclus dans composenativetray — pas de dépendance additionnelle.
Démarrage rapide
@OptIn(ExperimentalTrayAppApi::class)
fun main() = application {
TrayApp(
icon = Icons.Default.Dashboard,
tooltip = "Quick dashboard",
windowSize = DpSize(300.dp, 400.dp),
) {
Column(Modifier.fillMaxSize().padding(16.dp)) {
Text("Dashboard", style = MaterialTheme.typography.h6)
Spacer(Modifier.height(8.dp))
Text("CPU: 42%")
Text("RAM: 8.2 GB")
}
}
}Fonctionnement
TrayApp = une icône tray + une fenêtre Compose transparente, sans décoration, toujours au-dessus. La bibliothèque suit la position de l'icône à l'écran et place la fenêtre à côté avec l'offset adapté à chaque OS. Le clic-en-dehors-pour-fermer est branché sur l'événement de perte de focus de l'OS, la popup se comporte de manière native partout.
Gestion d'état
@OptIn(ExperimentalTrayAppApi::class)
fun main() = application {
val state = rememberTrayAppState(
initialWindowSize = DpSize(350.dp, 500.dp),
initiallyVisible = false,
initialDismissMode = TrayWindowDismissMode.AUTO,
)
TrayApp(
icon = Icons.Default.Dashboard,
tooltip = "Dashboard",
state = state,
) {
Column {
Text("Dashboard")
Button(onClick = { state.hide() }) { Text("Fermer") }
Button(onClick = { state.setWindowSize(500.dp, 600.dp) }) { Text("Redimensionner") }
}
}
}TrayAppState
| API | Description |
|---|---|
isVisible: StateFlow<Boolean> | visibilité courante |
show() / hide() / toggle() | contrôle impératif |
setWindowSize(size) | redimensionne à la volée |
setDismissMode(mode) | AUTO (clic dehors ferme) ou MANUAL |
onVisibilityChanged(cb) | observer les transitions |
Avec un menu contextuel
Clic gauche ouvre la popup, clic droit ouvre un menu classique :
@OptIn(ExperimentalTrayAppApi::class)
fun main() = application {
TrayApp(
icon = Icons.Default.Dashboard,
tooltip = "Dashboard",
menu = {
Item(label = "Réglages") { openSettings() }
Divider()
Item(label = "Quitter") { exitProcess(0) }
},
) {
Text("Contenu de la popup")
}
}Options de fenêtre
| Paramètre | Défaut | Notes |
|---|---|---|
windowSize | DpSize(300.dp, 200.dp) | taille initiale |
visibleOnStart | false | affiche tout de suite |
enterTransition / exitTransition | défaut plateforme | animations |
transparent | true | fond transparent |
undecorated | true | sans cadre |
resizable | false | redim utilisateur |
horizontalOffset / verticalOffset | 0 / défaut plateforme | décalage depuis l'icône |
Cycle de vie tray-only (macOS)
Une tray app veut généralement pas d'icône dans le Dock. Sur macOS, mets LSUIElement = true dans l'Info.plist — le plugin Gradle Nucleus expose macOS.infoPlist.extraKeysRawXml :
nucleus {
application {
nativeDistributions {
macOS {
infoPlist {
extraKeysRawXml = """
<key>LSUIElement</key>
<true/>
""".trimIndent()
}
}
}
}
}L'app tourne sans entrée Dock ni barre de menus — juste l'icône du tray.
Voir aussi
- System tray et DSL menu du tray.
- Single instance — pratique pour qu'un re-launch depuis le
.appré-affiche la popup au lieu de démarrer un second process.
DSL menu du tray
Construis le menu contextuel du tray comme un DSL Kotlin réactif à Compose — items, cases à cocher, sous-menus, séparateurs, contenu conditionnel.
Raccourcis globaux
Enregistre des raccourcis clavier au niveau OS qui se déclenchent même quand le app n'a pas le focus — lecteurs média, captures d'écran, outils d'accessibilité.