diff --git a/src/tray_linux.cpp b/src/tray_linux.cpp index 3cdb7c4..3334e76 100644 --- a/src/tray_linux.cpp +++ b/src/tray_linux.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include // lib includes @@ -22,36 +21,17 @@ namespace tray_linux { /** - * Notification element struct + * Currently shown notification object */ - struct notification_data { - /** - * @brief Notification object - */ - NotifyNotification *obj = nullptr; - /** - * @brief Notification callback - */ - void (*cb)() = nullptr; - /** - * @brief Notification shown indicator - */ - bool shown = false; - /** - * @brief Notification mutex for async thread synchronization - */ - std::mutex mutex; - }; - + NotifyNotification *notification_current = nullptr; // NOSONAR(cpp:S5421) - mutable state, not const /** - * Currently shown notifications + * Currently shown notification callback */ - std::vector> notifications; // NOSONAR(cpp:S5421) - mutable state, not const + void (*notification_current_callback)() = nullptr; // NOSONAR(cpp:S5421) - mutable state, not const /** - * Lock for currently shown notifications vector + * Lock for currently shown notification/callback */ - std::mutex notifications_mutex; // NOSONAR(cpp:S5421) - mutable state, not const - + std::mutex notification_mutex; // NOSONAR(cpp:S5421) - mutable state, not const /** * QtTrayMenu instance */ @@ -62,64 +42,34 @@ namespace tray_linux { void (*log_callback)(int, const char *) = nullptr; // NOSONAR(cpp:S5421) - mutable state, not const /** - * @brief Show notification asynchronously with timeout to avoid Dbus lockups - * @param notification - Tray notification to show - * @param timeout - optional timeout for async run in ms (default: 1000) - * @return true if notification was successfully shown - */ - bool async_tray_notification_show_(const std::shared_ptr ¬ification, int timeout = 1000) { - std::thread t([notification]() { // NOSONAR(cpp:S6168) - jthread is only available on C++20 onwards - std::scoped_lock lock(notification->mutex); - if (notification->obj != nullptr && NOTIFY_IS_NOTIFICATION(notification->obj) && notify_notification_show(notification->obj, nullptr)) { - notification->shown = true; - } - }); - t.detach(); // NOSONAR(cpp:S5962) - while (!notification->shown && timeout > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - timeout -= 10; - } - return notification->shown; - } - - /** - * @brief Acknowledge notification asynchronously with timeout to avoid Dbus lockups - * @param notification - Tray notification to close - * @param timeout - optional timeout for async run in ms (default: 1000) - * @return true if notification was successfully closed + * @brief Initialize notifications + * @param app_name application name for notifications + * @return true if successful */ - bool async_tray_notification_acknowledge_(const std::shared_ptr ¬ification, int timeout = 1000) { - std::thread t([notification]() { // NOSONAR(cpp:S6168) - jthread is only available on C++20 onwards - std::scoped_lock lock(notification->mutex); - if (notification->obj != nullptr && NOTIFY_IS_NOTIFICATION(notification->obj) && notify_notification_close(notification->obj, nullptr)) { - notification->shown = false; - g_object_unref(G_OBJECT(notification->obj)); - notification->obj = nullptr; - notification->cb = nullptr; - } - }); - t.detach(); // NOSONAR(cpp:S5962) - while (notification->obj != nullptr && timeout > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - timeout -= 10; + bool init_notify(const char *app_name) { + if (!notify_is_initted()) { + std::scoped_lock lock(notification_mutex); + return notify_init(app_name); } - return notification->obj == nullptr; + return true; // Already initialized, so init was successful } /** - * @brief Acknowledge/click current notifications + * @brief Acknowledge/click current notification * @param run_callback - Run notification callback when acknowledging */ - void acknowledge_notifications(bool run_callback = false) { + void acknowledge_notification(const bool run_callback = false) { if (notify_is_initted()) { - std::scoped_lock lock(notifications_mutex); - for (auto notification : notifications) { - if (run_callback && notification->cb != nullptr) { - notification->cb(); + std::scoped_lock lock(notification_mutex); + if (notification_current != nullptr && NOTIFY_IS_NOTIFICATION(notification_current)) { + if (run_callback && notification_current_callback != nullptr) { + notification_current_callback(); } - async_tray_notification_acknowledge_(notification); + notify_notification_close(notification_current, nullptr); + g_object_unref(G_OBJECT(notification_current)); + notification_current = nullptr; + notification_current_callback = nullptr; } - notifications.clear(); } else if (qt_tray_menu != nullptr && QtTrayMenu::supportsMessages()) { qt_tray_menu->clickMessage(); } @@ -135,24 +85,22 @@ namespace tray_linux { } // Try to notify using libnotify if (notify_is_initted()) { - std::scoped_lock lock(notifications_mutex); - if (!notifications.empty()) { - acknowledge_notifications(); + if (notification_current != nullptr) { + acknowledge_notification(); } + std::scoped_lock lock(notification_mutex); std::filesystem::path notification_icon = tray->notification_icon != nullptr ? tray->notification_icon : tray->icon; if (std::filesystem::exists(notification_icon)) { // Use absolute path for filesystem icon files, not a relative one notification_icon = std::filesystem::absolute(notification_icon); } - auto notification = std::make_shared(); - notification->obj = notify_notification_new(tray->notification_title, tray->notification_text, notification_icon.c_str()); - if (notification->obj != nullptr && NOTIFY_IS_NOTIFICATION(notification->obj)) { + notification_current = notify_notification_new(tray->notification_title, tray->notification_text, notification_icon.c_str()); + if (notification_current != nullptr && NOTIFY_IS_NOTIFICATION(notification_current)) { if (tray->notification_cb != nullptr) { - notification->cb = tray->notification_cb; - notify_notification_add_action(notification->obj, "default", "Default", NOTIFY_ACTION_CALLBACK(tray->notification_cb), nullptr, nullptr); + notification_current_callback = tray->notification_cb; + notify_notification_add_action(notification_current, "default", "Default", NOTIFY_ACTION_CALLBACK(tray->notification_cb), nullptr, nullptr); } - notifications.emplace_back(notification); - if (async_tray_notification_show_(notification)) { + if (notify_notification_show(notification_current, nullptr)) { return; } } @@ -163,27 +111,13 @@ namespace tray_linux { } } - /** - * @brief Initialize notifications - * @param app_name application name for notifications - * @return true if successful - */ - bool init_notify(const char *app_name) { - if (!notify_is_initted()) { - if (!notifications.empty()) { - acknowledge_notifications(); - } - return notify_init(app_name); - } - return true; // Already initialized, so init was successful - } - /** * @brief Uninitialize notifications */ void uninit_notify() { if (notify_is_initted()) { - acknowledge_notifications(); + acknowledge_notification(); + std::scoped_lock lock(notification_mutex); notify_uninit(); } } @@ -311,6 +245,6 @@ extern "C" { } void tray_simulate_notification_click(void) { - tray_linux::acknowledge_notifications(true); + tray_linux::acknowledge_notification(true); } } // extern "C"