Skip to content

Commit 9a62b35

Browse files
committed
Refactor menu ID generation to use IdAllocator
Replaces platform-specific atomic ID generators and registries with a unified IdAllocator for Menu and MenuItem objects across Linux, macOS, and Windows. Simplifies event emission by passing direct object pointers instead of registry lookups. This change improves consistency and maintainability of menu ID management.
1 parent bbada34 commit 9a62b35

File tree

6 files changed

+80
-112
lines changed

6 files changed

+80
-112
lines changed

src/menu.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
#include "foundation/event.h"
99
#include "foundation/event_emitter.h"
1010
#include "foundation/geometry.h"
11+
#include "foundation/id_allocator.h"
1112
#include "foundation/native_object_provider.h"
1213
#include "menu_event.h"
1314

1415
namespace nativeapi {
1516

1617
class Image;
1718

18-
typedef long MenuId;
19-
typedef long MenuItemId;
19+
typedef IdAllocator::IdType MenuId;
20+
typedef IdAllocator::IdType MenuItemId;
2021

2122
/**
2223
* @brief Enumeration of different menu item types.

src/menu_event.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
#include <string>
44

55
#include "foundation/event.h"
6+
#include "foundation/id_allocator.h"
67

78
namespace nativeapi {
89

910
// Forward declarations for menu types
10-
typedef long MenuId;
11-
typedef long MenuItemId;
11+
typedef IdAllocator::IdType MenuId;
12+
typedef IdAllocator::IdType MenuItemId;
1213

1314
/**
1415
* @brief Menu opened event.

src/platform/linux/menu_linux.cpp

Lines changed: 31 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,63 @@
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

1514
namespace 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
2617
static 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

4029
static 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

5037
static 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

6045
static 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

7154
static 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

10990
MenuItem::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

149126
MenuItem::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

174147
MenuItemType 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

333305
Menu::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

349317
Menu::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

363327
Menu::~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
}

src/platform/linux/tray_icon_linux.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
#include <unistd.h>
12
#include <iostream>
23
#include <optional>
34
#include <string>
4-
#include <unistd.h>
55

66
// Platform-specific includes for Linux
77
#ifdef __linux__
@@ -77,7 +77,8 @@ TrayIcon::TrayIcon(void* tray)
7777

7878
TrayIcon::~TrayIcon() {
7979
if (pimpl_->app_indicator_) {
80-
app_indicator_set_status(pimpl_->app_indicator_, APP_INDICATOR_STATUS_PASSIVE);
80+
app_indicator_set_status(pimpl_->app_indicator_,
81+
APP_INDICATOR_STATUS_PASSIVE);
8182
g_object_unref(pimpl_->app_indicator_);
8283
pimpl_->app_indicator_ = nullptr;
8384
}
@@ -97,52 +98,60 @@ void TrayIcon::SetIcon(std::shared_ptr<Image> image) {
9798

9899
// If no image provided, use default icon
99100
if (!image) {
100-
app_indicator_set_icon_full(pimpl_->app_indicator_, "application-default-icon", "Tray Icon");
101+
app_indicator_set_icon_full(pimpl_->app_indicator_,
102+
"application-default-icon", "Tray Icon");
101103
return;
102104
}
103105

104106
// Get the native GdkPixbuf object
105107
GdkPixbuf* pixbuf = static_cast<GdkPixbuf*>(image->GetNativeObject());
106108
if (!pixbuf) {
107-
app_indicator_set_icon_full(pimpl_->app_indicator_, "application-default-icon", "Tray Icon");
109+
app_indicator_set_icon_full(pimpl_->app_indicator_,
110+
"application-default-icon", "Tray Icon");
108111
return;
109112
}
110113

111114
// Create temporary PNG file
112115
char temp_path[] = "/tmp/tray_icon_XXXXXX";
113116
int fd = mkstemp(temp_path);
114117
if (fd == -1) {
115-
app_indicator_set_icon_full(pimpl_->app_indicator_, "application-default-icon", "Tray Icon");
118+
app_indicator_set_icon_full(pimpl_->app_indicator_,
119+
"application-default-icon", "Tray Icon");
116120
return;
117121
}
118122
close(fd);
119-
123+
120124
// Append .png extension
121125
std::string png_path(temp_path);
122126
png_path += ".png";
123-
127+
124128
// Save pixbuf to PNG file
125129
GError* error = nullptr;
126-
gboolean success = gdk_pixbuf_save(pixbuf, png_path.c_str(), "png", &error, nullptr);
127-
130+
gboolean success =
131+
gdk_pixbuf_save(pixbuf, png_path.c_str(), "png", &error, nullptr);
132+
128133
// Always clean up the original temporary file
129134
unlink(temp_path);
130-
135+
131136
if (error) {
132137
g_error_free(error);
133138
}
134-
139+
135140
if (success) {
136141
// Set the icon and schedule cleanup
137142
app_indicator_set_icon_full(pimpl_->app_indicator_, png_path.c_str(), "");
138-
g_timeout_add(5000, [](gpointer data) -> gboolean {
139-
unlink(static_cast<char*>(data));
140-
g_free(data);
141-
return FALSE; // Don't repeat
142-
}, g_strdup(png_path.c_str()));
143+
g_timeout_add(
144+
5000,
145+
[](gpointer data) -> gboolean {
146+
unlink(static_cast<char*>(data));
147+
g_free(data);
148+
return FALSE; // Don't repeat
149+
},
150+
g_strdup(png_path.c_str()));
143151
} else {
144152
// Fallback to default icon
145-
app_indicator_set_icon_full(pimpl_->app_indicator_, "application-default-icon", "Tray Icon");
153+
app_indicator_set_icon_full(pimpl_->app_indicator_,
154+
"application-default-icon", "Tray Icon");
146155
unlink(png_path.c_str());
147156
}
148157
}

0 commit comments

Comments
 (0)