Skip to content

Commit ffea44a

Browse files
committed
Fix tray icon handling and enhance error safety
Zero-initialize NOTIFYICONIDENTIFIER in tray_windows.c to prevent undefined behavior, ensuring compatibility with Windows APIs. Refactored WindowsTrayManager to improve safety, including null pointer checks, better error handling for memory access issues, and extraction of reusable `safeGetTrayPosition` logic. Updated binaries to reflect these critical fixes.
1 parent c090f89 commit ffea44a

4 files changed

Lines changed: 53 additions & 33 deletions

File tree

src/commonMain/kotlin/com/kdroid/composetray/lib/windows/WindowsTrayManager.kt

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -160,27 +160,20 @@ internal class WindowsTrayManager(
160160
var consecutiveErrors = 0
161161
var initialPosCaptured = false
162162
var initialPosAttempts = 0
163+
var positionErrorCount = 0
164+
val maxPositionErrors = 3 // Stop trying after 3 errors to avoid spamming logs
163165

164166
while (running.get()) {
165167
try {
166168
// Try to capture initial precise tray icon position (per instance)
167-
if (!initialPosCaptured && initialPosAttempts < 60) {
169+
if (!initialPosCaptured && initialPosAttempts < 60 && positionErrorCount < maxPositionErrors) {
168170
initialPosAttempts++
169-
try {
170-
val xRef = IntByReference()
171-
val yRef = IntByReference()
172-
val precise = WindowsNativeTrayLibrary.tray_get_notification_icons_position(xRef, yRef) != 0
173-
if (precise) {
174-
val screen = java.awt.Toolkit.getDefaultToolkit().screenSize
175-
val corner = com.kdroid.composetray.utils.convertPositionToCorner(xRef.value, yRef.value, screen.width, screen.height)
176-
TrayClickTracker.setClickPosition(instanceId, xRef.value, yRef.value, corner)
177-
initialPosCaptured = true
178-
log("Captured initial tray icon position: ${xRef.value}, ${yRef.value}")
179-
}
180-
} catch (e: Exception) {
181-
// ignore and retry later
171+
if (safeGetTrayPosition(instanceId)) {
172+
initialPosCaptured = true
173+
log("Captured initial tray icon position")
182174
}
183175
}
176+
184177
// Check for pending updates
185178
processUpdateQueue()
186179

@@ -237,6 +230,36 @@ internal class WindowsTrayManager(
237230
log("Message loop ended")
238231
}
239232

233+
/**
234+
* Safely attempts to get the tray position with error handling
235+
* @return true if position was successfully obtained, false otherwise
236+
*/
237+
private fun safeGetTrayPosition(instanceId: String): Boolean {
238+
return try {
239+
val xRef = IntByReference()
240+
val yRef = IntByReference()
241+
val precise = WindowsNativeTrayLibrary.tray_get_notification_icons_position(xRef, yRef) != 0
242+
if (precise) {
243+
val screen = java.awt.Toolkit.getDefaultToolkit().screenSize
244+
val corner = com.kdroid.composetray.utils.convertPositionToCorner(
245+
xRef.value, yRef.value, screen.width, screen.height
246+
)
247+
TrayClickTracker.setClickPosition(instanceId, xRef.value, yRef.value, corner)
248+
true
249+
} else {
250+
false
251+
}
252+
} catch (e: Error) {
253+
// Handle invalid memory access error
254+
log("Failed to get tray icon position (memory access error): ${e.message}")
255+
false
256+
} catch (e: Exception) {
257+
// Handle other exceptions
258+
log("Failed to get tray icon position: ${e.message}")
259+
false
260+
}
261+
}
262+
240263
private fun processUpdateQueue() {
241264
val update = synchronized(updateQueueLock) {
242265
if (updateQueue.isNotEmpty()) {
@@ -276,8 +299,16 @@ internal class WindowsTrayManager(
276299

277300
// Update the native tray
278301
log("Calling tray_update()")
279-
WindowsNativeTrayLibrary.tray_update(newTray)
280-
log("tray_update() completed")
302+
try {
303+
WindowsNativeTrayLibrary.tray_update(newTray)
304+
log("tray_update() completed")
305+
} catch (e: Error) {
306+
log("Failed to update tray (memory access error): ${e.message}")
307+
e.printStackTrace()
308+
} catch (e: Exception) {
309+
log("Failed to update tray: ${e.message}")
310+
e.printStackTrace()
311+
}
281312

282313
// Update the reference
283314
tray.set(newTray)
@@ -291,14 +322,7 @@ internal class WindowsTrayManager(
291322
log("Left click callback invoked")
292323
try {
293324
// Capture precise tray position on the tray thread (per-instance)
294-
val xRef = IntByReference()
295-
val yRef = IntByReference()
296-
val precise = WindowsNativeTrayLibrary.tray_get_notification_icons_position(xRef, yRef) != 0
297-
if (precise) {
298-
val screen = java.awt.Toolkit.getDefaultToolkit().screenSize
299-
val corner = com.kdroid.composetray.utils.convertPositionToCorner(xRef.value, yRef.value, screen.width, screen.height)
300-
TrayClickTracker.setClickPosition(instanceId, xRef.value, yRef.value, corner)
301-
}
325+
safeGetTrayPosition(instanceId)
302326

303327
// Execute callback in IO scope (like macOS)
304328
mainScope?.launch {
@@ -360,14 +384,7 @@ internal class WindowsTrayManager(
360384
log("Menu item clicked: ${menuItem.text}")
361385
try {
362386
// Capture precise tray position on the tray thread (per-instance)
363-
val xRef = IntByReference()
364-
val yRef = IntByReference()
365-
val precise = WindowsNativeTrayLibrary.tray_get_notification_icons_position(xRef, yRef) != 0
366-
if (precise) {
367-
val screen = java.awt.Toolkit.getDefaultToolkit().screenSize
368-
val corner = com.kdroid.composetray.utils.convertPositionToCorner(xRef.value, yRef.value, screen.width, screen.height)
369-
TrayClickTracker.setClickPosition(instanceId, xRef.value, yRef.value, corner)
370-
}
387+
safeGetTrayPosition(instanceId)
371388

372389
if (running.get()) {
373390
// Execute callback in IO scope (like macOS)
@@ -418,6 +435,9 @@ internal class WindowsTrayManager(
418435
try {
419436
log("Calling tray_exit()")
420437
WindowsNativeTrayLibrary.tray_exit()
438+
} catch (e: Error) {
439+
log("Error in tray_exit() (memory access): ${e.message}")
440+
e.printStackTrace()
421441
} catch (e: Exception) {
422442
log("Error in tray_exit(): ${e.message}")
423443
e.printStackTrace()
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

winlib

0 commit comments

Comments
 (0)