Skip to content

Commit d05f2af

Browse files
committed
Refactor tray icon ID handling and accessors
Replaces direct access to the tray icon ID with a GetId() accessor method throughout the codebase. On macOS, tray icon IDs are now managed using Objective-C associated objects for better lifecycle management. Updates all usages to call GetId() instead of accessing the id member directly.
1 parent bbf6edd commit d05f2af

File tree

6 files changed

+63
-24
lines changed

6 files changed

+63
-24
lines changed

examples/window_example/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ int main() {
8282
"WVy6ENA/1l/"
8383
"XFg23zDhiRuqUXbBi1whJ9enqSQUWa7x3IcWHH0xDhLfUVYSpsWt6LMfZQwwX/"
8484
"wLVwWPG97osM9Wf7Df6GGOwnsP4BQFiPuOZ8wJUAAAAASUVORK5CYII=");
85-
std::cout << "Tray ID: " << tray_icon.id << std::endl;
85+
std::cout << "Tray ID: " << tray_icon.GetId() << std::endl;
8686
auto title = tray_icon.GetTitle();
8787
std::cout << "Tray Title: "
8888
<< (title.has_value() ? title.value() : "(no title)")

src/capi/tray_icon_c.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ native_tray_icon_id_t native_tray_icon_get_id(native_tray_icon_t tray_icon) {
7777

7878
try {
7979
auto tray_icon_ptr = static_cast<TrayIcon*>(tray_icon);
80-
return tray_icon_ptr->id;
80+
return tray_icon_ptr->GetId();
8181
} catch (...) {
8282
return -1;
8383
}

src/platform/linux/tray_icon_linux.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <iostream>
66
#include <optional>
77
#include <string>
8+
#include "../../foundation/id_allocator.h"
89
#include "../../menu.h"
910
#include "../../tray_icon.h"
1011
#include "../../tray_icon_event.h"
@@ -19,18 +20,20 @@ class TrayIcon::Impl {
1920
title_(std::nullopt),
2021
tooltip_(std::nullopt),
2122
context_menu_(nullptr),
22-
visible_(false) {}
23+
visible_(false) {
24+
id_ = IdAllocator::Allocate<TrayIcon>();
25+
}
2326

2427
AppIndicator* app_indicator_;
2528
std::shared_ptr<Menu>
2629
context_menu_; // Store menu shared_ptr to keep it alive
2730
std::optional<std::string> title_;
2831
std::optional<std::string> tooltip_;
2932
bool visible_;
33+
TrayIconId id_;
3034
};
3135

3236
TrayIcon::TrayIcon() : pimpl_(std::make_unique<Impl>(nullptr)) {
33-
id = -1;
3437

3538
#if HAS_GTK && HAS_AYATANA_APPINDICATOR
3639
// Create a unique ID for this tray icon
@@ -54,7 +57,6 @@ TrayIcon::TrayIcon() : pimpl_(std::make_unique<Impl>(nullptr)) {
5457

5558
TrayIcon::TrayIcon(void* tray)
5659
: pimpl_(std::make_unique<Impl>((AppIndicator*)tray)) {
57-
id = -1; // Will be set by TrayManager when created
5860
// Make the indicator visible by default
5961
if (pimpl_->app_indicator_) {
6062
pimpl_->visible_ = true;
@@ -67,6 +69,10 @@ TrayIcon::~TrayIcon() {
6769
}
6870
}
6971

72+
TrayIconId TrayIcon::GetId() {
73+
return pimpl_->id_;
74+
}
75+
7076
void TrayIcon::SetIcon(std::string icon) {
7177
if (!pimpl_->app_indicator_) {
7278
return;
@@ -88,7 +94,7 @@ void TrayIcon::SetIcon(std::string icon) {
8894
// Create a temporary file path
8995
const char* temp_dir = g_get_tmp_dir();
9096
std::string temp_path = std::string(temp_dir) +
91-
"/nativeapi_tray_icon_" + std::to_string(id) +
97+
"/nativeapi_tray_icon_" + std::to_string(GetId()) +
9298
".png";
9399

94100
// Write to file

src/platform/macos/tray_icon_macos.mm

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#import <Cocoa/Cocoa.h>
88
#import <Foundation/Foundation.h>
9+
#import <objc/runtime.h>
910

1011
// Note: This file assumes ARC (Automatic Reference Counting) is enabled
1112
// for proper memory management of Objective-C objects.
@@ -15,11 +16,14 @@
1516
typedef void (^TrayIconRightClickedBlock)(nativeapi::TrayIconId tray_icon_id);
1617
typedef void (^TrayIconDoubleClickedBlock)(nativeapi::TrayIconId tray_icon_id);
1718

19+
// Key for associated object to store tray icon ID
20+
static const void* kTrayIconIdKey = &kTrayIconIdKey;
21+
1822
@interface NSStatusBarButtonTarget : NSObject
19-
@property(nonatomic, assign) nativeapi::TrayIcon* trayIcon;
2023
@property(nonatomic, copy) TrayIconClickedBlock leftClickedBlock;
2124
@property(nonatomic, copy) TrayIconRightClickedBlock rightClickedBlock;
2225
@property(nonatomic, copy) TrayIconDoubleClickedBlock doubleClickedBlock;
26+
@property(nonatomic, assign) nativeapi::TrayIcon* trayIcon;
2327
- (void)statusItemClicked:(id)sender;
2428
@end
2529

@@ -33,6 +37,18 @@ - (void)statusItemClicked:(id)sender;
3337
ns_status_bar_button_target_(nil),
3438
menu_closed_listener_id_(0) {
3539
if (status_item) {
40+
// Check if ID already exists in the associated object
41+
NSNumber* allocatedId = objc_getAssociatedObject(status_item, kTrayIconIdKey);
42+
if (allocatedId) {
43+
// Reuse allocated ID
44+
id_ = [allocatedId longValue];
45+
} else {
46+
// Allocate new ID and store it
47+
id_ = IdAllocator::Allocate<TrayIcon>();
48+
objc_setAssociatedObject(status_item, kTrayIconIdKey, [NSNumber numberWithLong:id_],
49+
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
50+
}
51+
3652
// Create and set up button target
3753
ns_status_bar_button_target_ = [[NSStatusBarButtonTarget alloc] init];
3854
ns_status_bar_button_target_.trayIcon = nullptr; // Will be set later
@@ -71,6 +87,11 @@ - (void)statusItemClicked:(id)sender;
7187
}
7288
// Clear menu reference
7389
ns_status_item_.menu = nil;
90+
91+
// Clean up associated object
92+
objc_setAssociatedObject(ns_status_item_, kTrayIconIdKey, nil,
93+
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
94+
7495
[[NSStatusBar systemStatusBar] removeStatusItem:ns_status_item_];
7596
ns_status_item_ = nil;
7697
}
@@ -83,15 +104,15 @@ - (void)statusItemClicked:(id)sender;
83104

84105
NSStatusItem* ns_status_item_;
85106
NSStatusBarButtonTarget* ns_status_bar_button_target_;
107+
108+
TrayIconId id_;
86109
std::shared_ptr<Menu> context_menu_;
87110
size_t menu_closed_listener_id_;
88111
};
89112

90113
TrayIcon::TrayIcon() : TrayIcon(nullptr) {}
91114

92115
TrayIcon::TrayIcon(void* tray) {
93-
id = IdAllocator::Allocate<TrayIcon>();
94-
95116
NSStatusItem* status_item = nullptr;
96117

97118
if (tray == nullptr) {
@@ -143,6 +164,10 @@ - (void)statusItemClicked:(id)sender;
143164
}
144165
}
145166

167+
TrayIconId TrayIcon::GetId() {
168+
return pimpl_->id_;
169+
}
170+
146171
void TrayIcon::SetIcon(std::string icon) {
147172
if (!pimpl_->ns_status_item_ || !pimpl_->ns_status_item_.button) {
148173
return;
@@ -354,11 +379,11 @@ @implementation NSStatusBarButtonTarget
354379

355380
- (void)statusItemClicked:(id)sender {
356381
// Check if trayIcon is still valid before proceeding
357-
if (!_trayIcon)
382+
if (!self.trayIcon)
358383
return;
359384

360385
// Create a local reference to prevent race conditions
361-
nativeapi::TrayIcon* trayIcon = _trayIcon;
386+
nativeapi::TrayIcon* trayIcon = self.trayIcon;
362387
if (!trayIcon)
363388
return;
364389

@@ -372,17 +397,17 @@ - (void)statusItemClicked:(id)sender {
372397
(event.modifierFlags & NSEventModifierFlagControl))) {
373398
// Right click or Ctrl+Left click
374399
if (_rightClickedBlock) {
375-
_rightClickedBlock(trayIcon->id);
400+
_rightClickedBlock(trayIcon->GetId());
376401
}
377402
} else if (event.type == NSEventTypeLeftMouseUp) {
378403
// Check for double click
379404
if (event.clickCount == 2) {
380405
if (_doubleClickedBlock) {
381-
_doubleClickedBlock(trayIcon->id);
406+
_doubleClickedBlock(trayIcon->GetId());
382407
}
383408
} else {
384409
if (_leftClickedBlock) {
385-
_leftClickedBlock(trayIcon->id, "left");
410+
_leftClickedBlock(trayIcon->GetId(), "left");
386411
}
387412
}
388413
}

src/platform/windows/tray_icon_windows.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <string>
55

66
#include "../../foundation/geometry.h"
7+
#include "../../foundation/id_allocator.h"
78
#include "../../menu.h"
89
#include "../../tray_icon.h"
910
#include "../../tray_icon_event.h"
@@ -14,10 +15,13 @@ namespace nativeapi {
1415
// Private implementation class
1516
class TrayIcon::Impl {
1617
public:
17-
Impl() : hwnd_(nullptr), icon_id_(0), icon_handle_(nullptr) {}
18+
Impl() : hwnd_(nullptr), icon_id_(0), icon_handle_(nullptr) {
19+
id_ = IdAllocator::Allocate<TrayIcon>();
20+
}
1821

1922
Impl(HWND hwnd, UINT icon_id)
2023
: hwnd_(hwnd), icon_id_(icon_id), icon_handle_(nullptr) {
24+
id_ = IdAllocator::Allocate<TrayIcon>();
2125
// Initialize NOTIFYICONDATA structure
2226
ZeroMemory(&nid_, sizeof(NOTIFYICONDATAW));
2327
nid_.cbSize = sizeof(NOTIFYICONDATAW);
@@ -50,14 +54,14 @@ class TrayIcon::Impl {
5054
switch (lParam) {
5155
case WM_LBUTTONUP:
5256
try {
53-
tray_icon->EmitSync<TrayIconClickedEvent>(tray_icon->id, "left");
57+
tray_icon->EmitSync<TrayIconClickedEvent>(tray_icon->GetId(), "left");
5458
} catch (...) {
5559
// Protect against event emission exceptions
5660
}
5761
break;
5862
case WM_RBUTTONUP:
5963
try {
60-
tray_icon->EmitSync<TrayIconRightClickedEvent>(tray_icon->id);
64+
tray_icon->EmitSync<TrayIconRightClickedEvent>(tray_icon->GetId());
6165
} catch (...) {
6266
// Protect against event emission exceptions
6367
}
@@ -67,7 +71,7 @@ class TrayIcon::Impl {
6771
break;
6872
case WM_LBUTTONDBLCLK:
6973
try {
70-
tray_icon->EmitSync<TrayIconDoubleClickedEvent>(tray_icon->id);
74+
tray_icon->EmitSync<TrayIconDoubleClickedEvent>(tray_icon->GetId());
7175
} catch (...) {
7276
// Protect against event emission exceptions
7377
}
@@ -92,9 +96,10 @@ class TrayIcon::Impl {
9296
NOTIFYICONDATAW nid_;
9397
std::shared_ptr<Menu> context_menu_;
9498
HICON icon_handle_;
99+
TrayIconId id_;
95100
};
96101

97-
TrayIcon::TrayIcon() : id(-1), pimpl_(std::make_unique<Impl>()) {
102+
TrayIcon::TrayIcon() : pimpl_(std::make_unique<Impl>()) {
98103
// Create a hidden window for this tray icon
99104
HINSTANCE hInstance = GetModuleHandle(nullptr);
100105

@@ -128,14 +133,18 @@ TrayIcon::TrayIcon() : id(-1), pimpl_(std::make_unique<Impl>()) {
128133
}
129134
}
130135

131-
TrayIcon::TrayIcon(void* tray) : id(-1), pimpl_(std::make_unique<Impl>()) {
136+
TrayIcon::TrayIcon(void* tray) : pimpl_(std::make_unique<Impl>()) {
132137
// In a real implementation, you'd extract HWND and icon ID from the tray
133138
// parameter For now, this constructor is mainly used by TrayManager for
134139
// creating uninitialized icons
135140
}
136141

137142
TrayIcon::~TrayIcon() {}
138143

144+
TrayIconId TrayIcon::GetId() {
145+
return pimpl_->id_;
146+
}
147+
139148
void TrayIcon::SetIcon(std::string icon) {
140149
if (!pimpl_->hwnd_) {
141150
return;

src/tray_icon.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,11 @@ class TrayIcon : public EventEmitter, public NativeObjectProvider {
9292
virtual ~TrayIcon();
9393

9494
/**
95-
* @brief Unique identifier for this tray icon.
95+
* @brief Get the unique identifier for this tray icon.
9696
*
97-
* This ID is assigned by the TrayManager when the icon is created
98-
* and can be used to reference the icon in subsequent operations.
97+
* @return The unique identifier for this tray icon
9998
*/
100-
TrayIconId id;
99+
TrayIconId GetId();
101100

102101
/**
103102
* @brief Set the icon image for the tray icon.

0 commit comments

Comments
 (0)