Skip to content

Commit 9cbfd9d

Browse files
committed
Refactor tray icon event handling across platforms
Removed platform-specific HandleLeftClick, HandleRightClick, and HandleDoubleClick methods from TrayIcon and replaced them with direct event emission in platform code. On macOS, click handling is now managed via blocks in the delegate, improving encapsulation and flexibility. Updated TrayIcon to inherit from NativeObjectProvider and added GetNativeObjectInternal for native object access. Minor formatting and cleanup applied in example and platform files.
1 parent 63289e2 commit 9cbfd9d

File tree

5 files changed

+104
-130
lines changed

5 files changed

+104
-130
lines changed

examples/window_example/main.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ int main() {
8282
"wLVwWPG97osM9Wf7Df6GGOwnsP4BQFiPuOZ8wJUAAAAASUVORK5CYII=");
8383
std::cout << "Tray ID: " << tray_icon.id << std::endl;
8484
auto title = tray_icon.GetTitle();
85-
std::cout << "Tray Title: " << (title.has_value() ? title.value() : "(no title)") << std::endl;
85+
std::cout << "Tray Title: "
86+
<< (title.has_value() ? title.value() : "(no title)")
87+
<< std::endl;
8688

8789
// Create context menu
8890
auto context_menu = Menu::Create();

src/platform/linux/tray_icon_linux.cpp

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ bool TrayIcon::SetVisible(bool visible) {
163163
app_indicator_set_status(pimpl_->app_indicator_,
164164
APP_INDICATOR_STATUS_PASSIVE);
165165
}
166-
166+
167167
pimpl_->visible_ = visible;
168168
return true;
169169
}
@@ -210,29 +210,4 @@ bool TrayIcon::CloseContextMenu() {
210210
return true;
211211
}
212212

213-
// Internal method to handle click events
214-
void TrayIcon::HandleLeftClick() {
215-
try {
216-
EmitSync<TrayIconClickedEvent>(id, "left");
217-
} catch (...) {
218-
// Protect against event emission exceptions
219-
}
220-
}
221-
222-
void TrayIcon::HandleRightClick() {
223-
try {
224-
EmitSync<TrayIconRightClickedEvent>(id);
225-
} catch (...) {
226-
// Protect against event emission exceptions
227-
}
228-
}
229-
230-
void TrayIcon::HandleDoubleClick() {
231-
try {
232-
EmitSync<TrayIconDoubleClickedEvent>(id);
233-
} catch (...) {
234-
// Protect against event emission exceptions
235-
}
236-
}
237-
238213
} // namespace nativeapi

src/platform/macos/tray_icon_macos.mm

Lines changed: 77 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@
1010
// for proper memory management of Objective-C objects.
1111

1212
// Forward declarations
13+
typedef void (^TrayIconClickedBlock)(nativeapi::TrayIconID tray_icon_id, const std::string& button);
14+
typedef void (^TrayIconRightClickedBlock)(nativeapi::TrayIconID tray_icon_id);
15+
typedef void (^TrayIconDoubleClickedBlock)(nativeapi::TrayIconID tray_icon_id);
16+
1317
@interface TrayIconDelegate : NSObject
1418
@property(nonatomic, assign) nativeapi::TrayIcon* trayIcon;
19+
@property(nonatomic, copy) TrayIconClickedBlock leftClickedBlock;
20+
@property(nonatomic, copy) TrayIconRightClickedBlock rightClickedBlock;
21+
@property(nonatomic, copy) TrayIconDoubleClickedBlock doubleClickedBlock;
1522
- (void)statusItemClicked:(id)sender;
16-
- (void)statusItemRightClicked:(id)sender;
1723
@end
1824

1925
@interface TrayIconMenuDelegate : NSObject <NSMenuDelegate>
@@ -48,14 +54,17 @@ @interface TrayIconMenuDelegate : NSObject <NSMenuDelegate>
4854
}
4955

