Skip to content

Commit fcec21b

Browse files
authored
Merge pull request #67 from NickvisionApps/2025.5.0
V2025.5.0
2 parents 60047fc + fd53278 commit fcec21b

File tree

11 files changed

+139
-94
lines changed

11 files changed

+139
-94
lines changed

.github/workflows/linux.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
with:
4343
pkgs: boost-json curl gettext-libintl glib gtest libsecret maddy openssl
4444
triplet: x64-linux
45-
revision: 0d5cae153065957df7f382de7c1549ccc88027e5
45+
revision: 61c70ce627a2a4ffff809f887e4188ff39ce0a14
4646
token: ${{ secrets.GITHUB_TOKEN }}
4747
github-binarycache: true
4848
- name: "Build"

.github/workflows/macos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
with:
3232
pkgs: boost-json curl gettext-libintl glib gtest maddy openssl
3333
triplet: arm64-osx
34-
revision: 0d5cae153065957df7f382de7c1549ccc88027e5
34+
revision: 61c70ce627a2a4ffff809f887e4188ff39ce0a14
3535
token: ${{ secrets.GITHUB_TOKEN }}
3636
github-binarycache: true
3737
- name: "Build"

.github/workflows/windows.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ jobs:
2727
uses: johnwason/vcpkg-action@v6
2828
id: vcpkg
2929
with:
30-
pkgs: boost-json curl gettext-libintl gtest maddy sqlcipher wintoast
30+
pkgs: boost-json curl gettext-libintl gtest maddy sqlcipher
3131
triplet: x64-windows
32-
revision: 0d5cae153065957df7f382de7c1549ccc88027e5
32+
revision: 61c70ce627a2a4ffff809f887e4188ff39ce0a14
3333
token: ${{ secrets.GITHUB_TOKEN }}
3434
github-binarycache: true
3535
- name: "Build"

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## 2025.5.0
4+
### Breaking Changes
5+
#### Notifications
6+
- Removed dependency of `wintoast` on Windows
7+
### New APIs
8+
#### System
9+
- Added `Environment::getExecutablePath()` function
10+
### Fixes
11+
#### Notifications
12+
- Fixed an issue where `ShellNotifications::send()` did not work on Windows
13+
314
## 2025.3.6
415
### Breaking Changes
516
None

CMakeLists.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ endif()
2020
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
2121

2222
#libnick Definition
23-
project ("libnick" LANGUAGES C CXX VERSION 2025.3.6 DESCRIPTION "A cross-platform base for native Nickvision applications.")
23+
project ("libnick" LANGUAGES C CXX VERSION 2025.5.0 DESCRIPTION "A cross-platform base for native Nickvision applications.")
2424
include(CMakePackageConfigHelpers)
2525
include(GNUInstallDirs)
2626
include(CTest)
@@ -97,10 +97,6 @@ if(USING_VCPKG)
9797
target_link_libraries(${PROJECT_NAME} PRIVATE unofficial::maddy::maddy)
9898
endif()
9999
if(WIN32)
100-
if(USING_VCPKG)
101-
find_package(unofficial-wintoast CONFIG REQUIRED)
102-
target_link_libraries(${PROJECT_NAME} PRIVATE unofficial::wintoast::wintoast)
103-
endif()
104100
find_package(sqlcipher CONFIG REQUIRED)
105101
target_link_libraries(${PROJECT_NAME} PUBLIC sqlcipher::sqlcipher Advapi32 Dnsapi Dwmapi Gdiplus Kernel32 Shell32 UxTheme Ws2_32)
106102
elseif(APPLE)

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ The following are a list of dependencies used by libnick.
2323
### Windows
2424
The above dependencies must be installed, *plus* the following for Windows systems:
2525
- sqlcipher
26-
- wintoast
2726

