22#include < cstring>
33#include < map>
44#include < memory>
5+ #include < optional>
6+ #include " ../global_registry.h"
57#include " ../tray_icon.h"
68#include " ../tray_icon_event.h"
79#include " string_utils_c.h"
@@ -22,12 +24,17 @@ static std::map<native_tray_icon_t,
2224 g_tray_icon_listeners;
2325static std::atomic<int > g_tray_icon_next_listener_id{1 };
2426
27+ // Global registry instance for managing TrayIcon object lifetimes
28+ static auto & g_tray_icons = globalRegistry<TrayIcon>();
29+
2530// TrayIcon C API Implementation
2631
2732native_tray_icon_t native_tray_icon_create (void ) {
2833 try {
2934 auto tray_icon = std::make_shared<TrayIcon>();
30- return static_cast <native_tray_icon_t >(tray_icon.get ());
35+ void * handle = tray_icon.get ();
36+ g_tray_icons[handle] = tray_icon; // Store shared_ptr to keep object alive
37+ return static_cast <native_tray_icon_t >(handle);
3138 } catch (...) {
3239 return nullptr ;
3340 }
@@ -39,7 +46,9 @@ native_tray_icon_t native_tray_icon_create_from_native(void* native_tray) {
3946
4047 try {
4148 auto tray_icon = std::make_shared<TrayIcon>(native_tray);
42- return static_cast <native_tray_icon_t >(tray_icon.get ());
49+ void * handle = tray_icon.get ();
50+ g_tray_icons[handle] = tray_icon; // Store shared_ptr to keep object alive
51+ return static_cast <native_tray_icon_t >(handle);
4352 } catch (...) {
4453 return nullptr ;
4554 }
@@ -49,14 +58,17 @@ void native_tray_icon_destroy(native_tray_icon_t tray_icon) {
4958 if (!tray_icon)
5059 return ;
5160
52- // Clean up listeners
53- auto it = g_tray_icon_listeners.find (tray_icon);
54- if (it != g_tray_icon_listeners.end ()) {
55- g_tray_icon_listeners.erase (it );
61+ // Remove event listeners first
62+ auto listeners_it = g_tray_icon_listeners.find (tray_icon);
63+ if (listeners_it != g_tray_icon_listeners.end ()) {
64+ g_tray_icon_listeners.erase (listeners_it );
5665 }
5766
58- // Note: The actual TrayIcon object is managed by shared_ptr
59- // This just removes our reference to it
67+ // Remove from global storage - this will release the shared_ptr
68+ auto tray_icon_it = g_tray_icons.find (tray_icon);
69+ if (tray_icon_it != g_tray_icons.end ()) {
70+ g_tray_icons.erase (tray_icon_it);
71+ }
6072}
6173
6274native_tray_icon_id_t native_tray_icon_get_id (native_tray_icon_t tray_icon) {
@@ -369,3 +381,19 @@ bool native_tray_icon_close_context_menu(native_tray_icon_t tray_icon) {
369381 return false ;
370382 }
371383}
384+
385+ // Implementation of cleanup function
386+ void cleanup_tray_icon_at_exit () {
387+ // Clear all event listeners first to prevent callbacks during cleanup
388+ g_tray_icon_listeners.clear ();
389+
390+ // Note: We intentionally do NOT clear g_tray_icons here
391+ // because they are now managed by function-local static pointers that
392+ // won't be destroyed during normal exit, preventing double-free issues.
393+ // The memory will be cleaned up by the OS when the process terminates.
394+ }
395+
396+ // Cleanup functions to ensure proper resource management
397+ void native_tray_icon_cleanup_all (void ) {
398+ cleanup_tray_icon_at_exit ();
399+ }
0 commit comments