@@ -10,6 +10,8 @@ import io.github.kdroidfilter.platformtools.LinuxDesktopEnvironment
1010import io.github.kdroidfilter.platformtools.OperatingSystem
1111import io.github.kdroidfilter.platformtools.detectLinuxDesktopEnvironment
1212import io.github.kdroidfilter.platformtools.getOperatingSystem
13+ import java.awt.GraphicsEnvironment
14+ import java.awt.Rectangle
1315import java.awt.Toolkit
1416import java.io.File
1517import java.util.*
@@ -30,16 +32,16 @@ internal object TrayClickTracker {
3032 Collections .synchronizedMap(mutableMapOf ())
3133
3234 fun updateClickPosition (x : Int , y : Int ) {
33- val screenSize = getLogicalScreenSize( )
34- val position = convertPositionToCorner(x, y, screenSize .width, screenSize .height)
35+ val bounds = getScreenBoundsAt(x, y )
36+ val position = convertPositionToCorner(x - bounds.x , y - bounds.y, bounds .width, bounds .height)
3537 val pos = TrayClickPosition (x, y, position)
3638 lastClickPosition.set(pos)
3739 runCatching { saveTrayClickPosition(x, y, position) }
3840 }
3941
4042 fun updateClickPosition (instanceId : String , x : Int , y : Int ) {
41- val screenSize = getLogicalScreenSize( )
42- val position = convertPositionToCorner(x, y, screenSize .width, screenSize .height)
43+ val bounds = getScreenBoundsAt(x, y )
44+ val position = convertPositionToCorner(x - bounds.x , y - bounds.y, bounds .width, bounds .height)
4345 val pos = TrayClickPosition (x, y, position)
4446 perInstancePositions[instanceId] = pos
4547 lastClickPosition.set(pos)
@@ -71,6 +73,20 @@ private fun getLogicalScreenSize(): java.awt.Dimension {
7173 return Toolkit .getDefaultToolkit().screenSize
7274}
7375
76+ /* *
77+ * Returns the bounds of the screen that contains the given point.
78+ * Falls back to the primary screen if the point is not on any screen.
79+ */
80+ private fun getScreenBoundsAt (x : Int , y : Int ): Rectangle {
81+ val ge = GraphicsEnvironment .getLocalGraphicsEnvironment()
82+ for (gd in ge.screenDevices) {
83+ val bounds = gd.defaultConfiguration.bounds
84+ if (bounds.contains(x, y)) return bounds
85+ }
86+ val primary = Toolkit .getDefaultToolkit().screenSize
87+ return Rectangle (0 , 0 , primary.width, primary.height)
88+ }
89+
7490internal fun convertPositionToCorner (x : Int , y : Int , width : Int , height : Int ): TrayPosition {
7591 // Use smarter margins based on typical taskbar/panel size
7692 // 100px from edge = probably within taskbar/panel area
@@ -247,15 +263,13 @@ fun getTrayWindowPosition(
247263 return calculateWindowPositionFromClick(
248264 sx, sy, corner,
249265 windowWidth, windowHeight,
250- screenSize.width, screenSize.height,
251266 horizontalOffset, verticalOffset
252267 )
253268 }
254269
255270 return calculateWindowPositionFromClick(
256271 posToUse.x, posToUse.y, posToUse.position,
257272 windowWidth, windowHeight,
258- screenSize.width, screenSize.height,
259273 horizontalOffset, verticalOffset
260274 )
261275 }
@@ -270,7 +284,6 @@ fun getTrayWindowPosition(
270284 return calculateWindowPositionFromClick(
271285 pos.x, pos.y, pos.position,
272286 windowWidth, windowHeight,
273- screenSize.width, screenSize.height,
274287 horizontalOffset, verticalOffset
275288 )
276289 }
@@ -282,7 +295,6 @@ fun getTrayWindowPosition(
282295 return calculateWindowPositionFromClick(
283296 clickPos.x, clickPos.y, clickPos.position,
284297 windowWidth, windowHeight,
285- screenSize.width, screenSize.height,
286298 horizontalOffset, verticalOffset
287299 )
288300 }
@@ -314,7 +326,6 @@ fun getTrayWindowPositionForInstance(
314326 verticalOffset : Int = 0
315327): WindowPosition {
316328 val os = getOperatingSystem()
317- val screenSize = Toolkit .getDefaultToolkit().screenSize
318329
319330 return when (os) {
320331 OperatingSystem .WINDOWS -> {
@@ -323,7 +334,6 @@ fun getTrayWindowPositionForInstance(
323334 calculateWindowPositionFromClick(
324335 pos.x, pos.y, pos.position,
325336 windowWidth, windowHeight,
326- screenSize.width, screenSize.height,
327337 horizontalOffset, verticalOffset
328338 )
329339 }
@@ -341,12 +351,14 @@ fun getTrayWindowPositionForInstance(
341351 if (precise) {
342352 val regionStr = runCatching { lib.tray_get_status_item_region_for(trayStruct) }.getOrNull()
343353 val trayPos = if (regionStr != null ) getMacTrayPosition(regionStr)
344- else convertPositionToCorner(x, y, screenSize.width, screenSize.height)
354+ else {
355+ val bounds = getScreenBoundsAt(x, y)
356+ convertPositionToCorner(x - bounds.x, y - bounds.y, bounds.width, bounds.height)
357+ }
345358 TrayClickTracker .setClickPosition(instanceId, x, y, trayPos)
346359 return calculateWindowPositionFromClick(
347360 x, y, trayPos,
348361 windowWidth, windowHeight,
349- screenSize.width, screenSize.height,
350362 horizontalOffset, verticalOffset
351363 )
352364 }
@@ -360,44 +372,42 @@ fun getTrayWindowPositionForInstance(
360372
361373/* *
362374 * Calcule la position (x,y) depuis un clic précis + applique les offsets et un clamp aux bords écran.
375+ * Uses the screen containing the click point for correct multi-monitor support.
363376 */
364377private fun calculateWindowPositionFromClick (
365378 clickX : Int , clickY : Int , trayPosition : TrayPosition ,
366379 windowWidth : Int , windowHeight : Int ,
367- screenWidth : Int , screenHeight : Int ,
368380 horizontalOffset : Int ,
369381 verticalOffset : Int
370382): WindowPosition {
371383 val os = getOperatingSystem()
372384 val isTop = trayPosition == TrayPosition .TOP_LEFT || trayPosition == TrayPosition .TOP_RIGHT
373385 val isRight = trayPosition == TrayPosition .TOP_RIGHT || trayPosition == TrayPosition .BOTTOM_RIGHT
374386
387+ val sb = getScreenBoundsAt(clickX, clickY)
388+
375389 return if (os == OperatingSystem .WINDOWS ) {
376- // ---- Legacy behavior for Windows (keep exact clickY & raw offsets) ----
377390 var x = clickX - (windowWidth / 2 )
378391 var y = if (isTop) clickY else clickY - windowHeight
379392
380393 x + = horizontalOffset
381394 y + = verticalOffset
382395
383- if (x < 0 ) x = 0 else if (x + windowWidth > screenWidth ) x = screenWidth - windowWidth
384- if (y < 0 ) y = 0 else if (y + windowHeight > screenHeight ) y = screenHeight - windowHeight
396+ if (x < sb.x ) x = sb.x else if (x + windowWidth > sb.x + sb.width ) x = sb.x + sb.width - windowWidth
397+ if (y < sb.y ) y = sb.y else if (y + windowHeight > sb.y + sb.height ) y = sb.y + sb.height - windowHeight
385398 WindowPosition (x = x.dp, y = y.dp)
386399 } else {
387- // ---- New behavior for macOS & Linux: snap to bar edge (ignore clickY height within icon) ----
388- // Conservative guess of panel thickness; works well across GNOME/KDE and typical macOS menubar heights.
389400 val panelGuessPx = 28
390401
391402 var x = clickX - (windowWidth / 2 )
392- val anchorY = if (isTop) panelGuessPx else (screenHeight - panelGuessPx)
403+ val anchorY = if (isTop) sb.y + panelGuessPx else (sb.y + sb.height - panelGuessPx)
393404 var y = if (isTop) anchorY else anchorY - windowHeight
394405
395- // Direction-aware offsets: always push AWAY from the bar/edge for consistency.
396406 x + = if (isRight) - horizontalOffset else horizontalOffset
397407 y + = if (isTop) verticalOffset else - verticalOffset
398408
399- if (x < 0 ) x = 0 else if (x + windowWidth > screenWidth ) x = screenWidth - windowWidth
400- if (y < 0 ) y = 0 else if (y + windowHeight > screenHeight ) y = screenHeight - windowHeight
409+ if (x < sb.x ) x = sb.x else if (x + windowWidth > sb.x + sb.width ) x = sb.x + sb.width - windowWidth
410+ if (y < sb.y ) y = sb.y else if (y + windowHeight > sb.y + sb.height ) y = sb.y + sb.height - windowHeight
401411 WindowPosition (x = x.dp, y = y.dp)
402412 }
403413}
0 commit comments