Skip to content

Commit bc83e4b

Browse files
Clear native notifications in tests
Add platform-specific notification cleanup for tests and tidy docs. Implement Windows toast history clearing (RoInitialize, WindowsCreateString, RoGetActivationFactory + IToastNotificationHistory::Clear) and include necessary WinRT headers (with correct include order). Keep Linux desktop cleanup in namespace. Replace the long Windows test sleep with a call to dismissNativeNotifications(), and shorten wait logic. Also add 'runtimeobject' to WIN32 test link libs in CMakeLists and simplify README icon docs to a single supported-formats line.
1 parent 6fdb6b6 commit bc83e4b

3 files changed

Lines changed: 69 additions & 9 deletions

File tree

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,7 @@ The `icon` and `notification_icon` fields can be a path to an image file or an i
133133
are resolved from the process working directory, so applications should copy or install icon files where the running
134134
process can find them.
135135

136-
| Component | Backend | Supported inputs | Notes |
137-
|-----------------------------------------|--------------------------------------------------------------|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
138-
| Tray icon (`icon`) | Qt `QSystemTrayIcon` / `QIcon` on all platforms | SVG, ICO, PNG, Qt theme icon names | Loaded through Qt's `QIcon` path; SVG, ICO, and PNG are tested. Theme icon names are resolved by Qt when the platform/theme supports them. |
139-
| Notification icon (`notification_icon`) | Qt `QSystemTrayIcon::showMessage` / `QIcon` on all platforms | SVG, ICO, PNG, Qt theme icon names | Loaded through Qt's `QIcon` path; SVG, ICO, and PNG are tested. Theme icon names are resolved by Qt when the platform/theme supports them. |
136+
SVG, ICO, PNG, and Qt theme icon names are supported.
140137

141138
For the most predictable cross-platform behavior, use SVG or PNG files for both tray and notification icons. ICO is
142139
supported by the Qt-backed paths tested by this project.

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ include_directories("${GTEST_SOURCE_DIR}/googletest/include" "${GTEST_SOURCE_DIR
2020
if (APPLE)
2121
set(TEST_LIBS "-framework Cocoa")
2222
elseif (WIN32)
23-
set(TEST_LIBS gdi32 gdiplus)
23+
set(TEST_LIBS gdi32 gdiplus runtimeobject)
2424
endif()
2525

2626
file(GLOB_RECURSE TEST_SOURCES

tests/utils.cpp

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,69 @@
88
// standard includes
99
#include <chrono>
1010
#include <cstdlib>
11+
#include <cwchar>
1112
#include <thread>
1213

13-
#ifdef __linux__
14+
#ifdef _WIN32
15+
// build fails if windows.ui.notifications.h is included before roapi.h
16+
#include <roapi.h>
17+
// clang-format off
18+
#include <windows.ui.notifications.h>
19+
// clang-format on
20+
#include <winstring.h>
21+
#endif
22+
23+
#if defined(_WIN32) || defined(__linux__)
1424
namespace {
25+
#ifdef _WIN32
26+
namespace notifications = ABI::Windows::UI::Notifications;
27+
28+
void clearToastNotificationHistory() {
29+
const HRESULT init_result = RoInitialize(RO_INIT_MULTITHREADED);
30+
const bool should_uninitialize = SUCCEEDED(init_result);
31+
32+
HSTRING class_id = nullptr;
33+
HRESULT result = WindowsCreateString(
34+
RuntimeClass_Windows_UI_Notifications_ToastNotificationManager,
35+
static_cast<UINT32>(std::wcslen(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager)),
36+
&class_id
37+
);
38+
if (FAILED(result)) {
39+
if (should_uninitialize) {
40+
RoUninitialize();
41+
}
42+
return;
43+
}
44+
45+
notifications::IToastNotificationManagerStatics2 *manager = nullptr;
46+
result = RoGetActivationFactory(
47+
class_id,
48+
__uuidof(notifications::IToastNotificationManagerStatics2),
49+
reinterpret_cast<void **>(&manager)
50+
);
51+
WindowsDeleteString(class_id);
52+
if (FAILED(result) || manager == nullptr) {
53+
if (should_uninitialize) {
54+
RoUninitialize();
55+
}
56+
return;
57+
}
58+
59+
notifications::IToastNotificationHistory *history = nullptr;
60+
result = manager->get_History(&history);
61+
manager->Release();
62+
if (SUCCEEDED(result) && history != nullptr) {
63+
(void) history->Clear();
64+
history->Release();
65+
}
66+
67+
if (should_uninitialize) {
68+
RoUninitialize();
69+
}
70+
}
71+
#endif
72+
73+
#ifdef __linux__
1574
void closeFreedesktopNotifications() {
1675
constexpr const char *close_notifications =
1776
"if command -v dbus-send >/dev/null 2>&1; then "
@@ -24,6 +83,7 @@ namespace {
2483
"fi";
2584
(void) std::system(close_notifications); // NOSONAR(cpp:S4721) - test-only cleanup of desktop notifications
2685
}
86+
#endif
2787
} // namespace
2888
#endif
2989

@@ -42,7 +102,11 @@ int setEnv(const std::string &name, const std::string &value) {
42102
}
43103

44104
void dismissNativeNotifications() {
45-
#ifdef __linux__
105+
#ifdef _WIN32
106+
clearToastNotificationHistory();
107+
constexpr auto wait_timeout = std::chrono::milliseconds(500);
108+
std::this_thread::sleep_for(wait_timeout);
109+
#elif defined(__linux__)
46110
closeFreedesktopNotifications();
47111
constexpr auto wait_timeout = std::chrono::milliseconds(500);
48112
std::this_thread::sleep_for(wait_timeout);
@@ -51,8 +115,7 @@ void dismissNativeNotifications() {
51115

52116
void waitForNativeNotificationTimeout() {
53117
#ifdef _WIN32
54-
constexpr auto wait_timeout = std::chrono::milliseconds(6000);
55-
std::this_thread::sleep_for(wait_timeout);
118+
dismissNativeNotifications();
56119
#elif defined(__linux__)
57120
dismissNativeNotifications();
58121
#endif

0 commit comments

Comments
 (0)