Skip to content

Commit c880de1

Browse files
committed
Refactor tray icon event handling to use event listeners API
Replace legacy click callbacks with event listener system for tray icons. Add TrayIconClickedEvent, TrayIconRightClickedEvent, and TrayIconDoubleClickedEvent. Update C/C++ APIs and examples to use new event types and listener functions. Remove deprecated SetOnLeftClick/SetOnRightClick/SetOnDoubleClick methods.
1 parent f8bd02d commit c880de1

File tree

11 files changed

+738
-230
lines changed

11 files changed

+738
-230
lines changed

examples/tray_icon_c_example/main.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ void on_menu_item_clicked(const void* event, void* user_data) {
2828
}
2929
}
3030

31-
32-
33-
void on_tray_left_click(void* user_data) {
34-
printf("Tray icon left clicked!\n");
31+
void on_tray_clicked(const void* event, void* user_data) {
32+
const native_tray_icon_clicked_event_t* clicked_event = (const native_tray_icon_clicked_event_t*)event;
33+
printf("Tray icon clicked! ID=%ld, Button='%s'\n", clicked_event->tray_icon_id,
34+
clicked_event->button);
3535
}
3636

37-
void on_tray_right_click(void* user_data) {
38-
printf("Tray icon right clicked!\n");
37+
void on_tray_right_clicked(const void* event, void* user_data) {
38+
const native_tray_icon_right_clicked_event_t* right_clicked_event = (const native_tray_icon_right_clicked_event_t*)event;
39+
printf("Tray icon right clicked! ID=%ld\n", right_clicked_event->tray_icon_id);
3940
}
4041

41-
void on_tray_double_click(void* user_data) {
42-
printf("Tray icon double clicked!\n");
42+
void on_tray_double_clicked(const void* event, void* user_data) {
43+
const native_tray_icon_double_clicked_event_t* double_clicked_event = (const native_tray_icon_double_clicked_event_t*)event;
44+
printf("Tray icon double clicked! ID=%ld\n", double_clicked_event->tray_icon_id);
4345
}
4446

4547
void on_menu_opened(const void* event, void* user_data) {
@@ -161,10 +163,10 @@ int main() {
161163
// Set the context menu
162164
native_tray_icon_set_context_menu(tray_icon, menu);
163165

164-
// Set up tray icon event handlers
165-
native_tray_icon_set_on_left_click(tray_icon, on_tray_left_click, NULL);
166-
native_tray_icon_set_on_right_click(tray_icon, on_tray_right_click, NULL);
167-
native_tray_icon_set_on_double_click(tray_icon, on_tray_double_click, NULL);
166+
// Set up tray icon event listeners using new API
167+
native_tray_icon_add_listener(tray_icon, NATIVE_TRAY_ICON_EVENT_CLICKED, on_tray_clicked, NULL);
168+
native_tray_icon_add_listener(tray_icon, NATIVE_TRAY_ICON_EVENT_RIGHT_CLICKED, on_tray_right_clicked, NULL);
169+
native_tray_icon_add_listener(tray_icon, NATIVE_TRAY_ICON_EVENT_DOUBLE_CLICKED, on_tray_double_clicked, NULL);
168170

169171
// Show the tray icon
170172
if (native_tray_icon_show(tray_icon)) {
@@ -203,7 +205,7 @@ int main() {
203205
native_tray_icon_list_free(tray_list);
204206

205207
printf("\n=== Tray icon and menu are now active ===\n");
206-
printf("- Left click the tray icon to see left click message\n");
208+
printf("- Click the tray icon to see click message\n");
207209
printf("- Right click the tray icon to open context menu\n");
208210
printf("- Double click the tray icon to see double click message\n");
209211
printf("- Use menu items to interact with the application\n");

examples/tray_icon_example/main.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "../../src/tray_icon.h"
77
#include "../../src/tray_manager.h"
88
#include "../../src/menu.h"
9+
#include "../../src/tray_icon_event.h"
910

1011
#ifdef __APPLE__
1112
#import <Cocoa/Cocoa.h>
@@ -47,21 +48,24 @@ int main() {
4748
// Try to set a system icon (using a system-provided icon)
4849
trayIcon->SetIcon("NSImageNameStatusAvailable");
4950

50-
// Set up click handlers
51-
trayIcon->SetOnLeftClick([]() {
51+
// Set up event listeners
52+
trayIcon->AddListener<TrayIconClickedEvent>([](const TrayIconClickedEvent& event) {
5253
std::cout << "*** TRAY ICON LEFT CLICKED! ***" << std::endl;
5354
std::cout << "This is the left click handler working!" << std::endl;
55+
std::cout << "Tray icon ID: " << event.GetTrayIconId() << std::endl;
5456
});
5557

56-
trayIcon->SetOnRightClick([&trayIcon]() {
58+
trayIcon->AddListener<TrayIconRightClickedEvent>([](const TrayIconRightClickedEvent& event) {
5759
std::cout << "*** TRAY ICON RIGHT CLICKED! ***" << std::endl;
5860
std::cout << "This is the right click handler working!" << std::endl;
61+
std::cout << "Tray icon ID: " << event.GetTrayIconId() << std::endl;
5962
// Context menu will be shown automatically
6063
});
6164

62-
trayIcon->SetOnDoubleClick([]() {
65+
trayIcon->AddListener<TrayIconDoubleClickedEvent>([](const TrayIconDoubleClickedEvent& event) {
6366
std::cout << "*** TRAY ICON DOUBLE CLICKED! ***" << std::endl;
6467
std::cout << "This is the double click handler working!" << std::endl;
68+
std::cout << "Tray icon ID: " << event.GetTrayIconId() << std::endl;
6569
});
6670

6771
// Create context menu

examples/window_example/main.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ using nativeapi::MenuItemSubmenuClosedEvent;
1414
using nativeapi::MenuItemSubmenuOpenedEvent;
1515
using nativeapi::MenuItemType;
1616
using nativeapi::TrayIcon;
17+
using nativeapi::TrayIconClickedEvent;
18+
using nativeapi::TrayIconRightClickedEvent;
19+
using nativeapi::TrayIconDoubleClickedEvent;
1720
using nativeapi::TrayManager;
1821
using nativeapi::Window;
1922
using nativeapi::WindowManager;
@@ -264,23 +267,26 @@ int main() {
264267
// Set the context menu to the tray icon
265268
tray_icon.SetContextMenu(context_menu);
266269

267-
// Set up click handlers
268-
tray_icon.SetOnLeftClick([]() {
270+
// Set up event listeners
271+
tray_icon.AddListener<TrayIconClickedEvent>([](const TrayIconClickedEvent& event) {
269272
std::cout << "*** TRAY ICON LEFT CLICKED! ***" << std::endl;
270273
std::cout << "This is the left click handler working!" << std::endl;
274+
std::cout << "Tray icon ID: " << event.GetTrayIconId() << std::endl;
271275
});
272276

273-
tray_icon.SetOnRightClick([&tray_icon]() {
277+
tray_icon.AddListener<TrayIconRightClickedEvent>([](const TrayIconRightClickedEvent& event) {
274278
std::cout << "*** TRAY ICON RIGHT CLICKED! ***" << std::endl;
275279
std::cout << "This is the right click handler working!" << std::endl;
280+
std::cout << "Tray icon ID: " << event.GetTrayIconId() << std::endl;
276281
// Context menu will be shown automatically on right-click
277282
// But we can also manually show it if needed:
278283
// tray_icon.ShowContextMenu();
279284
});
280285

281-
tray_icon.SetOnDoubleClick([]() {
286+
tray_icon.AddListener<TrayIconDoubleClickedEvent>([](const TrayIconDoubleClickedEvent& event) {
282287
std::cout << "*** TRAY ICON DOUBLE CLICKED! ***" << std::endl;
283288
std::cout << "This is the double click handler working!" << std::endl;
289+
std::cout << "Tray icon ID: " << event.GetTrayIconId() << std::endl;
284290
});
285291
} else {
286292
std::cerr << "Failed to create tray." << std::endl;

include/nativeapi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "../src/keyboard_monitor.h"
1313
#include "../src/menu.h"
1414
#include "../src/tray_icon.h"
15+
#include "../src/tray_icon_event.h"
1516
#include "../src/tray_manager.h"
1617
#include "../src/window.h"
1718
#include "../src/window_event.h"

src/capi/tray_icon_c.cpp

Lines changed: 91 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
#include "tray_icon_c.h"
22
#include "../tray_icon.h"
3+
#include "../tray_icon_event.h"
34
#include <cstring>
45
#include <map>
56
#include <memory>
67

78
using namespace nativeapi;
89

9-
// Internal structure to manage C callbacks
10-
struct TrayIconCallbackData {
11-
native_tray_icon_left_click_callback_t left_click_callback;
12-
native_tray_icon_right_click_callback_t right_click_callback;
13-
native_tray_icon_double_click_callback_t double_click_callback;
14-
void* left_click_user_data;
15-
void* right_click_user_data;
16-
void* double_click_user_data;
10+
// Internal structure to manage C event listeners
11+
struct TrayIconListenerData {
12+
native_tray_icon_event_type_t event_type;
13+
native_tray_icon_event_callback_t callback;
14+
void* user_data;
15+
size_t listener_id;
1716
};
1817

19-
// Global map to store callback data
20-
static std::map<native_tray_icon_t, std::shared_ptr<TrayIconCallbackData>> g_tray_icon_callbacks;
18+
// Global maps to store listener data
19+
static std::map<native_tray_icon_t, std::vector<std::shared_ptr<TrayIconListenerData>>> g_tray_icon_listeners;
20+
static size_t g_next_listener_id = 1;
2121

2222
// TrayIcon C API Implementation
2323

@@ -43,11 +43,11 @@ native_tray_icon_t native_tray_icon_create_from_native(void* native_tray) {
4343

4444
void native_tray_icon_destroy(native_tray_icon_t tray_icon) {
4545
if (!tray_icon) return;
46-
47-
// Clean up callbacks
48-
auto it = g_tray_icon_callbacks.find(tray_icon);
49-
if (it != g_tray_icon_callbacks.end()) {
50-
g_tray_icon_callbacks.erase(it);
46+
47+
// Clean up listeners
48+
auto it = g_tray_icon_listeners.find(tray_icon);
49+
if (it != g_tray_icon_listeners.end()) {
50+
g_tray_icon_listeners.erase(it);
5151
}
5252

5353
// Note: The actual TrayIcon object is managed by shared_ptr
@@ -215,93 +215,95 @@ bool native_tray_icon_is_visible(native_tray_icon_t tray_icon) {
215215
}
216216
}
217217

218-
void native_tray_icon_set_on_left_click(native_tray_icon_t tray_icon, native_tray_icon_left_click_callback_t callback, void* user_data) {
219-
if (!tray_icon) return;
220-
221-
try {
222-
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
223-
224-
// Get or create callback data
225-
auto it = g_tray_icon_callbacks.find(tray_icon);
226-
if (it == g_tray_icon_callbacks.end()) {
227-
g_tray_icon_callbacks[tray_icon] = std::make_shared<TrayIconCallbackData>();
228-
}
229-
230-
auto callback_data = g_tray_icon_callbacks[tray_icon];
231-
callback_data->left_click_callback = callback;
232-
callback_data->left_click_user_data = user_data;
233-
234-
if (callback) {
235-
tray_icon_ptr->SetOnLeftClick([callback_data]() {
236-
if (callback_data && callback_data->left_click_callback) {
237-
callback_data->left_click_callback(callback_data->left_click_user_data);
238-
}
239-
});
240-
} else {
241-
tray_icon_ptr->SetOnLeftClick(nullptr);
242-
}
243-
} catch (...) {
244-
// Ignore exceptions
245-
}
246-
}
218+
int native_tray_icon_add_listener(native_tray_icon_t tray_icon, native_tray_icon_event_type_t event_type, native_tray_icon_event_callback_t callback, void* user_data) {
219+
if (!tray_icon || !callback) return -1;
247220

248-
void native_tray_icon_set_on_right_click(native_tray_icon_t tray_icon, native_tray_icon_right_click_callback_t callback, void* user_data) {
249-
if (!tray_icon) return;
250-
251221
try {
252222
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
253-
254-
// Get or create callback data
255-
auto it = g_tray_icon_callbacks.find(tray_icon);
256-
if (it == g_tray_icon_callbacks.end()) {
257-
g_tray_icon_callbacks[tray_icon] = std::make_shared<TrayIconCallbackData>();
258-
}
259-
260-
auto callback_data = g_tray_icon_callbacks[tray_icon];
261-
callback_data->right_click_callback = callback;
262-
callback_data->right_click_user_data = user_data;
263-
264-
if (callback) {
265-
tray_icon_ptr->SetOnRightClick([callback_data]() {
266-
if (callback_data && callback_data->right_click_callback) {
267-
callback_data->right_click_callback(callback_data->right_click_user_data);
268-
}
269-
});
270-
} else {
271-
tray_icon_ptr->SetOnRightClick(nullptr);
223+
224+
// Create listener data
225+
auto listener_data = std::make_shared<TrayIconListenerData>();
226+
listener_data->event_type = event_type;
227+
listener_data->callback = callback;
228+
listener_data->user_data = user_data;
229+
listener_data->listener_id = g_next_listener_id++;
230+
231+
// Get or create listener list for this tray icon
232+
auto& listeners = g_tray_icon_listeners[tray_icon];
233+
234+
// Add event listener based on type
235+
size_t cpp_listener_id = 0;
236+
switch (event_type) {
237+
case NATIVE_TRAY_ICON_EVENT_CLICKED:
238+
cpp_listener_id = tray_icon_ptr->AddListener<TrayIconClickedEvent>(
239+
[listener_data](const TrayIconClickedEvent& event) {
240+
if (listener_data && listener_data->callback) {
241+
native_tray_icon_clicked_event_t c_event;
242+
c_event.tray_icon_id = event.GetTrayIconId();
243+
strncpy(c_event.button, event.GetButton().c_str(), sizeof(c_event.button) - 1);
244+
c_event.button[sizeof(c_event.button) - 1] = '\0';
245+
listener_data->callback(&c_event, listener_data->user_data);
246+
}
247+
});
248+
break;
249+
250+
case NATIVE_TRAY_ICON_EVENT_RIGHT_CLICKED:
251+
cpp_listener_id = tray_icon_ptr->AddListener<TrayIconRightClickedEvent>(
252+
[listener_data](const TrayIconRightClickedEvent& event) {
253+
if (listener_data && listener_data->callback) {
254+
native_tray_icon_right_clicked_event_t c_event;
255+
c_event.tray_icon_id = event.GetTrayIconId();
256+
listener_data->callback(&c_event, listener_data->user_data);
257+
}
258+
});
259+
break;
260+
261+
case NATIVE_TRAY_ICON_EVENT_DOUBLE_CLICKED:
262+
cpp_listener_id = tray_icon_ptr->AddListener<TrayIconDoubleClickedEvent>(
263+
[listener_data](const TrayIconDoubleClickedEvent& event) {
264+
if (listener_data && listener_data->callback) {
265+
native_tray_icon_double_clicked_event_t c_event;
266+
c_event.tray_icon_id = event.GetTrayIconId();
267+
listener_data->callback(&c_event, listener_data->user_data);
268+
}
269+
});
270+
break;
271+
272+
default:
273+
return -1;
272274
}
275+
276+
// Store the C++ listener ID in our data structure
277+
listener_data->listener_id = cpp_listener_id;
278+
listeners.push_back(listener_data);
279+
280+
return static_cast<int>(cpp_listener_id);
273281
} catch (...) {
274-
// Ignore exceptions
282+
return -1;
275283
}
276284
}
277285

278-
void native_tray_icon_set_on_double_click(native_tray_icon_t tray_icon, native_tray_icon_double_click_callback_t callback, void* user_data) {
279-
if (!tray_icon) return;
280-
286+
bool native_tray_icon_remove_listener(native_tray_icon_t tray_icon, int listener_id) {
287+
if (!tray_icon) return false;
288+
281289
try {
282290
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
283-
284-
// Get or create callback data
285-
auto it = g_tray_icon_callbacks.find(tray_icon);
286-
if (it == g_tray_icon_callbacks.end()) {
287-
g_tray_icon_callbacks[tray_icon] = std::make_shared<TrayIconCallbackData>();
288-
}
289-
290-
auto callback_data = g_tray_icon_callbacks[tray_icon];
291-
callback_data->double_click_callback = callback;
292-
callback_data->double_click_user_data = user_data;
293-
294-
if (callback) {
295-
tray_icon_ptr->SetOnDoubleClick([callback_data]() {
296-
if (callback_data && callback_data->double_click_callback) {
297-
callback_data->double_click_callback(callback_data->double_click_user_data);
291+
292+
// Find and remove the listener
293+
auto it = g_tray_icon_listeners.find(tray_icon);
294+
if (it != g_tray_icon_listeners.end()) {
295+
auto& listeners = it->second;
296+
for (auto lit = listeners.begin(); lit != listeners.end(); ++lit) {
297+
if (static_cast<int>((*lit)->listener_id) == listener_id) {
298+
tray_icon_ptr->RemoveListener((*lit)->listener_id);
299+
listeners.erase(lit);
300+
return true;
298301
}
299-
});
300-
} else {
301-
tray_icon_ptr->SetOnDoubleClick(nullptr);
302+
}
302303
}
304+
return false;
303305
} catch (...) {
304-
// Ignore exceptions
306+
return false;
305307
}
306308
}
307309

0 commit comments

Comments
 (0)