plusui-native-core 0.1.105 → 0.1.106

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/Core/.claude/settings.local.json +7 -0
  2. package/Core/CMakeLists.txt +1 -1
  3. package/Core/Features/API/app-api.ts +28 -28
  4. package/Core/Features/API/browser-api.ts +38 -38
  5. package/Core/Features/API/clipboard-api.ts +21 -21
  6. package/Core/Features/API/display-api.ts +33 -33
  7. package/Core/Features/API/keyboard-api.ts +33 -33
  8. package/Core/Features/API/menu-api.ts +39 -39
  9. package/Core/Features/API/router-api.ts +23 -23
  10. package/Core/Features/API/tray-api.ts +22 -22
  11. package/Core/Features/API/webgpu-api.ts +55 -55
  12. package/Core/Features/App/app.cpp +128 -102
  13. package/Core/Features/Browser/browser.cpp +227 -227
  14. package/Core/Features/Browser/browser.ts +161 -161
  15. package/Core/Features/Clipboard/clipboard.cpp +235 -235
  16. package/Core/Features/Display/display.cpp +212 -212
  17. package/Core/Features/FileDrop/filedrop.cpp +448 -324
  18. package/Core/Features/FileDrop/filedrop.css +421 -421
  19. package/Core/Features/FileDrop/filedrop.ts +0 -7
  20. package/Core/Features/Keyboard/keyboard_linux.cpp +4 -0
  21. package/Core/Features/Router/router.cpp +62 -62
  22. package/Core/Features/Router/router.ts +113 -113
  23. package/Core/Features/Tray/tray.cpp +328 -324
  24. package/Core/Features/WebGPU/webgpu.cpp +948 -948
  25. package/Core/Features/Window/webview.cpp +1009 -1009
  26. package/Core/Features/Window/webview.ts +516 -516
  27. package/Core/Features/Window/window.cpp +2240 -1986
  28. package/Core/include/plusui/api.hpp +237 -237
  29. package/Core/include/plusui/app.hpp +33 -33
  30. package/Core/include/plusui/browser.hpp +67 -67
  31. package/Core/include/plusui/clipboard.hpp +41 -41
  32. package/Core/include/plusui/connect.hpp +340 -340
  33. package/Core/include/plusui/connection.hpp +3 -3
  34. package/Core/include/plusui/display.hpp +90 -90
  35. package/Core/include/plusui/filedrop.hpp +92 -77
  36. package/Core/include/plusui/keyboard.hpp +112 -112
  37. package/Core/include/plusui/menu.hpp +153 -153
  38. package/Core/include/plusui/plusui +18 -18
  39. package/Core/include/plusui/router.hpp +42 -42
  40. package/Core/include/plusui/tray.hpp +94 -94
  41. package/Core/include/plusui/webgpu.hpp +434 -434
  42. package/Core/include/plusui/window.hpp +180 -177
  43. package/Core/scripts/generate-umbrella-header.mjs +77 -77
  44. package/Core/vendor/WebView2EnvironmentOptions.h +406 -406
  45. package/Core/vendor/webview.h +487 -487
  46. package/Core/vendor/webview2.h +52079 -52079
  47. package/README.md +19 -19
  48. package/package.json +1 -1
