1010#include < memory>
1111#include < mutex>
1212#include < string>
13- #include < thread>
1413#include < utility>
1514
1615// lib includes
2221
2322namespace tray_linux {
2423 /* *
25- * Notification element struct
24+ * Currently shown notification object
2625 */
27- struct notification_data {
28- /* *
29- * @brief Notification object
30- */
31- NotifyNotification *obj = nullptr ;
32- /* *
33- * @brief Notification callback
34- */
35- void (*cb)() = nullptr ;
36- /* *
37- * @brief Notification shown indicator
38- */
39- bool shown = false ;
40- /* *
41- * @brief Notification mutex for async thread synchronization
42- */
43- std::mutex mutex;
44- };
45-
26+ NotifyNotification *notification_current = nullptr ; // NOSONAR(cpp:S5421) - mutable state, not const
4627 /* *
47- * Currently shown notifications
28+ * Currently shown notification callback
4829 */
49- std::vector<std::shared_ptr<notification_data>> notifications ; // NOSONAR(cpp:S5421) - mutable state, not const
30+ void (*notification_current_callback)() = nullptr ; // NOSONAR(cpp:S5421) - mutable state, not const
5031 /* *
51- * Lock for currently shown notifications vector
32+ * Lock for currently shown notification/callback
5233 */
53- std::mutex notifications_mutex; // NOSONAR(cpp:S5421) - mutable state, not const
54-
34+ std::mutex notification_mutex; // NOSONAR(cpp:S5421) - mutable state, not const
5535 /* *
5636 * QtTrayMenu instance
5737 */
@@ -62,64 +42,34 @@ namespace tray_linux {
6242 void (*log_callback)(int , const char *) = nullptr ; // NOSONAR(cpp:S5421) - mutable state, not const
6343
6444 /* *
65- * @brief Show notification asynchronously with timeout to avoid Dbus lockups
66- * @param notification - Tray notification to show
67- * @param timeout - optional timeout for async run in ms (default: 1000)
68- * @return true if notification was successfully shown
69- */
70- bool async_tray_notification_show_ (const std::shared_ptr<notification_data> ¬ification, int timeout = 1000 ) {
71- std::thread t ([notification]() { // NOSONAR(cpp:S6168) - jthread is only available on C++20 onwards
72- std::scoped_lock lock (notification->mutex );
73- if (notification->obj != nullptr && NOTIFY_IS_NOTIFICATION (notification->obj ) && notify_notification_show (notification->obj , nullptr )) {
74- notification->shown = true ;
75- }
76- });
77- t.detach (); // NOSONAR(cpp:S5962)
78- while (!notification->shown && timeout > 0 ) {
79- std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
80- timeout -= 10 ;
81- }
82- return notification->shown ;
83- }
84-
85- /* *
86- * @brief Acknowledge notification asynchronously with timeout to avoid Dbus lockups
87- * @param notification - Tray notification to close
88- * @param timeout - optional timeout for async run in ms (default: 1000)
89- * @return true if notification was successfully closed
45+ * @brief Initialize notifications
46+ * @param app_name application name for notifications
47+ * @return true if successful
9048 */
91- bool async_tray_notification_acknowledge_ (const std::shared_ptr<notification_data> ¬ification, int timeout = 1000 ) {
92- std::thread t ([notification]() { // NOSONAR(cpp:S6168) - jthread is only available on C++20 onwards
93- std::scoped_lock lock (notification->mutex );
94- if (notification->obj != nullptr && NOTIFY_IS_NOTIFICATION (notification->obj ) && notify_notification_close (notification->obj , nullptr )) {
95- notification->shown = false ;
96- g_object_unref (G_OBJECT (notification->obj ));
97- notification->obj = nullptr ;
98- notification->cb = nullptr ;
99- }
100- });
101- t.detach (); // NOSONAR(cpp:S5962)
102- while (notification->obj != nullptr && timeout > 0 ) {
103- std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
104- timeout -= 10 ;
49+ bool init_notify (const char *app_name) {
50+ if (!notify_is_initted ()) {
51+ std::scoped_lock lock (notification_mutex);
52+ return notify_init (app_name);
10553 }
106- return notification-> obj == nullptr ;
54+ return true ; // Already initialized, so init was successful
10755 }
10856
10957 /* *
110- * @brief Acknowledge/click current notifications
58+ * @brief Acknowledge/click current notification
11159 * @param run_callback - Run notification callback when acknowledging
11260 */
113- void acknowledge_notifications ( bool run_callback = false ) {
61+ void acknowledge_notification ( const bool run_callback = false ) {
11462 if (notify_is_initted ()) {
115- std::scoped_lock lock (notifications_mutex );
116- for ( auto notification : notifications ) {
117- if (run_callback && notification-> cb != nullptr ) {
118- notification-> cb ();
63+ std::scoped_lock lock (notification_mutex );
64+ if (notification_current != nullptr && NOTIFY_IS_NOTIFICATION (notification_current) ) {
65+ if (run_callback && notification_current_callback != nullptr ) {
66+ notification_current_callback ();
11967 }
120- async_tray_notification_acknowledge_ (notification);
68+ notify_notification_close (notification_current, nullptr );
69+ g_object_unref (G_OBJECT (notification_current));
70+ notification_current = nullptr ;
71+ notification_current_callback = nullptr ;
12172 }
122- notifications.clear ();
12373 } else if (qt_tray_menu != nullptr && QtTrayMenu::supportsMessages ()) {
12474 qt_tray_menu->clickMessage ();
12575 }
@@ -135,24 +85,22 @@ namespace tray_linux {
13585 }
13686 // Try to notify using libnotify
13787 if (notify_is_initted ()) {
138- std::scoped_lock lock (notifications_mutex);
139- if (!notifications.empty ()) {
140- acknowledge_notifications ();
88+ if (notification_current != nullptr ) {
89+ acknowledge_notification ();
14190 }
91+ std::scoped_lock lock (notification_mutex);
14292 std::filesystem::path notification_icon = tray->notification_icon != nullptr ? tray->notification_icon : tray->icon ;
14393 if (std::filesystem::exists (notification_icon)) {
14494 // Use absolute path for filesystem icon files, not a relative one
14595 notification_icon = std::filesystem::absolute (notification_icon);
14696 }
147- auto notification = std::make_shared<struct notification_data >();
148- notification->obj = notify_notification_new (tray->notification_title , tray->notification_text , notification_icon.c_str ());
149- if (notification->obj != nullptr && NOTIFY_IS_NOTIFICATION (notification->obj )) {
97+ notification_current = notify_notification_new (tray->notification_title , tray->notification_text , notification_icon.c_str ());
98+ if (notification_current != nullptr && NOTIFY_IS_NOTIFICATION (notification_current)) {
15099 if (tray->notification_cb != nullptr ) {
151- notification-> cb = tray->notification_cb ;
152- notify_notification_add_action (notification-> obj , " default" , " Default" , NOTIFY_ACTION_CALLBACK (tray->notification_cb ), nullptr , nullptr );
100+ notification_current_callback = tray->notification_cb ;
101+ notify_notification_add_action (notification_current , " default" , " Default" , NOTIFY_ACTION_CALLBACK (tray->notification_cb ), nullptr , nullptr );
153102 }
154- notifications.emplace_back (notification);
155- if (async_tray_notification_show_ (notification)) {
103+ if (notify_notification_show (notification_current, nullptr )) {
156104 return ;
157105 }
158106 }
@@ -163,27 +111,13 @@ namespace tray_linux {
163111 }
164112 }
165113
166- /* *
167- * @brief Initialize notifications
168- * @param app_name application name for notifications
169- * @return true if successful
170- */
171- bool init_notify (const char *app_name) {
172- if (!notify_is_initted ()) {
173- if (!notifications.empty ()) {
174- acknowledge_notifications ();
175- }
176- return notify_init (app_name);
177- }
178- return true ; // Already initialized, so init was successful
179- }
180-
181114 /* *
182115 * @brief Uninitialize notifications
183116 */
184117 void uninit_notify () {
185118 if (notify_is_initted ()) {
186- acknowledge_notifications ();
119+ acknowledge_notification ();
120+ std::scoped_lock lock (notification_mutex);
187121 notify_uninit ();
188122 }
189123 }
@@ -311,6 +245,6 @@ extern "C" {
311245 }
312246
313247 void tray_simulate_notification_click (void ) {
314- tray_linux::acknowledge_notifications (true );
248+ tray_linux::acknowledge_notification (true );
315249 }
316250} // extern "C"
0 commit comments