@@ -73,6 +73,11 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
7373
7474 public let nativeHandle : native_menu_item_t
7575 private var eventListeners : [ Int32 : Any ] = [ : ]
76+
77+ // Static map to track instances by their native handle address
78+ // Note: Access is protected by instancesLock
79+ private nonisolated ( unsafe) static var instances : [ Int : MenuItem ] = [ : ]
80+ private static let instancesLock = NSLock ( )
7681
7782 /// Unique identifier for this menu item.
7883 public var id : Int {
@@ -92,6 +97,12 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
9297 self . nativeHandle = nativeItem
9398 super. init ( )
9499
100+ // Store instance in static map using handle address as key
101+ let handleAddress = Int ( bitPattern: nativeHandle)
102+ MenuItem . instancesLock. lock ( )
103+ MenuItem . instances [ handleAddress] = self
104+ MenuItem . instancesLock. unlock ( )
105+
95106 // Register event listeners
96107 setupEventListeners ( )
97108 }
@@ -108,6 +119,13 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
108119 internal init ( nativeItem: native_menu_item_t ) {
109120 self . nativeHandle = nativeItem
110121 super. init ( )
122+
123+ // Store instance in static map using handle address as key
124+ let handleAddress = Int ( bitPattern: nativeHandle)
125+ MenuItem . instancesLock. lock ( )
126+ MenuItem . instances [ handleAddress] = self
127+ MenuItem . instancesLock. unlock ( )
128+
111129 setupEventListeners ( )
112130 }
113131
@@ -122,7 +140,7 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
122140 nativeHandle,
123141 NATIVE_MENU_ITEM_EVENT_CLICKED,
124142 MenuItem . clickedCallback,
125- Unmanaged . passUnretained ( self ) . toOpaque ( )
143+ nativeHandle
126144 )
127145 if clickedListenerId >= 0 {
128146 eventListeners [ clickedListenerId] = " clicked "
@@ -133,7 +151,7 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
133151 nativeHandle,
134152 NATIVE_MENU_ITEM_EVENT_SUBMENU_OPENED,
135153 MenuItem . submenuOpenedCallback,
136- Unmanaged . passUnretained ( self ) . toOpaque ( )
154+ nativeHandle
137155 )
138156 if submenuOpenedListenerId >= 0 {
139157 eventListeners [ submenuOpenedListenerId] = " submenuOpened "
@@ -144,7 +162,7 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
144162 nativeHandle,
145163 NATIVE_MENU_ITEM_EVENT_SUBMENU_CLOSED,
146164 MenuItem . submenuClosedCallback,
147- Unmanaged . passUnretained ( self ) . toOpaque ( )
165+ nativeHandle
148166 )
149167 if submenuClosedListenerId >= 0 {
150168 eventListeners [ submenuClosedListenerId] = " submenuClosed "
@@ -154,23 +172,47 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
154172 // Static callback functions for native events
155173 private static let clickedCallback : native_menu_item_event_callback_t = { eventPtr, userDataPtr in
156174 guard let userDataPtr = userDataPtr else { return }
157- let menuItem = Unmanaged < MenuItem > . fromOpaque ( userDataPtr) . takeUnretainedValue ( )
158- print ( " Menu item clicked: \( menuItem. id) " )
159- menuItem. emitSync ( MenuItemClickedEvent ( menuItem. id) )
175+ let handleAddress = Int ( bitPattern: userDataPtr)
176+
177+ instancesLock. lock ( )
178+ guard let instance = instances [ handleAddress] else {
179+ instancesLock. unlock ( )
180+ return
181+ }
182+ instancesLock. unlock ( )
183+
184+ print ( " Menu item clicked: \( instance. id) " )
185+ instance. emitSync ( MenuItemClickedEvent ( instance. id) )
160186 }
161187
162188 private static let submenuOpenedCallback : native_menu_item_event_callback_t = { eventPtr, userDataPtr in
163189 guard let userDataPtr = userDataPtr else { return }
164- let menuItem = Unmanaged < MenuItem > . fromOpaque ( userDataPtr) . takeUnretainedValue ( )
165- print ( " Menu item submenu opened: \( menuItem. id) " )
166- menuItem. emitSync ( MenuItemSubmenuOpenedEvent ( menuItem. id) )
190+ let handleAddress = Int ( bitPattern: userDataPtr)
191+
192+ instancesLock. lock ( )
193+ guard let instance = instances [ handleAddress] else {
194+ instancesLock. unlock ( )
195+ return
196+ }
197+ instancesLock. unlock ( )
198+
199+ print ( " Menu item submenu opened: \( instance. id) " )
200+ instance. emitSync ( MenuItemSubmenuOpenedEvent ( instance. id) )
167201 }
168202
169203 private static let submenuClosedCallback : native_menu_item_event_callback_t = { eventPtr, userDataPtr in
170204 guard let userDataPtr = userDataPtr else { return }
171- let menuItem = Unmanaged < MenuItem > . fromOpaque ( userDataPtr) . takeUnretainedValue ( )
172- print ( " Menu item submenu closed: \( menuItem. id) " )
173- menuItem. emitSync ( MenuItemSubmenuClosedEvent ( menuItem. id) )
205+ let handleAddress = Int ( bitPattern: userDataPtr)
206+
207+ instancesLock. lock ( )
208+ guard let instance = instances [ handleAddress] else {
209+ instancesLock. unlock ( )
210+ return
211+ }
212+ instancesLock. unlock ( )
213+
214+ print ( " Menu item submenu closed: \( instance. id) " )
215+ instance. emitSync ( MenuItemSubmenuClosedEvent ( instance. id) )
174216 }
175217
176218 // MARK: - Properties
@@ -313,6 +355,12 @@ public class MenuItem: BaseEventEmitter, NativeHandleWrapper {
313355 }
314356
315357 public func dispose( ) {
358+ // Remove instance from static map
359+ let handleAddress = Int ( bitPattern: nativeHandle)
360+ MenuItem . instancesLock. lock ( )
361+ MenuItem . instances. removeValue ( forKey: handleAddress)
362+ MenuItem . instancesLock. unlock ( )
363+
316364 // Remove native listeners
317365 for (listenerId, _) in eventListeners {
318366 native_menu_item_remove_listener ( nativeHandle, listenerId)
@@ -335,6 +383,11 @@ public class Menu: BaseEventEmitter, NativeHandleWrapper {
335383
336384 public let nativeHandle : native_menu_t
337385 private var eventListeners : [ Int32 : Any ] = [ : ]
386+
387+ // Static map to track instances by their native handle address
388+ // Note: Access is protected by instancesLock
389+ private nonisolated ( unsafe) static var instances : [ Int : Menu ] = [ : ]
390+ private static let instancesLock = NSLock ( )
338391
339392 /// Unique identifier for this menu.
340393 public var id : Int {
@@ -350,12 +403,26 @@ public class Menu: BaseEventEmitter, NativeHandleWrapper {
350403 }
351404 self . nativeHandle = nativeMenu
352405 super. init ( )
406+
407+ // Store instance in static map using handle address as key
408+ let handleAddress = Int ( bitPattern: nativeHandle)
409+ Menu . instancesLock. lock ( )
410+ Menu . instances [ handleAddress] = self
411+ Menu . instancesLock. unlock ( )
412+
353413 setupEventListeners ( )
354414 }
355415
356416 internal init ( nativeMenu: native_menu_t ) {
357417 self . nativeHandle = nativeMenu
358418 super. init ( )
419+
420+ // Store instance in static map using handle address as key
421+ let handleAddress = Int ( bitPattern: nativeHandle)
422+ Menu . instancesLock. lock ( )
423+ Menu . instances [ handleAddress] = self
424+ Menu . instancesLock. unlock ( )
425+
359426 setupEventListeners ( )
360427 }
361428
@@ -370,7 +437,7 @@ public class Menu: BaseEventEmitter, NativeHandleWrapper {
370437 nativeHandle,
371438 NATIVE_MENU_EVENT_OPENED,
372439 Menu . openedCallback,
373- Unmanaged . passUnretained ( self ) . toOpaque ( )
440+ nativeHandle
374441 )
375442 if openedListenerId >= 0 {
376443 eventListeners [ openedListenerId] = " opened "
@@ -381,7 +448,7 @@ public class Menu: BaseEventEmitter, NativeHandleWrapper {
381448 nativeHandle,
382449 NATIVE_MENU_EVENT_CLOSED,
383450 Menu . closedCallback,
384- Unmanaged . passUnretained ( self ) . toOpaque ( )
451+ nativeHandle
385452 )
386453 if closedListenerId >= 0 {
387454 eventListeners [ closedListenerId] = " closed "
@@ -391,16 +458,32 @@ public class Menu: BaseEventEmitter, NativeHandleWrapper {
391458 // Static callback functions for native events
392459 private static let openedCallback : native_menu_event_callback_t = { eventPtr, userDataPtr in
393460 guard let userDataPtr = userDataPtr else { return }
394- let menu = Unmanaged < Menu > . fromOpaque ( userDataPtr) . takeUnretainedValue ( )
395- print ( " Menu opened: \( menu. id) " )
396- menu. emitSync ( MenuOpenedEvent ( menu. id) )
461+ let handleAddress = Int ( bitPattern: userDataPtr)
462+
463+ instancesLock. lock ( )
464+ guard let instance = instances [ handleAddress] else {
465+ instancesLock. unlock ( )
466+ return
467+ }
468+ instancesLock. unlock ( )
469+
470+ print ( " Menu opened: \( instance. id) " )
471+ instance. emitSync ( MenuOpenedEvent ( instance. id) )
397472 }
398473
399474 private static let closedCallback : native_menu_event_callback_t = { eventPtr, userDataPtr in
400475 guard let userDataPtr = userDataPtr else { return }
401- let menu = Unmanaged < Menu > . fromOpaque ( userDataPtr) . takeUnretainedValue ( )
402- print ( " Menu closed: \( menu. id) " )
403- menu. emitSync ( MenuClosedEvent ( menu. id) )
476+ let handleAddress = Int ( bitPattern: userDataPtr)
477+
478+ instancesLock. lock ( )
479+ guard let instance = instances [ handleAddress] else {
480+ instancesLock. unlock ( )
481+ return
482+ }
483+ instancesLock. unlock ( )
484+
485+ print ( " Menu closed: \( instance. id) " )
486+ instance. emitSync ( MenuClosedEvent ( instance. id) )
404487 }
405488
406489 // MARK: - Menu Item Management
@@ -476,6 +559,12 @@ public class Menu: BaseEventEmitter, NativeHandleWrapper {
476559 }
477560
478561 public func dispose( ) {
562+ // Remove instance from static map
563+ let handleAddress = Int ( bitPattern: nativeHandle)
564+ Menu . instancesLock. lock ( )
565+ Menu . instances. removeValue ( forKey: handleAddress)
566+ Menu . instancesLock. unlock ( )
567+
479568 // Remove native listeners
480569 for (listenerId, _) in eventListeners {
481570 native_menu_remove_listener ( nativeHandle, listenerId)
0 commit comments