@@ -30,15 +30,15 @@ internal object TrayClickTracker {
3030 Collections .synchronizedMap(mutableMapOf ())
3131
3232 fun updateClickPosition (x : Int , y : Int ) {
33- val screenSize = Toolkit .getDefaultToolkit().screenSize
33+ val screenSize = getLogicalScreenSize()
3434 val position = convertPositionToCorner(x, y, screenSize.width, screenSize.height)
3535 val pos = TrayClickPosition (x, y, position)
3636 lastClickPosition.set(pos)
3737 runCatching { saveTrayClickPosition(x, y, position) }
3838 }
3939
4040 fun updateClickPosition (instanceId : String , x : Int , y : Int ) {
41- val screenSize = Toolkit .getDefaultToolkit().screenSize
41+ val screenSize = getLogicalScreenSize()
4242 val position = convertPositionToCorner(x, y, screenSize.width, screenSize.height)
4343 val pos = TrayClickPosition (x, y, position)
4444 perInstancePositions[instanceId] = pos
@@ -63,11 +63,38 @@ internal object TrayClickTracker {
6363 fun getLastClickPosition (instanceId : String ): TrayClickPosition ? = perInstancePositions[instanceId]
6464}
6565
66- internal fun convertPositionToCorner (x : Int , y : Int , width : Int , height : Int ): TrayPosition = when {
67- x < width / 2 && y < height / 2 -> TrayPosition .TOP_LEFT
68- x >= width / 2 && y < height / 2 -> TrayPosition .TOP_RIGHT
69- x < width / 2 && y >= height / 2 -> TrayPosition .BOTTOM_LEFT
70- else -> TrayPosition .BOTTOM_RIGHT
66+ /* *
67+ * Get logical screen size (DPI-independent on Windows).
68+ * On Windows, Toolkit.getDefaultToolkit().screenSize returns logical coordinates.
69+ */
70+ private fun getLogicalScreenSize (): java.awt.Dimension {
71+ return Toolkit .getDefaultToolkit().screenSize
72+ }
73+
74+ internal fun convertPositionToCorner (x : Int , y : Int , width : Int , height : Int ): TrayPosition {
75+ // Use smarter margins based on typical taskbar/panel size
76+ // 100px from edge = probably within taskbar/panel area
77+ val edgeThreshold = 100
78+
79+ val isNearTop = y < edgeThreshold
80+ val isNearBottom = y > height - edgeThreshold
81+ val isNearLeft = x < edgeThreshold
82+ val isNearRight = x > width - edgeThreshold
83+
84+ return when {
85+ // Strong edge detection first
86+ isNearTop && isNearLeft -> TrayPosition .TOP_LEFT
87+ isNearTop && isNearRight -> TrayPosition .TOP_RIGHT
88+ isNearTop -> TrayPosition .TOP_RIGHT // Default top to right
89+ isNearBottom && isNearLeft -> TrayPosition .BOTTOM_LEFT
90+ isNearBottom && isNearRight -> TrayPosition .BOTTOM_RIGHT
91+ isNearBottom -> TrayPosition .BOTTOM_RIGHT // Default bottom to right
92+ // Fallback: use quadrant-based detection
93+ x >= width / 2 && y < height / 2 -> TrayPosition .TOP_RIGHT
94+ x < width / 2 && y < height / 2 -> TrayPosition .TOP_LEFT
95+ x >= width / 2 -> TrayPosition .BOTTOM_RIGHT
96+ else -> TrayPosition .BOTTOM_LEFT
97+ }
7198}
7299
73100private const val PROPERTIES_FILE = " tray_position.properties"
@@ -430,6 +457,32 @@ private fun dpiAwareHalfIconOffset(): Int {
430457 }
431458}
432459
460+ /* *
461+ * Detects the Windows taskbar height based on DPI scaling.
462+ * Default taskbar: 40px at 100%, 48px at 125%, 60px at 150%, etc.
463+ */
464+ private fun getWindowsTaskbarHeight (): Int {
465+ return try {
466+ val dpi = Toolkit .getDefaultToolkit().screenResolution
467+ val scale = dpi / 96.0
468+ // Taskbar default height: 40px at 100% scaling
469+ (40 * scale).roundToInt().coerceIn(32 , 72 )
470+ } catch (_: Throwable ) {
471+ 40
472+ }
473+ }
474+
475+ /* *
476+ * Gets the appropriate bar size (taskbar/menubar/panel) for the current OS.
477+ */
478+ private fun getSystemBarSize (): Int {
479+ return when (getOperatingSystem()) {
480+ OperatingSystem .WINDOWS -> getWindowsTaskbarHeight()
481+ OperatingSystem .MACOS -> 25 // macOS menu bar
482+ else -> 28 // Linux panel (GNOME/KDE average)
483+ }
484+ }
485+
433486internal fun isPointWithinMacStatusItem (px : Int , py : Int ): Boolean {
434487 if (getOperatingSystem() != OperatingSystem .MACOS ) return false
435488 val (ix, iy) = getStatusItemXYForMac()
0 commit comments