Question
I'm working on a desktop application using Jetbrains Compose, but I'm open to solutions using Swing (it's used under the hood) as well. I want to implement a feature where the application window is initially located at the system tray icon, similar to how JetBrains Toolbox behaves (I want to place an (undecorated) window close to the tray icon).
Examples
I have tried using mouse events to detect clicks on the tray icon and position the window accordingly, but that approach doesn't achieve the desired behavior. It actually works, but window sometimes is jumping (depending on where I clicked and solution overall looks weird).
My previous solution
I publish my solution for case someone need it:
internal object XTray {
fun initialize(image: Image, onClick: (x: Int, y: Int) -> Unit) {
createTrayIcon(image, onClick)
}
private fun createTrayIcon(
image: Image,
onClick: (x: Int, y: Int) -> Unit,
): TrayIcon {
val systemTray = SystemTray.getSystemTray()
val trayIcon = TrayIcon(image, "Open X")
trayIcon.popupMenu = PopupMenu("X")
trayIcon.addMouseListener(createTrayMouseListener { x, y ->
onClick(x, y)
})
systemTray.add(trayIcon)
return trayIcon
}
private fun createTrayMouseListener(
onClick: (x: Int, y: Int) -> Unit,
): MouseAdapter {
return object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent?) {
e ?: return
if (SwingUtilities.isLeftMouseButton(e)) {
println("${e.x} & ${e.y}")
onClick(calculateWindowX(e.x), calculateWindowY(e.y))
}
}
}
}
private fun calculateWindowX(
trayCenterX: Int,
windowWidth: Int = 350,
screenWidth: Int = Toolkit.getDefaultToolkit().screenSize.width,
): Int {
val halfWindowWidth = windowWidth / 2
return when {
trayCenterX - halfWindowWidth < 0 -> 0 // Tray icon is closer to the left edge
trayCenterX + halfWindowWidth > screenWidth -> screenWidth - windowWidth // Tray icon is closer to the right edge
else -> trayCenterX - halfWindowWidth // Tray icon is in the middle of the screen
}
}
private fun calculateWindowY(
trayCenterY: Int,
windowHeight: Int = 650,
screenHeight: Int = Toolkit.getDefaultToolkit().screenSize.height,
): Int {
val halfWindowHeight = windowHeight / 2
return when {
trayCenterY - halfWindowHeight < 0 -> 0 // Tray icon is closer to the top edge
trayCenterY + halfWindowHeight > screenHeight -> screenHeight - windowHeight // Tray icon is closer to the bottom edge
else -> trayCenterY - halfWindowHeight // Tray icon is in the middle of the screen
}
}
}
Other applications, like JetBrains Toolbox, show their window at startup, without any need to locate a icon by click on that icon. So, there's should be another solution.
I suspect that I need to use system APIs to accomplish this, but I'm wondering if there is a ready-made solution or library that provides this functionality. It seems like a common feature, and I don't want to reinvent the wheel.
I'd like to look at examples, but I can't find them.