11#include < gtk/gtk.h>
22#include < algorithm>
3- #include < atomic>
43#include < cctype>
54#include < iostream>
65#include < memory>
76#include < optional>
87#include < string>
9- #include < unordered_map>
108#include < vector>
9+ #include " ../../foundation/id_allocator.h"
1110#include " ../../image.h"
1211#include " ../../menu.h"
1312#include " ../../menu_event.h"
1413
1514namespace nativeapi {
1615
17- // Global ID generators
18- static std::atomic<MenuItemId> g_next_menu_item_id{1 };
19- static std::atomic<MenuId> g_next_menu_id{1 };
20-
21- // Global registry to map native objects to C++ objects for event emission
22- static std::unordered_map<MenuItemId, MenuItem*> g_menu_item_registry;
23- static std::unordered_map<MenuId, Menu*> g_menu_registry;
24-
2516// GTK signal handlers → Event emission
2617static void OnGtkMenuItemActivate (GtkMenuItem* /* item*/ , gpointer user_data) {
27- MenuItemId item_id = static_cast <MenuItemId>(GPOINTER_TO_SIZE (user_data));
28- auto it = g_menu_item_registry.find (item_id);
29- if (it == g_menu_item_registry.end ()) {
18+ MenuItem* menu_item = static_cast <MenuItem*>(user_data);
19+ if (!menu_item) {
3020 return ;
3121 }
32- MenuItem* menu_item = it->second ;
3322 std::string text = " " ;
3423 if (auto label = menu_item->GetLabel (); label.has_value ()) {
3524 text = *label;
3625 }
37- menu_item->EmitSync (MenuItemClickedEvent (item_id , text));
26+ menu_item->EmitSync (MenuItemClickedEvent (menu_item-> id , text));
3827}
3928
4029static void OnGtkMenuShow (GtkWidget* /* menu*/ , gpointer user_data) {
41- MenuId menu_id = static_cast <MenuId>(GPOINTER_TO_SIZE (user_data));
42- auto it = g_menu_registry.find (menu_id);
43- if (it == g_menu_registry.end ()) {
30+ Menu* menu_obj = static_cast <Menu*>(user_data);
31+ if (!menu_obj) {
4432 return ;
4533 }
46- Menu* menu_obj = it->second ;
47- menu_obj->EmitSync (MenuOpenedEvent (menu_id));
34+ menu_obj->EmitSync (MenuOpenedEvent (menu_obj->id ));
4835}
4936
5037static void OnGtkMenuHide (GtkWidget* /* menu*/ , gpointer user_data) {
51- MenuId menu_id = static_cast <MenuId>(GPOINTER_TO_SIZE (user_data));
52- auto it = g_menu_registry.find (menu_id);
53- if (it == g_menu_registry.end ()) {
38+ Menu* menu_obj = static_cast <Menu*>(user_data);
39+ if (!menu_obj) {
5440 return ;
5541 }
56- Menu* menu_obj = it->second ;
57- menu_obj->EmitSync (MenuClosedEvent (menu_id));
42+ menu_obj->EmitSync (MenuClosedEvent (menu_obj->id ));
5843}
5944
6045static void OnGtkSubmenuShow (GtkWidget* /* submenu*/ , gpointer user_data) {
61- MenuItemId item_id = static_cast <MenuItemId>(GPOINTER_TO_SIZE (user_data));
62- auto it = g_menu_item_registry.find (item_id);
63- if (it == g_menu_item_registry.end ()) {
46+ MenuItem* menu_item = static_cast <MenuItem*>(user_data);
47+ if (!menu_item) {
6448 return ;
6549 }
66- MenuItem* menu_item = it->second ;
6750 // Emit submenu opened on the item
68- menu_item->EmitSync (MenuItemSubmenuOpenedEvent (item_id ));
51+ menu_item->EmitSync (MenuItemSubmenuOpenedEvent (menu_item-> id ));
6952}
7053
7154static void OnGtkSubmenuHide (GtkWidget* /* submenu*/ , gpointer user_data) {
72- MenuItemId item_id = static_cast <MenuItemId>(GPOINTER_TO_SIZE (user_data));
73- auto it = g_menu_item_registry.find (item_id);
74- if (it == g_menu_item_registry.end ()) {
55+ MenuItem* menu_item = static_cast <MenuItem*>(user_data);
56+ if (!menu_item) {
7557 return ;
7658 }
77- MenuItem* menu_item = it->second ;
7859 // Emit submenu closed on the item
79- menu_item->EmitSync (MenuItemSubmenuClosedEvent (item_id ));
60+ menu_item->EmitSync (MenuItemSubmenuClosedEvent (menu_item-> id ));
8061}
8162
8263// Private implementation class for MenuItem
@@ -107,7 +88,7 @@ class MenuItem::Impl {
10788};
10889
10990MenuItem::MenuItem (const std::string& text, MenuItemType type)
110- : id(g_next_menu_item_id++ ) {
91+ : id(IdAllocator::Allocate<MenuItem>() ) {
11192 GtkWidget* gtk_item = nullptr ;
11293
11394 switch (type) {
@@ -135,19 +116,15 @@ MenuItem::MenuItem(const std::string& text, MenuItemType type)
135116 pimpl_->title_ .reset ();
136117 }
137118
138- // Register the MenuItem for event emission
139- g_menu_item_registry[id] = this ;
140-
141119 // Connect activation signal for click events (except separators)
142120 if (gtk_item && type != MenuItemType::Separator) {
143121 g_signal_connect (G_OBJECT (gtk_item), " activate" ,
144- G_CALLBACK (OnGtkMenuItemActivate),
145- GSIZE_TO_POINTER (static_cast <gsize>(id)));
122+ G_CALLBACK (OnGtkMenuItemActivate), this );
146123 }
147124}
148125
149126MenuItem::MenuItem (void * menu_item)
150- : id(g_next_menu_item_id++ ),
127+ : id(IdAllocator::Allocate<MenuItem>() ),
151128 pimpl_(new Impl((GtkWidget*)menu_item, MenuItemType::Normal)) {
152129 if (pimpl_->gtk_menu_item_ && pimpl_->type_ != MenuItemType::Separator) {
153130 const char * label =
@@ -158,18 +135,14 @@ MenuItem::MenuItem(void* menu_item)
158135 pimpl_->title_ .reset ();
159136 }
160137 }
161- g_menu_item_registry[id] = this ;
162138
163139 if (pimpl_->gtk_menu_item_ ) {
164140 g_signal_connect (G_OBJECT (pimpl_->gtk_menu_item_ ), " activate" ,
165- G_CALLBACK (OnGtkMenuItemActivate),
166- GSIZE_TO_POINTER (static_cast <gsize>(id)));
141+ G_CALLBACK (OnGtkMenuItemActivate), this );
167142 }
168143}
169144
170- MenuItem::~MenuItem () {
171- g_menu_item_registry.erase (id);
172- }
145+ MenuItem::~MenuItem () {}
173146
174147MenuItemType MenuItem::GetType () const {
175148 return pimpl_->type_ ;
@@ -281,15 +254,14 @@ void MenuItem::SetSubmenu(std::shared_ptr<Menu> submenu) {
281254 gtk_menu_item_set_submenu (GTK_MENU_ITEM (pimpl_->gtk_menu_item_ ),
282255 (GtkWidget*)submenu->GetNativeObject ());
283256
284- // Emit submenu open/close events on the parent item when submenu shows/hides
257+ // Emit submenu open/close events on the parent item when submenu
258+ // shows/hides
285259 GtkWidget* submenu_widget = (GtkWidget*)submenu->GetNativeObject ();
286260 if (submenu_widget) {
287261 g_signal_connect (G_OBJECT (submenu_widget), " show" ,
288- G_CALLBACK (OnGtkSubmenuShow),
289- GSIZE_TO_POINTER (static_cast <gsize>(id)));
262+ G_CALLBACK (OnGtkSubmenuShow), this );
290263 g_signal_connect (G_OBJECT (submenu_widget), " hide" ,
291- G_CALLBACK (OnGtkSubmenuHide),
292- GSIZE_TO_POINTER (static_cast <gsize>(id)));
264+ G_CALLBACK (OnGtkSubmenuHide), this );
293265 }
294266 }
295267}
@@ -331,38 +303,28 @@ class Menu::Impl {
331303};
332304
333305Menu::Menu ()
334- : id(g_next_menu_id++ ),
306+ : id(IdAllocator::Allocate<Menu>() ),
335307 pimpl_ (std::unique_ptr<Impl>(new Impl(gtk_menu_new()))) {
336- g_menu_registry[id] = this ;
337-
338308 // Connect menu show/hide to emit open/close events
339309 if (pimpl_->gtk_menu_ ) {
340310 g_signal_connect (G_OBJECT (pimpl_->gtk_menu_ ), " show" ,
341- G_CALLBACK (OnGtkMenuShow),
342- GSIZE_TO_POINTER (static_cast <gsize>(id)));
311+ G_CALLBACK (OnGtkMenuShow), this );
343312 g_signal_connect (G_OBJECT (pimpl_->gtk_menu_ ), " hide" ,
344- G_CALLBACK (OnGtkMenuHide),
345- GSIZE_TO_POINTER (static_cast <gsize>(id)));
313+ G_CALLBACK (OnGtkMenuHide), this );
346314 }
347315}
348316
349317Menu::Menu (void * menu)
350- : id(g_next_menu_id++), pimpl_(new Impl((GtkWidget*)menu)) {
351- g_menu_registry[id] = this ;
352-
318+ : id(IdAllocator::Allocate<Menu>()), pimpl_(new Impl((GtkWidget*)menu)) {
353319 if (pimpl_->gtk_menu_ ) {
354320 g_signal_connect (G_OBJECT (pimpl_->gtk_menu_ ), " show" ,
355- G_CALLBACK (OnGtkMenuShow),
356- GSIZE_TO_POINTER (static_cast <gsize>(id)));
321+ G_CALLBACK (OnGtkMenuShow), this );
357322 g_signal_connect (G_OBJECT (pimpl_->gtk_menu_ ), " hide" ,
358- G_CALLBACK (OnGtkMenuHide),
359- GSIZE_TO_POINTER (static_cast <gsize>(id)));
323+ G_CALLBACK (OnGtkMenuHide), this );
360324 }
361325}
362326
363327Menu::~Menu () {
364- // Unregister from event registry
365- g_menu_registry.erase (id);
366328 if (pimpl_->gtk_menu_ ) {
367329 g_object_unref (pimpl_->gtk_menu_ );
368330 }
0 commit comments