2827
### Linux
2928
The above dependencies must be installed, *plus* the following for Linux systems:
@@ -63,7 +62,7 @@ A C++20 compiler is also required to build libnick.
6362
1. Set the `VCPKG_ROOT` environment variable to the path of your vcpkg installation's root directory.
6463
#### Windows
6564
1. Set the `VCPKG_DEFAULT_TRIPLET` environment variable to `x64-windows`
66-
1. Run `vcpkg install boost-json curl gettext-libintl gtest maddy sqlcipher wintoast`
65+
1. Run `vcpkg install boost-json curl gettext-libintl gtest maddy sqlcipher`
6766
#### Linux
6867
1. Set the `VCPKG_DEFAULT_TRIPLET` environment variable to `x64-linux`
6968
1. Run `vcpkg install boost-json curl gettext-libintl glib gtest libsecret maddy openssl`

cmake/config.cmake.in

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ if(USING_VCPKG)
2121
find_dependency(unofficial-maddy REQUIRED)
2222
endif()
2323
if(WIN32)
24-
if(USING_VCPKG)
25-
find_dependency(unofficial-wintoast CONFIG REQUIRED)
26-
endif()
2724
find_dependency(sqlcipher CONFIG REQUIRED)
2825
elseif(APPLE)
2926
find_library(CF_LIBRARY CoreFoundation)

include/notifications/shellnotification.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ namespace Nickvision::Notifications::ShellNotification
3939
* @param e ShellNotificationSentEventArgs
4040
* @param info The application information
4141
* @param openText Localized text of "Open"
42+
* @return True if notification sent
43+
* @return False if notification not sent
4244
*/
43-
void send(const ShellNotificationSentEventArgs& e, const App::AppInfo& info, const std::string& openText);
45+
void send(const ShellNotificationSentEventArgs& e, const App::AppInfo& info, const std::string& openText = "");
4446
}
4547

4648
#endif //SHELLNOTIFICATION_H

include/system/environment.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ namespace Nickvision::System::Environment
6262
* @return The executable's directory path
6363
*/
6464
const std::filesystem::path& getExecutableDirectory();
65+
/**
66+
* @brief Gets the path of the executable file.
67+
* @return The executable file's path
68+
*/
69+
const std::filesystem::path& getExecutablePath();
6570
/**
6671
* @brief Gets the name of the current locale.
6772
* @return The locale name
@@ -127,4 +132,4 @@ namespace Nickvision::System::Environment
127132
std::string getDebugInformation(const App::AppInfo& appInfo, const std::string& extraInformation = "");
128133
}
129134

130-
#endif //ENVIRONMENT_H
135+
#endif //ENVIRONMENT_H

src/notifications/shellnotification.cpp

Lines changed: 85 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,106 @@
11
#include "notifications/shellnotification.h"
22
#include <filesystem>
3-
#include <memory>
4-
#include <string>
53
#include <thread>
6-
#include "helpers/stringhelpers.h"
74
#include "system/environment.h"
85
#ifdef _WIN32
9-
#include <wintoastlib.h>
6+
#include <windows.h>
7+
#include <shellapi.h>
108
#else
119
#include <gio/gio.h>
1210
#endif
1311

14-
using namespace Nickvision::App;
15-
using namespace Nickvision::Helpers;
16-
using namespace Nickvision::System;
17-
1812
#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
6716
#endif
6817

18+
using namespace Nickvision::App;
19+
using namespace Nickvision::System;
20+
6921
namespace Nickvision::Notifications
7022
{
7123
void ShellNotification::send(const ShellNotificationSentEventArgs& e, const AppInfo& info, const std::string& openText)
7224
{
7325
#ifdef _WIN32
74-
WinToast::WinToastError err;
75-
static bool initialized{ false };
76-
if(!initialized)
26+
std::thread worker{ [e, info]()
7727
{
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();
96104
#else
97105
std::string iconPath;
98106
if(!Environment::hasVariable("SNAP"))

0 commit comments

Comments
 (0)