|
1 | 1 | #include "notifications/shellnotification.h" |
2 | 2 | #include <filesystem> |
3 | | -#include <memory> |
4 | | -#include <string> |
5 | 3 | #include <thread> |
6 | | -#include "helpers/stringhelpers.h" |
7 | 4 | #include "system/environment.h" |
8 | 5 | #ifdef _WIN32 |
9 | | -#include <wintoastlib.h> |
| 6 | +#include <windows.h> |
| 7 | +#include <shellapi.h> |
10 | 8 | #else |
11 | 9 | #include <gio/gio.h> |
12 | 10 | #endif |
13 | 11 |
|
14 | | -using namespace Nickvision::App; |
15 | | -using namespace Nickvision::Helpers; |
16 | | -using namespace Nickvision::System; |
17 | | - |
18 | 12 | #ifdef _WIN32 |
19 | | -using namespace WinToastLib; |
20 | | - |
21 | | -class WinToastHandler : public IWinToastHandler |
22 | | -{ |
23 | | -public: |
24 | | - WinToastHandler() |
25 | | - { |
26 | | - |
27 | | - } |
28 | | - |
29 | | - WinToastHandler(const std::filesystem::path& openPath) |
30 | | - : m_openPath{ openPath } |
31 | | - { |
32 | | - |
33 | | - } |
34 | | - |
35 | | - void toastActivated() const override |
36 | | - { |
37 | | - |
38 | | - } |
39 | | - |
40 | | - void toastActivated(int actionIndex) const override |
41 | | - { |
42 | | - //First and only button --> "Open" |
43 | | - if(actionIndex == 0 && !m_openPath.empty()) |
44 | | - { |
45 | | - ShellExecuteW(nullptr, L"open", m_openPath.wstring().c_str(), nullptr, nullptr, SW_SHOWDEFAULT); |
46 | | - } |
47 | | - } |
48 | | - |
49 | | - void toastActivated(const char*) const override |
50 | | - { |
51 | | - |
52 | | - } |
53 | | - |
54 | | - void toastDismissed(WinToastDismissalReason) const override |
55 | | - { |
56 | | - |
57 | | - } |
58 | | - |
59 | | - void toastFailed() const override |
60 | | - { |
61 | | - |
62 | | - } |
63 | | - |
64 | | -private: |
65 | | - std::filesystem::path m_openPath; |
66 | | -}; |
| 13 | +#define WM_TRAYICON WM_APP + 1 |
| 14 | +#define TRAYICON_ID 1001 |
| 15 | +#define TIMER_ID 1002 |
67 | 16 | #endif |
68 | 17 |
|
| 18 | +using namespace Nickvision::App; |
| 19 | +using namespace Nickvision::System; |
| 20 | + |
69 | 21 | namespace Nickvision::Notifications |
70 | 22 | { |
71 | 23 | void ShellNotification::send(const ShellNotificationSentEventArgs& e, const AppInfo& info, const std::string& openText) |
72 | 24 | { |
73 | 25 | #ifdef _WIN32 |
74 | | - WinToast::WinToastError err; |
75 | | - static bool initialized{ false }; |
76 | | - if(!initialized) |
| 26 | + std::thread worker{ [e, info]() |
77 | 27 | { |
78 | | - WinToast::instance()->setAppName(StringHelpers::wstr(info.getEnglishShortName())); |
79 | | - WinToast::instance()->setAppUserModelId(StringHelpers::wstr(info.getEnglishShortName())); |
80 | | - initialized = WinToast::instance()->initialize(&err); |
81 | | - } |
82 | | - WinToastTemplate tmpl{ WinToastTemplate::Text02 }; |
83 | | - IWinToastHandler* handler{ nullptr }; |
84 | | - tmpl.setTextField(StringHelpers::wstr(e.getTitle()), WinToastTemplate::FirstLine); |
85 | | - tmpl.setTextField(StringHelpers::wstr(e.getMessage()), WinToastTemplate::SecondLine); |
86 | | - if(e.getAction() == "open" && std::filesystem::exists(e.getActionParam())) |
87 | | - { |
88 | | - tmpl.addAction(StringHelpers::wstr(openText)); |
89 | | - handler = new WinToastHandler(e.getActionParam()); |
90 | | - } |
91 | | - else |
92 | | - { |
93 | | - handler = new WinToastHandler(); |
94 | | - } |
95 | | - WinToast::instance()->showToast(tmpl, handler); |
| 28 | + static std::filesystem::path path{ e.getAction() == "open" ? e.getActionParam() : "" }; |
| 29 | + std::string className{ "libnick_notification" }; |
| 30 | + WNDCLASSA wc{}; |
| 31 | + wc.lpfnWndProc = +[](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT |
| 32 | + { |
| 33 | + if(msg == WM_TRAYICON) |
| 34 | + { |
| 35 | + if(lParam == NIN_BALLOONUSERCLICK) |
| 36 | + { |
| 37 | + if(std::filesystem::exists(path)) |
| 38 | + { |
| 39 | + ShellExecuteA(hwnd, "open", path.string().c_str(), nullptr, nullptr, SW_SHOWDEFAULT); |
| 40 | + } |
| 41 | + } |
| 42 | + } |
| 43 | + else if(msg == WM_TIMER) |
| 44 | + { |
| 45 | + if(wParam == TIMER_ID) |
| 46 | + { |
| 47 | + KillTimer(hwnd, TIMER_ID); |
| 48 | + PostQuitMessage(0); |
| 49 | + } |
| 50 | + } |
| 51 | + else if(msg == WM_DESTROY) |
| 52 | + { |
| 53 | + PostQuitMessage(0); |
| 54 | + } |
| 55 | + return DefWindowProcA(hwnd, msg, wParam, lParam); |
| 56 | + }; |
| 57 | + wc.hInstance = GetModuleHandleA(nullptr); |
| 58 | + wc.lpszClassName = className.c_str(); |
| 59 | + RegisterClassA(&wc); |
| 60 | + HWND hwnd{ CreateWindowExA(0, className.c_str(), info.getShortName().c_str(), 0, 0, 0, 0, 0, nullptr, nullptr, GetModuleHandleA(nullptr), nullptr) }; |
| 61 | + if(!hwnd) |
| 62 | + { |
| 63 | + return; |
| 64 | + } |
| 65 | + HICON icn; |
| 66 | + ExtractIconExA(Environment::getExecutablePath().string().c_str(), 0, nullptr, &icn, 1); |
| 67 | + NOTIFYICONDATAA nid{}; |
| 68 | + nid.cbSize = sizeof(NOTIFYICONDATAA); |
| 69 | + nid.hWnd = hwnd; |
| 70 | + nid.uID = TRAYICON_ID; |
| 71 | + nid.uFlags = NIF_INFO | NIF_ICON | NIF_TIP | NIF_MESSAGE; |
| 72 | + nid.uCallbackMessage = WM_TRAYICON; |
| 73 | + nid.hIcon = icn ? icn : LoadIconA(nullptr, IDI_APPLICATION); |
| 74 | + switch(e.getSeverity()) |
| 75 | + { |
| 76 | + case NotificationSeverity::Error: |
| 77 | + nid.dwInfoFlags = NIIF_ERROR; |
| 78 | + break; |
| 79 | + case NotificationSeverity::Warning: |
| 80 | + nid.dwInfoFlags = NIIF_WARNING; |
| 81 | + break; |
| 82 | + default: |
| 83 | + nid.dwInfoFlags = NIIF_INFO; |
| 84 | + break; |
| 85 | + } |
| 86 | + strcpy_s(nid.szTip, info.getShortName().c_str()); |
| 87 | + strcpy_s(nid.szInfoTitle, e.getTitle().c_str()); |
| 88 | + strcpy_s(nid.szInfo, e.getMessage().c_str()); |
| 89 | + Shell_NotifyIconA(NIM_ADD, &nid); |
| 90 | + SetTimer(hwnd, TIMER_ID, 5000, nullptr); |
| 91 | + MSG msg; |
| 92 | + while(GetMessageA(&msg, nullptr, 0, 0)) |
| 93 | + { |
| 94 | + TranslateMessage(&msg); |
| 95 | + DispatchMessageA(&msg); |
| 96 | + } |
| 97 | + Shell_NotifyIconA(NIM_DELETE, &nid); |
| 98 | + if(icn) |
| 99 | + { |
| 100 | + DestroyIcon(icn); |
| 101 | + } |
| 102 | + } }; |
| 103 | + worker.detach(); |
96 | 104 | #else |
97 | 105 | std::string iconPath; |
98 | 106 | if(!Environment::hasVariable("SNAP")) |
|
0 commit comments