@@ -1,324 +1,328 @@
1
- #ifdef _WIN32
2
- #ifndef _WIN32_WINNT
3
- #define _WIN32_WINNT 0x0601
4
- #endif
5
- #include <windows.h>
6
-
7
- #ifndef EXTERN_C
8
- #ifdef __cplusplus
9
- #define EXTERN_C extern "C"
10
- #else
11
- #define EXTERN_C extern
12
- #endif
13
- #endif
14
-
15
- #include <shellapi.h>
16
- #include <shlobj.h>
17
- #pragma comment(lib, "shell32.lib")
18
- #endif
19
-
20
- #include <algorithm>
21
- #include <iostream>
22
- #include <plusui/tray.hpp>
23
- #include <string>
24
- #include <vector>
25
-
26
- #define STB_IMAGE_IMPLEMENTATION
27
- #include <stb_image.h>
28
-
29
- #ifdef __APPLE__
30
- #include <Cocoa/Cocoa.h>
31
- #elif !defined(_WIN32)
32
- #include <gdk/gdk.h>
33
- #include <gtk/gtk.h>
34
- #endif
35
-
36
- namespace plusui {
37
-
38
- struct TrayIcon::Impl {
39
- int id = 0;
40
- std::string tooltip;
41
- std::string iconPath;
42
- bool visible = true;
43
-
44
- std::function<void(int, int)> clickCallback;
45
- std::function<void(int, int)> rightClickCallback;
46
- std::function<void()> doubleClickCallback;
47
- std::function<void(const std::string &)> menuItemCallback;
48
- std::vector<TrayMenuItem> menuItems;
49
-
50
- #ifdef _WIN32
51
- NOTIFYICONDATAW nid = {};
52
- HWND hwnd = nullptr;
53
- #endif
54
- };
55
-
56
- TrayIcon::TrayIcon() : pImpl(std::make_unique<Impl>()) {}
57
- TrayIcon::~TrayIcon() { dispose(); }
58
-
59
- TrayIcon::TrayIcon(TrayIcon &&other) noexcept = default;
60
- TrayIcon &TrayIcon::operator=(TrayIcon &&other) noexcept = default;
61
-
62
- TrayIcon TrayIcon::create(const std::string &tooltip,
63
- const std::string &iconPath) {
64
- TrayIcon icon;
65
- icon.pImpl->tooltip = tooltip;
66
- icon.pImpl->iconPath = iconPath;
67
-
68
- #ifdef _WIN32
69
- icon.pImpl->nid.uID = 1;
70
- icon.pImpl->nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
71
- icon.pImpl->nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
72
- icon.pImpl->nid.uCallbackMessage = WM_APP + 1; // Example message
73
-
74
- if (!tooltip.empty()) {
75
- std::wstring wtooltip(tooltip.begin(), tooltip.end());
76
- wcsncpy_s(icon.pImpl->nid.szTip, _countof(icon.pImpl->nid.szTip),
77
- wtooltip.c_str(), _TRUNCATE);
78
- }
79
-
80
- // Note: nim_add should be called after hwnd is set
81
- #endif
82
-
83
- return icon;
84
- }
85
-
86
- void TrayIcon::show() {
87
- pImpl->visible = true;
88
- #ifdef _WIN32
89
- if (pImpl->hwnd) {
90
- pImpl->nid.hWnd = pImpl->hwnd;
91
- Shell_NotifyIconW(NIM_ADD, &pImpl->nid);
92
- }
93
- #endif
94
- }
95
-
96
- void TrayIcon::hide() {
97
- pImpl->visible = false;
98
- #ifdef _WIN32
99
- Shell_NotifyIconW(NIM_DELETE, &pImpl->nid);
100
- #endif
101
- }
102
-
103
- void TrayIcon::setTooltip(const std::string &tooltip) {
104
- pImpl->tooltip = tooltip;
105
- #ifdef _WIN32
106
- if (!tooltip.empty()) {
107
- std::wstring wtooltip(tooltip.begin(), tooltip.end());
108
- wcsncpy_s(pImpl->nid.szTip, _countof(pImpl->nid.szTip), wtooltip.c_str(),
109
- _TRUNCATE);
110
- Shell_NotifyIconW(NIM_MODIFY, &pImpl->nid);
111
- }
112
- #endif
113
- }
114
-
115
- void TrayIcon::setIcon(const std::string &iconPath) {
116
- pImpl->iconPath = iconPath;
117
- #ifdef _WIN32
118
- if (!iconPath.empty()) {
119
- std::wstring wpath(iconPath.begin(), iconPath.end());
120
- pImpl->nid.hIcon = (HICON)LoadImageW(nullptr, wpath.c_str(), IMAGE_ICON, 16,
121
- 16, LR_LOADFROMFILE);
122
- Shell_NotifyIconW(NIM_MODIFY, &pImpl->nid);
123
- }
124
- #endif
125
- }
126
-
127
- void TrayIcon::setIconFromData(const std::vector<uint8_t> &data, int width,
128
- int height) {
129
- #ifdef _WIN32
130
- if (!data.empty()) {
131
- BITMAPINFO bmi = {};
132
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
133
- bmi.bmiHeader.biWidth = width;
134
- bmi.bmiHeader.biHeight = -height;
135
- bmi.bmiHeader.biPlanes = 1;
136
- bmi.bmiHeader.biBitCount = 32;
137
- bmi.bmiHeader.biCompression = BI_RGB;
138
-
139
- void *bits = nullptr;
140
- HBITMAP hbm =
141
- CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0);
142
- if (hbm && bits && data.size() >= (size_t)width * height * 4) {
143
- memcpy(bits, data.data(), width * height * 4);
144
-
145
- ICONINFO ii = {};
146
- ii.fIcon = TRUE;
147
- ii.hbmColor = hbm;
148
- ii.hbmMask = hbm;
149
-
150
- HICON hIcon = CreateIconIndirect(&ii);
151
- if (hIcon) {
152
- pImpl->nid.hIcon = hIcon;
153
- Shell_NotifyIconW(NIM_MODIFY, &pImpl->nid);
154
- DestroyIcon(hIcon);
155
- }
156
- DeleteObject(hbm);
157
- }
158
- }
159
- #endif
160
- }
161
-
162
- void TrayIcon::setIconFromMemory(const unsigned char *data, size_t size) {
163
- int width, height, channels;
164
- unsigned char *pixels =
165
- stbi_load_from_memory(data, (int)size, &width, &height, &channels, 4);
166
- if (pixels) {
167
- std::vector<uint8_t> pixelVec(pixels, pixels + (width * height * 4));
168
-
169
- #ifdef _WIN32
170
- // Windows expects BGRA, stb_image returns RGBA
171
- for (int i = 0; i < width * height; ++i) {
172
- uint8_t r = pixelVec[i * 4 + 0];
173
- uint8_t b = pixelVec[i * 4 + 2];
174
- pixelVec[i * 4 + 0] = b;
175
- pixelVec[i * 4 + 2] = r;
176
- }
177
- setIconFromData(pixelVec, width, height);
178
- #elif defined(__APPLE__)
179
- // Implementation for macOS (To be implemented)
180
- #else
181
- // Implementation for Linux (GTK) (To be implemented)
182
- #endif
183
-
184
- stbi_image_free(pixels);
185
- }
186
- }
187
-
188
- // Methods removed: show, hide (duplicate definitions)
189
-
190
- bool TrayIcon::isVisible() const { return pImpl->visible; }
191
-
192
- void TrayIcon::setMenu(const std::vector<TrayMenuItem> &items) {
193
- pImpl->menuItems = items;
194
- #ifdef _WIN32
195
- HMENU hMenu = CreatePopupMenu();
196
- for (const auto &item : items) {
197
- if (item.separator) {
198
- AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
199
- } else {
200
- std::wstring label(item.label.begin(), item.label.end());
201
- UINT flags = MF_STRING;
202
- if (!item.enabled)
203
- flags |= MF_DISABLED;
204
- if (item.checked)
205
- flags |= MF_CHECKED;
206
- AppendMenuW(hMenu, flags, (UINT_PTR)item.id.c_str(), label.c_str());
207
- }
208
- }
209
- #endif
210
- }
211
-
212
- void TrayIcon::setContextMenu(const std::vector<TrayMenuItem> &items) {
213
- setMenu(items);
214
- }
215
-
216
- void TrayIcon::onClick(std::function<void(int, int)> callback) {
217
- pImpl->clickCallback = callback;
218
- }
219
-
220
- void TrayIcon::onRightClick(std::function<void(int, int)> callback) {
221
- pImpl->rightClickCallback = callback;
222
- }
223
-
224
- void TrayIcon::onDoubleClick(std::function<void()> callback) {
225
- pImpl->doubleClickCallback = callback;
226
- }
227
-
228
- void TrayIcon::onMenuItemClick(
229
- std::function<void(const std::string &)> callback) {
230
- pImpl->menuItemCallback = callback;
231
- }
232
-
233
- void TrayIcon::dispose() {
234
- #ifdef _WIN32
235
- Shell_NotifyIconW(NIM_DELETE, &pImpl->nid);
236
- #endif
237
- }
238
-
239
- struct TrayManager::Impl {
240
- HWND hwnd = nullptr;
241
- std::unique_ptr<TrayIcon> mainIcon;
242
- std::vector<TrayIcon *> icons;
243
- std::function<void(TrayIcon &)> onCreatedCallback;
244
- std::function<void(int)> onDestroyedCallback;
245
- std::string currentIconPath;
246
- std::string currentTooltip;
247
- bool currentVisible = false;
248
- };
249
-
250
- TrayManager::TrayManager() : pImpl(std::make_unique<Impl>()) {}
251
- TrayManager::~TrayManager() = default;
252
-
253
- TrayManager &TrayManager::instance() {
254
- static TrayManager inst;
255
- return inst;
256
- }
257
-
258
- void TrayManager::setWindowHandle(void *hwnd) {
259
- #ifdef _WIN32
260
- pImpl->hwnd = (HWND)hwnd;
261
- if (pImpl->mainIcon) {
262
- pImpl->mainIcon->pImpl->hwnd = pImpl->hwnd;
263
- }
264
- #endif
265
- }
266
-
267
- void TrayManager::setIcon(const std::string &iconPath) {
268
- pImpl->currentIconPath = iconPath;
269
- if (pImpl->mainIcon) {
270
- pImpl->mainIcon->setIcon(iconPath);
271
- } else {
272
- pImpl->mainIcon =
273
- std::make_unique<TrayIcon>(TrayIcon::create("", iconPath));
274
- #ifdef _WIN32
275
- pImpl->mainIcon->pImpl->nid.cbSize = sizeof(NOTIFYICONDATAW);
276
- pImpl->mainIcon->pImpl->hwnd = pImpl->hwnd;
277
- #endif
278
- }
279
- }
280
-
281
- void TrayManager::setTooltip(const std::string &tooltip) {
282
- pImpl->currentTooltip = tooltip;
283
- if (pImpl->mainIcon) {
284
- pImpl->mainIcon->setTooltip(tooltip);
285
- }
286
- }
287
-
288
- void TrayManager::setVisible(bool visible) {
289
- pImpl->currentVisible = visible;
290
- if (pImpl->mainIcon) {
291
- if (visible)
292
- pImpl->mainIcon->show();
293
- else
294
- pImpl->mainIcon->hide();
295
- }
296
- }
297
-
298
- std::vector<TrayIcon *> TrayManager::getIcons() { return pImpl->icons; }
299
-
300
- void TrayManager::onTrayCreated(std::function<void(TrayIcon &)> callback) {
301
- pImpl->onCreatedCallback = callback;
302
- }
303
-
304
- void TrayManager::onTrayDestroyed(std::function<void(int)> callback) {
305
- pImpl->onDestroyedCallback = callback;
306
- }
307
-
308
- void TrayManager::refresh() {}
309
-
310
- void TrayManager::setIconFromMemory(const unsigned char *data, size_t size) {
311
- if (pImpl->mainIcon) {
312
- pImpl->mainIcon->setIconFromMemory(data, size);
313
- } else {
314
- // Create the icon if it doesn't exist
315
- pImpl->mainIcon = std::make_unique<TrayIcon>(TrayIcon::create("", ""));
316
- #ifdef _WIN32
317
- pImpl->mainIcon->pImpl->nid.cbSize = sizeof(NOTIFYICONDATAW);
318
- pImpl->mainIcon->pImpl->hwnd = pImpl->hwnd;
319
- #endif
320
- pImpl->mainIcon->setIconFromMemory(data, size);
321
- }
322
- }
323
-
324
- } // namespace plusui
1
+ #ifdef _WIN32
2
+ #ifndef _WIN32_WINNT
3
+ #define _WIN32_WINNT 0x0601
4
+ #endif
5
+ #include <windows.h>
6
+
7
+ #ifndef EXTERN_C
8
+ #ifdef __cplusplus
9
+ #define EXTERN_C extern "C"
10
+ #else
11
+ #define EXTERN_C extern
12
+ #endif
13
+ #endif
14
+
15
+ #include <shellapi.h>
16
+ #include <shlobj.h>
17
+ #pragma comment(lib, "shell32.lib")
18
+ #endif
19
+
20
+ #include <algorithm>
21
+ #include <iostream>
22
+ #include <plusui/tray.hpp>
23
+ #include <string>
24
+ #include <vector>
25
+
26
+ #define STB_IMAGE_IMPLEMENTATION
27
+ #include <stb_image.h>
28
+
29
+ #ifdef __APPLE__
30
+ #include <Cocoa/Cocoa.h>
31
+ #elif !defined(_WIN32)
32
+ #include <gdk/gdk.h>
33
+ #include <gtk/gtk.h>
34
+ #endif
35
+
36
+ namespace plusui {
37
+
38
+ struct TrayIcon::Impl {
39
+ int id = 0;
40
+ std::string tooltip;
41
+ std::string iconPath;
42
+ bool visible = true;
43
+
44
+ std::function<void(int, int)> clickCallback;
45
+ std::function<void(int, int)> rightClickCallback;
46
+ std::function<void()> doubleClickCallback;
47
+ std::function<void(const std::string &)> menuItemCallback;
48
+ std::vector<TrayMenuItem> menuItems;
49
+
50
+ #ifdef _WIN32
51
+ NOTIFYICONDATAW nid = {};
52
+ HWND hwnd = nullptr;
53
+ #endif
54
+ };
55
+
56
+ TrayIcon::TrayIcon() : pImpl(std::make_unique<Impl>()) {}
57
+ TrayIcon::~TrayIcon() { dispose(); }
58
+
59
+ TrayIcon::TrayIcon(TrayIcon &&other) noexcept = default;
60
+ TrayIcon &TrayIcon::operator=(TrayIcon &&other) noexcept = default;
61
+
62
+ TrayIcon TrayIcon::create(const std::string &tooltip,
63
+ const std::string &iconPath) {
64
+ TrayIcon icon;
65
+ icon.pImpl->tooltip = tooltip;
66
+ icon.pImpl->iconPath = iconPath;
67
+
68
+ #ifdef _WIN32
69
+ icon.pImpl->nid.uID = 1;
70
+ icon.pImpl->nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
71
+ icon.pImpl->nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
72
+ icon.pImpl->nid.uCallbackMessage = WM_APP + 1; // Example message
73
+
74
+ if (!tooltip.empty()) {
75
+ std::wstring wtooltip(tooltip.begin(), tooltip.end());
76
+ wcsncpy_s(icon.pImpl->nid.szTip, _countof(icon.pImpl->nid.szTip),
77
+ wtooltip.c_str(), _TRUNCATE);
78
+ }
79
+
80
+ // Note: nim_add should be called after hwnd is set
81
+ #endif
82
+
83
+ return icon;
84
+ }
85
+
86
+ void TrayIcon::show() {
87
+ pImpl->visible = true;
88
+ #ifdef _WIN32
89
+ if (pImpl->hwnd) {
90
+ pImpl->nid.hWnd = pImpl->hwnd;
91
+ Shell_NotifyIconW(NIM_ADD, &pImpl->nid);
92
+ }
93
+ #endif
94
+ }
95
+
96
+ void TrayIcon::hide() {
97
+ pImpl->visible = false;
98
+ #ifdef _WIN32
99
+ Shell_NotifyIconW(NIM_DELETE, &pImpl->nid);
100
+ #endif
101
+ }
102
+
103
+ void TrayIcon::setTooltip(const std::string &tooltip) {
104
+ pImpl->tooltip = tooltip;
105
+ #ifdef _WIN32
106
+ if (!tooltip.empty()) {
107
+ std::wstring wtooltip(tooltip.begin(), tooltip.end());
108
+ wcsncpy_s(pImpl->nid.szTip, _countof(pImpl->nid.szTip), wtooltip.c_str(),
109
+ _TRUNCATE);
110
+ Shell_NotifyIconW(NIM_MODIFY, &pImpl->nid);
111
+ }
112
+ #endif
113
+ }
114
+
115
+ void TrayIcon::setIcon(const std::string &iconPath) {
116
+ pImpl->iconPath = iconPath;
117
+ #ifdef _WIN32
118
+ if (!iconPath.empty()) {
119
+ std::wstring wpath(iconPath.begin(), iconPath.end());
120
+ pImpl->nid.hIcon = (HICON)LoadImageW(nullptr, wpath.c_str(), IMAGE_ICON, 16,
121
+ 16, LR_LOADFROMFILE);
122
+ Shell_NotifyIconW(NIM_MODIFY, &pImpl->nid);
123
+ }
124
+ #endif
125
+ }
126
+
127
+ void TrayIcon::setIconFromData(const std::vector<uint8_t> &data, int width,
128
+ int height) {
129
+ #ifdef _WIN32
130
+ if (!data.empty()) {
131
+ BITMAPINFO bmi = {};
132
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
133
+ bmi.bmiHeader.biWidth = width;
134
+ bmi.bmiHeader.biHeight = -height;
135
+ bmi.bmiHeader.biPlanes = 1;
136
+ bmi.bmiHeader.biBitCount = 32;
137
+ bmi.bmiHeader.biCompression = BI_RGB;
138
+
139
+ void *bits = nullptr;
140
+ HBITMAP hbm =
141
+ CreateDIBSection(nullptr, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0);
142
+ if (hbm && bits && data.size() >= (size_t)width * height * 4) {
143
+ memcpy(bits, data.data(), width * height * 4);
144
+
145
+ ICONINFO ii = {};
146
+ ii.fIcon = TRUE;
147
+ ii.hbmColor = hbm;
148
+ ii.hbmMask = hbm;
149
+
150
+ HICON hIcon = CreateIconIndirect(&ii);
151
+ if (hIcon) {
152
+ pImpl->nid.hIcon = hIcon;
153
+ Shell_NotifyIconW(NIM_MODIFY, &pImpl->nid);
154
+ DestroyIcon(hIcon);
155
+ }
156
+ DeleteObject(hbm);
157
+ }
158
+ }
159
+ #endif
160
+ }
161
+
162
+ void TrayIcon::setIconFromMemory(const unsigned char *data, size_t size) {
163
+ int width, height, channels;
164
+ unsigned char *pixels =
165
+ stbi_load_from_memory(data, (int)size, &width, &height, &channels, 4);
166
+ if (pixels) {
167
+ std::vector<uint8_t> pixelVec(pixels, pixels + (width * height * 4));
168
+
169
+ #ifdef _WIN32
170
+ // Windows expects BGRA, stb_image returns RGBA
171
+ for (int i = 0; i < width * height; ++i) {
172
+ uint8_t r = pixelVec[i * 4 + 0];
173
+ uint8_t b = pixelVec[i * 4 + 2];
174
+ pixelVec[i * 4 + 0] = b;
175
+ pixelVec[i * 4 + 2] = r;
176
+ }
177
+ setIconFromData(pixelVec, width, height);
178
+ #elif defined(__APPLE__)
179
+ // Implementation for macOS (To be implemented)
180
+ #else
181
+ // Implementation for Linux (GTK) (To be implemented)
182
+ #endif
183
+
184
+ stbi_image_free(pixels);
185
+ }
186
+ }
187
+
188
+ // Methods removed: show, hide (duplicate definitions)
189
+
190
+ bool TrayIcon::isVisible() const { return pImpl->visible; }
191
+
192
+ void TrayIcon::setMenu(const std::vector<TrayMenuItem> &items) {
193
+ pImpl->menuItems = items;
194
+ #ifdef _WIN32
195
+ HMENU hMenu = CreatePopupMenu();
196
+ for (const auto &item : items) {
197
+ if (item.separator) {
198
+ AppendMenuW(hMenu, MF_SEPARATOR, 0, nullptr);
199
+ } else {
200
+ std::wstring label(item.label.begin(), item.label.end());
201
+ UINT flags = MF_STRING;
202
+ if (!item.enabled)
203
+ flags |= MF_DISABLED;
204
+ if (item.checked)
205
+ flags |= MF_CHECKED;
206
+ AppendMenuW(hMenu, flags, (UINT_PTR)item.id.c_str(), label.c_str());
207
+ }
208
+ }
209
+ #endif
210
+ }
211
+
212
+ void TrayIcon::setContextMenu(const std::vector<TrayMenuItem> &items) {
213
+ setMenu(items);
214
+ }
215
+
216
+ void TrayIcon::onClick(std::function<void(int, int)> callback) {
217
+ pImpl->clickCallback = callback;
218
+ }
219
+
220
+ void TrayIcon::onRightClick(std::function<void(int, int)> callback) {
221
+ pImpl->rightClickCallback = callback;
222
+ }
223
+
224
+ void TrayIcon::onDoubleClick(std::function<void()> callback) {
225
+ pImpl->doubleClickCallback = callback;
226
+ }
227
+
228
+ void TrayIcon::onMenuItemClick(
229
+ std::function<void(const std::string &)> callback) {
230
+ pImpl->menuItemCallback = callback;
231
+ }
232
+
233
+ void TrayIcon::dispose() {
234
+ #ifdef _WIN32
235
+ Shell_NotifyIconW(NIM_DELETE, &pImpl->nid);
236
+ #endif
237
+ }
238
+
239
+ struct TrayManager::Impl {
240
+ #ifdef _WIN32
241
+ HWND hwnd = nullptr;
242
+ #else
243
+ void* hwnd = nullptr;
244
+ #endif
245
+ std::unique_ptr<TrayIcon> mainIcon;
246
+ std::vector<TrayIcon *> icons;
247
+ std::function<void(TrayIcon &)> onCreatedCallback;
248
+ std::function<void(int)> onDestroyedCallback;
249
+ std::string currentIconPath;
250
+ std::string currentTooltip;
251
+ bool currentVisible = false;
252
+ };
253
+
254
+ TrayManager::TrayManager() : pImpl(std::make_unique<Impl>()) {}
255
+ TrayManager::~TrayManager() = default;
256
+
257
+ TrayManager &TrayManager::instance() {
258
+ static TrayManager inst;
259
+ return inst;
260
+ }
261
+
262
+ void TrayManager::setWindowHandle(void *hwnd) {
263
+ #ifdef _WIN32
264
+ pImpl->hwnd = (HWND)hwnd;
265
+ if (pImpl->mainIcon) {
266
+ pImpl->mainIcon->pImpl->hwnd = pImpl->hwnd;
267
+ }
268
+ #endif
269
+ }
270
+
271
+ void TrayManager::setIcon(const std::string &iconPath) {
272
+ pImpl->currentIconPath = iconPath;
273
+ if (pImpl->mainIcon) {
274
+ pImpl->mainIcon->setIcon(iconPath);
275
+ } else {
276
+ pImpl->mainIcon =
277
+ std::make_unique<TrayIcon>(TrayIcon::create("", iconPath));
278
+ #ifdef _WIN32
279
+ pImpl->mainIcon->pImpl->nid.cbSize = sizeof(NOTIFYICONDATAW);
280
+ pImpl->mainIcon->pImpl->hwnd = pImpl->hwnd;
281
+ #endif
282
+ }
283
+ }
284
+
285
+ void TrayManager::setTooltip(const std::string &tooltip) {
286
+ pImpl->currentTooltip = tooltip;
287
+ if (pImpl->mainIcon) {
288
+ pImpl->mainIcon->setTooltip(tooltip);
289
+ }
290
+ }
291
+
292
+ void TrayManager::setVisible(bool visible) {
293
+ pImpl->currentVisible = visible;
294
+ if (pImpl->mainIcon) {
295
+ if (visible)
296
+ pImpl->mainIcon->show();
297
+ else
298
+ pImpl->mainIcon->hide();
299
+ }
300
+ }
301
+
302
+ std::vector<TrayIcon *> TrayManager::getIcons() { return pImpl->icons; }
303
+
304
+ void TrayManager::onTrayCreated(std::function<void(TrayIcon &)> callback) {
305
+ pImpl->onCreatedCallback = callback;
306
+ }
307
+
308
+ void TrayManager::onTrayDestroyed(std::function<void(int)> callback) {
309
+ pImpl->onDestroyedCallback = callback;
310
+ }
311
+
312
+ void TrayManager::refresh() {}
313
+
314
+ void TrayManager::setIconFromMemory(const unsigned char *data, size_t size) {
315
+ if (pImpl->mainIcon) {
316
+ pImpl->mainIcon->setIconFromMemory(data, size);
317
+ } else {
318
+ // Create the icon if it doesn't exist
319
+ pImpl->mainIcon = std::make_unique<TrayIcon>(TrayIcon::create("", ""));
320
+ #ifdef _WIN32
321
+ pImpl->mainIcon->pImpl->nid.cbSize = sizeof(NOTIFYICONDATAW);
322
+ pImpl->mainIcon->pImpl->hwnd = pImpl->hwnd;
323
+ #endif
324
+ pImpl->mainIcon->setIconFromMemory(data, size);
325
+ }
326
+ }
327
+
328
+ } // namespace plusui