Skip to content

Commit 94822e1

Browse files
committed
Add thread-safe global registry for shared object lifetimes
Introduce a thread-safe singleton Registry<T> for managing shared_ptr lifetimes of Menu, MenuItem, and TrayIcon objects. Replace legacy global maps with the new registry in C API implementations. Update example code to use new registry logic and ensure proper object destruction.
1 parent 24560cf commit 94822e1

File tree

9 files changed

+879
-566
lines changed

9 files changed

+879
-566
lines changed

examples/menu_c_example/main.c

Lines changed: 242 additions & 209 deletions
Large diffs are not rendered by default.

examples/tray_icon_c_example/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ int main() {
150150
native_menu_add_item(submenu, sub_item2);
151151

152152
// Create submenu item and add to main menu
153-
native_menu_item_t submenu_item =
154-
native_menu_item_create("More Options", NATIVE_MENU_ITEM_TYPE_SUBMENU);
153+
native_menu_item_t submenu_item = native_menu_item_create(
154+
"More Options", NATIVE_MENU_ITEM_TYPE_SUBMENU);
155155
if (submenu_item) {
156156
native_menu_item_set_submenu(submenu_item, submenu);
157157
native_menu_add_item(menu, submenu_item);

examples/window_c_example/main.c

Lines changed: 367 additions & 291 deletions
Large diffs are not rendered by default.

src/capi/app_runner_c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ static std::shared_ptr<Window> GetWindowFromHandle(
2222
// We need to get the shared_ptr from WindowManager
2323
auto* window_ptr = static_cast<Window*>(window_handle);
2424
WindowID window_id = window_ptr->GetId();
25-
25+
2626
// Retrieve the shared_ptr from WindowManager
2727
auto& manager = WindowManager::GetInstance();
2828
return manager.Get(window_id);

src/capi/menu_c.cpp

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@
1111

1212
using namespace nativeapi;
1313

14-
// Global registry instances for managing MenuItem and Menu object lifetimes
15-
static auto& g_menu_items = globalRegistry<MenuItem>();
16-
static auto& g_menus = globalRegistry<Menu>();
17-
1814
// Internal structures to manage event listeners
1915

2016
// Event listener data structures
@@ -154,7 +150,10 @@ native_menu_item_t native_menu_item_create(const char* text,
154150
try {
155151
auto item = std::make_shared<MenuItem>(text, convert_menu_item_type(type));
156152
void* handle = item.get();
157-
g_menu_items[handle] = item; // Store shared_ptr to keep object alive
153+
154+
// Store the shared_ptr in the registry to keep the object alive
155+
GlobalRegistry<MenuItem>().Register(handle, item);
156+
158157
return static_cast<native_menu_item_t>(handle);
159158
} catch (...) {
160159
return nullptr;
@@ -165,7 +164,10 @@ native_menu_item_t native_menu_item_create_separator(void) {
165164
try {
166165
auto item = std::make_shared<MenuItem>("", MenuItemType::Separator);
167166
void* handle = item.get();
168-
g_menu_items[handle] = item; // Store shared_ptr to keep object alive
167+
168+
// Store the shared_ptr in the registry to keep the object alive
169+
GlobalRegistry<MenuItem>().Register(handle, item);
170+
169171
return static_cast<native_menu_item_t>(handle);
170172
} catch (...) {
171173
return nullptr;
@@ -182,17 +184,18 @@ void native_menu_item_destroy(native_menu_item_t item) {
182184
g_menu_item_listeners.erase(listeners_it);
183185
}
184186

185-
// Remove from global storage - this will release the shared_ptr
186-
auto item_it = g_menu_items.find(item);
187-
if (item_it != g_menu_items.end()) {
188-
g_menu_items.erase(item_it);
189-
}
187+
// Unregister from registry - this will also destroy the object
188+
GlobalRegistry<MenuItem>().Unregister(item);
190189
}
191190

192191
native_menu_item_id_t native_menu_item_get_id(native_menu_item_t item) {
193192
if (!item)
194193
return -1;
195194

195+
// Verify the item exists in the registry
196+
if (!GlobalRegistry<MenuItem>().Contains(item))
197+
return -1;
198+
196199
try {
197200
auto menu_item = static_cast<MenuItem*>(item);
198201
return menu_item->id;
@@ -486,15 +489,14 @@ void native_menu_item_set_submenu(native_menu_item_t item,
486489

487490
try {
488491
// Verify item exists in global storage
489-
auto item_it = g_menu_items.find(item);
490-
if (item_it == g_menu_items.end())
492+
if (!GlobalRegistry<MenuItem>().Contains(item))
491493
return;
492494

493495
auto menu_item = static_cast<MenuItem*>(item);
494496
// Get the shared_ptr from global storage instead of creating a new one
495-
auto menu_it = g_menus.find(submenu);
496-
if (menu_it != g_menus.end()) {
497-
menu_item->SetSubmenu(menu_it->second);
497+
auto submenu_ptr = GlobalRegistry<Menu>().Get(submenu);
498+
if (submenu_ptr) {
499+
menu_item->SetSubmenu(submenu_ptr);
498500
}
499501
} catch (...) {
500502
// Ignore exceptions
@@ -652,7 +654,10 @@ native_menu_t native_menu_create(void) {
652654
try {
653655
auto menu = std::make_shared<Menu>();
654656
void* handle = menu.get();
655-
g_menus[handle] = menu; // Store shared_ptr to keep object alive
657+
658+
// Store the shared_ptr in the registry to keep the object alive
659+
GlobalRegistry<Menu>().Register(handle, menu);
660+
656661
return static_cast<native_menu_t>(handle);
657662
} catch (...) {
658663
return nullptr;
@@ -669,17 +674,18 @@ void native_menu_destroy(native_menu_t menu) {
669674
g_menu_listeners.erase(listeners_it);
670675
}
671676

672-
// Remove from global storage - this will release the shared_ptr
673-
auto menu_it = g_menus.find(menu);
674-
if (menu_it != g_menus.end()) {
675-
g_menus.erase(menu_it);
676-
}
677+
// Unregister from registry - this will also destroy the object
678+
GlobalRegistry<Menu>().Unregister(menu);
677679
}
678680

679681
native_menu_id_t native_menu_get_id(native_menu_t menu) {
680682
if (!menu)
681683
return -1;
682684

685+
// Verify the menu exists in the registry
686+
if (!GlobalRegistry<Menu>().Contains(menu))
687+
return -1;
688+
683689
try {
684690
auto menu_ptr = static_cast<Menu*>(menu);
685691
return menu_ptr->id;
@@ -694,15 +700,14 @@ void native_menu_add_item(native_menu_t menu, native_menu_item_t item) {
694700

695701
try {
696702
// Verify menu exists in global storage
697-
auto menu_it = g_menus.find(menu);
698-
if (menu_it == g_menus.end())
703+
if (!GlobalRegistry<Menu>().Contains(menu))
699704
return;
700705

701706
auto menu_ptr = static_cast<Menu*>(menu);
702707
// Get the shared_ptr from global storage instead of creating a new one
703-
auto item_it = g_menu_items.find(item);
704-
if (item_it != g_menu_items.end()) {
705-
menu_ptr->AddItem(item_it->second);
708+
auto item_ptr = GlobalRegistry<MenuItem>().Get(item);
709+
if (item_ptr) {
710+
menu_ptr->AddItem(item_ptr);
706711
}
707712
} catch (...) {
708713
// Ignore exceptions
@@ -717,15 +722,14 @@ void native_menu_insert_item(native_menu_t menu,
717722

718723
try {
719724
// Verify menu exists in global storage
720-
auto menu_it = g_menus.find(menu);
721-
if (menu_it == g_menus.end())
725+
if (!GlobalRegistry<Menu>().Contains(menu))
722726
return;
723727

724728
auto menu_ptr = static_cast<Menu*>(menu);
725729
// Get the shared_ptr from global storage instead of creating a new one
726-
auto item_it = g_menu_items.find(item);
727-
if (item_it != g_menu_items.end()) {
728-
menu_ptr->InsertItem(index, item_it->second);
730+
auto item_ptr = GlobalRegistry<MenuItem>().Get(item);
731+
if (item_ptr) {
732+
menu_ptr->InsertItem(index, item_ptr);
729733
}
730734
} catch (...) {
731735
// Ignore exceptions
@@ -738,15 +742,14 @@ bool native_menu_remove_item(native_menu_t menu, native_menu_item_t item) {
738742

739743
try {
740744
// Verify menu exists in global storage
741-
auto menu_it = g_menus.find(menu);
742-
if (menu_it == g_menus.end())
745+
if (!GlobalRegistry<Menu>().Contains(menu))
743746
return false;
744747

745748
auto menu_ptr = static_cast<Menu*>(menu);
746749
// Get the shared_ptr from global storage instead of creating a new one
747-
auto item_it = g_menu_items.find(item);
748-
if (item_it != g_menu_items.end()) {
749-
return menu_ptr->RemoveItem(item_it->second);
750+
auto item_ptr = GlobalRegistry<MenuItem>().Get(item);
751+
if (item_ptr) {
752+
return menu_ptr->RemoveItem(item_ptr);
750753
}
751754
return false;
752755
} catch (...) {

src/capi/tray_icon_c.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ static std::map<native_tray_icon_t,
2525
g_tray_icon_listeners;
2626
static std::atomic<int> g_tray_icon_next_listener_id{1};
2727

28-
// Global registry instance for managing TrayIcon object lifetimes
29-
static auto& g_tray_icons = globalRegistry<TrayIcon>();
30-
3128
// TrayIcon C API Implementation
3229

3330
native_tray_icon_t native_tray_icon_create(void) {
3431
try {
3532
auto tray_icon = std::make_shared<TrayIcon>();
3633
void* handle = tray_icon.get();
37-
g_tray_icons[handle] = tray_icon; // Store shared_ptr to keep object alive
34+
35+
// Store the shared_ptr in the registry to keep the object alive
36+
GlobalRegistry<TrayIcon>().Register(handle, tray_icon);
37+
3838
return static_cast<native_tray_icon_t>(handle);
3939
} catch (...) {
4040
return nullptr;
@@ -48,7 +48,10 @@ native_tray_icon_t native_tray_icon_create_from_native(void* native_tray) {
4848
try {
4949
auto tray_icon = std::make_shared<TrayIcon>(native_tray);
5050
void* handle = tray_icon.get();
51-
g_tray_icons[handle] = tray_icon; // Store shared_ptr to keep object alive
51+
52+
// Store the shared_ptr in the registry to keep the object alive
53+
GlobalRegistry<TrayIcon>().Register(handle, tray_icon);
54+
5255
return static_cast<native_tray_icon_t>(handle);
5356
} catch (...) {
5457
return nullptr;
@@ -65,17 +68,18 @@ void native_tray_icon_destroy(native_tray_icon_t tray_icon) {
6568
g_tray_icon_listeners.erase(listeners_it);
6669
}
6770

68-
// Remove from global storage - this will release the shared_ptr
69-
auto tray_icon_it = g_tray_icons.find(tray_icon);
70-
if (tray_icon_it != g_tray_icons.end()) {
71-
g_tray_icons.erase(tray_icon_it);
72-
}
71+
// Unregister from registry - this will also destroy the object
72+
GlobalRegistry<TrayIcon>().Unregister(tray_icon);
7373
}
7474

7575
native_tray_icon_id_t native_tray_icon_get_id(native_tray_icon_t tray_icon) {
7676
if (!tray_icon)
7777
return -1;
7878

79+
// Verify the tray icon exists in the registry
80+
if (!GlobalRegistry<TrayIcon>().Contains(tray_icon))
81+
return -1;
82+
7983
try {
8084
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
8185
return tray_icon_ptr->GetId();
@@ -89,6 +93,10 @@ void native_tray_icon_set_icon(native_tray_icon_t tray_icon,
8993
if (!tray_icon)
9094
return;
9195

96+
// Verify the tray icon exists in the registry
97+
if (!GlobalRegistry<TrayIcon>().Contains(tray_icon))
98+
return;
99+
92100
try {
93101
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
94102
if (image) {
@@ -278,6 +286,10 @@ int native_tray_icon_add_listener(native_tray_icon_t tray_icon,
278286
if (!tray_icon || !callback)
279287
return -1;
280288

289+
// Verify the tray icon exists in the registry
290+
if (!GlobalRegistry<TrayIcon>().Contains(tray_icon))
291+
return -1;
292+
281293
try {
282294
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
283295

@@ -350,6 +362,10 @@ bool native_tray_icon_remove_listener(native_tray_icon_t tray_icon,
350362
if (!tray_icon)
351363
return false;
352364

365+
// Verify the tray icon exists in the registry
366+
if (!GlobalRegistry<TrayIcon>().Contains(tray_icon))
367+
return false;
368+
353369
try {
354370
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
355371

0 commit comments

Comments
 (0)