5056
~Impl() {
51-
// First, clean up delegates to prevent callbacks
57+
// Clean up blocks first
5258
if (delegate_) {
53-
delegate_.trayIcon = nullptr; // Clear the raw pointer first
59+
delegate_.leftClickedBlock = nil;
60+
delegate_.rightClickedBlock = nil;
61+
delegate_.doubleClickedBlock = nil;
62+
delegate_.trayIcon = nullptr;
5463
delegate_ = nil;
5564
}
5665

5766
if (menu_delegate_) {
58-
menu_delegate_.trayIcon = nullptr; // Clear the raw pointer first
67+
menu_delegate_.trayIcon = nullptr;
5968
menu_delegate_ = nil;
6069
}
6170

@@ -88,6 +97,31 @@ @interface TrayIconMenuDelegate : NSObject <NSMenuDelegate>
8897
id = -1;
8998
if (pimpl_->delegate_) {
9099
pimpl_->delegate_.trayIcon = this;
100+
101+
// 设置默认的 Block 处理器,直接发送事件
102+
pimpl_->delegate_.leftClickedBlock = ^(TrayIconID tray_icon_id, const std::string& button) {
103+
try {
104+
EmitSync<TrayIconClickedEvent>(tray_icon_id, button);
105+
} catch (...) {
106+
// Protect against event emission exceptions
107+
}
108+
};
109+
110+
pimpl_->delegate_.rightClickedBlock = ^(TrayIconID tray_icon_id) {
111+
try {
112+
EmitSync<TrayIconRightClickedEvent>(tray_icon_id);
113+
} catch (...) {
114+
// Protect against event emission exceptions
115+
}
116+
};
117+
118+
pimpl_->delegate_.doubleClickedBlock = ^(TrayIconID tray_icon_id) {
119+
try {
120+
EmitSync<TrayIconDoubleClickedEvent>(tray_icon_id);
121+
} catch (...) {
122+
// Protect against event emission exceptions
123+
}
124+
};
91125
}
92126
if (pimpl_->menu_delegate_) {
93127
pimpl_->menu_delegate_.trayIcon = this;
@@ -98,6 +132,31 @@ @interface TrayIconMenuDelegate : NSObject <NSMenuDelegate>
98132
id = -1; // Will be set by TrayManager when created
99133
if (pimpl_->delegate_) {
100134
pimpl_->delegate_.trayIcon = this;
135+
136+
// 设置默认的 Block 处理器,直接发送事件
137+
pimpl_->delegate_.leftClickedBlock = ^(TrayIconID tray_icon_id, const std::string& button) {
138+
try {
139+
EmitSync<TrayIconClickedEvent>(tray_icon_id, button);
140+
} catch (...) {
141+
// Protect against event emission exceptions
142+
}
143+
};
144+
145+
pimpl_->delegate_.rightClickedBlock = ^(TrayIconID tray_icon_id) {
146+
try {
147+
EmitSync<TrayIconRightClickedEvent>(tray_icon_id);
148+
} catch (...) {
149+
// Protect against event emission exceptions
150+
}
151+
};
152+
153+
pimpl_->delegate_.doubleClickedBlock = ^(TrayIconID tray_icon_id) {
154+
try {
155+
EmitSync<TrayIconDoubleClickedEvent>(tray_icon_id);
156+
} catch (...) {
157+
// Protect against event emission exceptions
158+
}
159+
};
101160
}
102161
if (pimpl_->menu_delegate_) {
103162
pimpl_->menu_delegate_.trayIcon = this;
@@ -295,35 +354,8 @@ @interface TrayIconMenuDelegate : NSObject <NSMenuDelegate>
295354
return pimpl_->context_menu_->Close();
296355
}
297356

298-
// Internal method to handle click events
299-
void TrayIcon::HandleLeftClick() {
300-
try {
301-
EmitSync<TrayIconClickedEvent>(id, "left");
302-
} catch (...) {
303-
// Protect against event emission exceptions
304-
}
305-
}
306-
307-
void TrayIcon::HandleRightClick() {
308-
try {
309-
EmitSync<TrayIconRightClickedEvent>(id);
310-
} catch (...) {
311-
// Protect against event emission exceptions
312-
}
313-
}
314-
315-
void TrayIcon::HandleDoubleClick() {
316-
try {
317-
EmitSync<TrayIconDoubleClickedEvent>(id);
318-
} catch (...) {
319-
// Protect against event emission exceptions
320-
}
321-
}
322-
323-
void TrayIcon::ClearStatusItemMenu() {
324-
if (pimpl_->ns_status_item_) {
325-
pimpl_->ns_status_item_.menu = nil;
326-
}
357+
void* TrayIcon::GetNativeObjectInternal() const {
358+
return (__bridge void*)pimpl_->ns_status_item_;
327359
}
328360

329361
} // namespace nativeapi
@@ -345,29 +377,28 @@ - (void)statusItemClicked:(id)sender {
345377
if (!event)
346378
return;
347379

348-
// Check the type of click
380+
// Check the type of click and call appropriate block
349381
if (event.type == NSEventTypeRightMouseUp ||
350382
(event.type == NSEventTypeLeftMouseUp &&
351383
(event.modifierFlags & NSEventModifierFlagControl))) {
352384
// Right click or Ctrl+Left click
353-
trayIcon->HandleRightClick();
385+
if (_rightClickedBlock) {
386+
_rightClickedBlock(trayIcon->id);
387+
}
354388
} else if (event.type == NSEventTypeLeftMouseUp) {
355389
// Check for double click
356390
if (event.clickCount == 2) {
357-
trayIcon->HandleDoubleClick();
391+
if (_doubleClickedBlock) {
392+
_doubleClickedBlock(trayIcon->id);
393+
}
358394
} else {
359-
trayIcon->HandleLeftClick();
395+
if (_leftClickedBlock) {
396+
_leftClickedBlock(trayIcon->id, "left");
397+
}
360398
}
361399
}
362400
}
363401

364-
- (void)statusItemRightClicked:(id)sender {
365-
// Check if trayIcon is still valid before proceeding
366-
if (_trayIcon) {
367-
_trayIcon->HandleRightClick();
368-
}
369-
}
370-
371402
@end
372403

373404
// Implementation of TrayIconMenuDelegate
@@ -376,8 +407,9 @@ @implementation TrayIconMenuDelegate
376407
- (void)menuDidClose:(NSMenu*)menu {
377408
// Check if trayIcon is still valid before proceeding
378409
if (_trayIcon) {
410+
NSStatusItem* ns_status_item_ = (__bridge NSStatusItem*)_trayIcon->GetNativeObject();
379411
// Call a public method to clear the menu (we'll add this method)
380-
_trayIcon->ClearStatusItemMenu();
412+
ns_status_item_.menu = nil;
381413
}
382414
}
383415

src/platform/windows/tray_icon_windows.cpp

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,28 @@ class TrayIcon::Impl {
5050
if (message == WM_USER + 1 && wParam == icon_id_) {
5151
switch (lParam) {
5252
case WM_LBUTTONUP:
53-
tray_icon->HandleLeftClick();
53+
try {
54+
tray_icon->EmitSync<TrayIconClickedEvent>(tray_icon->id, "left");
55+
} catch (...) {
56+
// Protect against event emission exceptions
57+
}
5458
break;
5559
case WM_RBUTTONUP:
56-
tray_icon->HandleRightClick();
60+
try {
61+
tray_icon->EmitSync<TrayIconRightClickedEvent>(tray_icon->id);
62+
} catch (...) {
63+
// Protect against event emission exceptions
64+
}
5765
if (tray_icon->GetContextMenu()) {
5866
tray_icon->OpenContextMenu();
5967
}
6068
break;
6169
case WM_LBUTTONDBLCLK:
62-
tray_icon->HandleDoubleClick();
70+
try {
71+
tray_icon->EmitSync<TrayIconDoubleClickedEvent>(tray_icon->id);
72+
} catch (...) {
73+
// Protect against event emission exceptions
74+
}
6375
break;
6476
}
6577
return 0;
@@ -225,7 +237,7 @@ bool TrayIcon::SetVisible(bool visible) {
225237
// Already in the desired state
226238
return true;
227239
}
228-
240+
229241
return false;
230242
}
231243

@@ -267,31 +279,6 @@ bool TrayIcon::CloseContextMenu() {
267279
return pimpl_->context_menu_->Close();
268280
}
269281

270-
// Internal method to handle click events
271-
void TrayIcon::HandleLeftClick() {
272-
try {
273-
EmitSync<TrayIconClickedEvent>(id, "left");
274-
} catch (...) {
275-
// Protect against event emission exceptions
276-
}
277-
}
278-
279-
void TrayIcon::HandleRightClick() {
280-
try {
281-
EmitSync<TrayIconRightClickedEvent>(id);
282-
} catch (...) {
283-
// Protect against event emission exceptions
284-
}
285-
}
286-
287-
void TrayIcon::HandleDoubleClick() {
288-
try {
289-
EmitSync<TrayIconDoubleClickedEvent>(id);
290-
} catch (...) {
291-
// Protect against event emission exceptions
292-
}
293-
}
294-
295282
// Note: Windows-specific functionality is now handled internally by the Impl
296283
// class The SetWindowsData and HandleWindowsMessage methods have been moved to
297284
// the Impl class to maintain proper encapsulation and avoid exposing

src/tray_icon.h

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ typedef long TrayIconID;
6161
* trayIcon->Show();
6262
* ```
6363
*/
64-
class TrayIcon : public EventEmitter {
64+
class TrayIcon : public EventEmitter, public NativeObjectProvider {
6565
public:
6666
/**
6767
* @brief Default constructor for TrayIcon.
@@ -316,38 +316,16 @@ class TrayIcon : public EventEmitter {
316316
*/
317317
bool CloseContextMenu();
318318

319+
protected:
319320
/**
320-
* @brief Internal method to handle left mouse click events.
321+
* @brief Internal method to get the platform-specific native tray icon object.
321322
*
322-
* This method is called internally by platform-specific code
323-
* when a left click event occurs on the tray icon.
324-
*/
325-
void HandleLeftClick();
326-
327-
/**
328-
* @brief Internal method to handle right mouse click events.
329-
*
330-
* This method is called internally by platform-specific code
331-
* when a right click event occurs on the tray icon.
332-
*/
333-
void HandleRightClick();
334-
335-
/**
336-
* @brief Internal method to handle double click events.
337-
*
338-
* This method is called internally by platform-specific code
339-
* when a double click event occurs on the tray icon.
340-
*/
341-
void HandleDoubleClick();
342-
343-
/**
344-
* @brief Clear the menu reference from the status item.
323+
* This method must be implemented by platform-specific code to return
324+
* the underlying native tray icon object.
345325
*
346-
* This method is used internally to clean up the menu reference
347-
* when the context menu is closed. It's called by the menu delegate
348-
* to ensure proper cleanup.
326+
* @return Pointer to the native menu item object
349327
*/
350-
void ClearStatusItemMenu();
328+
void* GetNativeObjectInternal() const override;
351329

352330
private:
353331
/**

0 commit comments

Comments
 (0)