Skip to content

Commit df8a6c4

Browse files
committed
Fix context menu listener management in TrayIcon
Ensures previous menu closed listeners are removed before adding new ones and tracks listener IDs to prevent leaks. This improves resource management and avoids potential issues when changing the tray icon's context menu.
1 parent a8ffc6d commit df8a6c4

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

src/platform/macos/tray_icon_macos.mm

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ - (void)statusItemClicked:(id)sender;
2727
// Private implementation class
2828
class TrayIcon::Impl {
2929
public:
30-
Impl() : ns_status_item_(nil), delegate_(nil) {}
30+
Impl() : ns_status_item_(nil), delegate_(nil), menu_closed_listener_id_(0) {}
3131

32-
Impl(NSStatusItem* status_item) : ns_status_item_(status_item), delegate_(nil) {
32+
Impl(NSStatusItem* status_item) : ns_status_item_(status_item), delegate_(nil), menu_closed_listener_id_(0) {
3333
if (status_item) {
3434
// Create and set up delegate
3535
delegate_ = [[TrayIconDelegate alloc] init];
@@ -45,6 +45,12 @@ - (void)statusItemClicked:(id)sender;
4545
}
4646

4747
~Impl() {
48+
// Remove the menu closed listener before cleaning up
49+
if (context_menu_ && menu_closed_listener_id_ != 0) {
50+
context_menu_->RemoveListener(menu_closed_listener_id_);
51+
menu_closed_listener_id_ = 0;
52+
}
53+
4854
// Clean up blocks first
4955
if (delegate_) {
5056
delegate_.leftClickedBlock = nil;
@@ -76,6 +82,7 @@ - (void)statusItemClicked:(id)sender;
7682
NSStatusItem* ns_status_item_;
7783
TrayIconDelegate* delegate_;
7884
std::shared_ptr<Menu> context_menu_;
85+
size_t menu_closed_listener_id_;
7986
};
8087

8188
TrayIcon::TrayIcon() : pimpl_(std::make_unique<Impl>()) {
@@ -242,17 +249,27 @@ - (void)statusItemClicked:(id)sender;
242249
}
243250

244251
void TrayIcon::SetContextMenu(std::shared_ptr<Menu> menu) {
252+
// Remove previous menu listener if it exists
253+
if (pimpl_->context_menu_ && pimpl_->menu_closed_listener_id_ != 0) {
254+
pimpl_->context_menu_->RemoveListener(pimpl_->menu_closed_listener_id_);
255+
pimpl_->menu_closed_listener_id_ = 0;
256+
}
257+
245258
// Store the menu reference
246259
// Don't set the menu directly to the status item, as this would cause
247260
// macOS to take over click handling and prevent our custom click events
248261
// Instead, we'll show the menu manually in our click handler
249262
pimpl_->context_menu_ = menu;
250-
auto pimpl_raw = pimpl_.get();
251-
pimpl_->context_menu_->AddListener<MenuClosedEvent>([pimpl_raw](const MenuClosedEvent& event) {
252-
if (pimpl_raw && pimpl_raw->ns_status_item_) {
253-
pimpl_raw->ns_status_item_.menu = nil;
254-
}
255-
});
263+
264+
if (pimpl_->context_menu_) {
265+
auto pimpl_raw = pimpl_.get();
266+
pimpl_->menu_closed_listener_id_ = pimpl_->context_menu_->AddListener<MenuClosedEvent>(
267+
[pimpl_raw](const MenuClosedEvent& event) {
268+
if (pimpl_raw && pimpl_raw->ns_status_item_) {
269+
pimpl_raw->ns_status_item_.menu = nil;
270+
}
271+
});
272+
}
256273
}
257274

258275
std::shared_ptr<Menu> TrayIcon::GetContextMenu() {

0 commit comments

Comments
 (0)