Protect pending DBusNotifications from concurrent access

This commit is contained in:
Martchus 2019-08-03 16:26:54 +02:00
parent 8de2d7f7c8
commit 9ba1aa32cf
1 changed files with 24 additions and 13 deletions

View File

@ -5,6 +5,8 @@
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusPendingReply> #include <QDBusPendingReply>
#include <QImage> #include <QImage>
#include <QMutex>
#include <QMutexLocker>
#include <map> #include <map>
@ -17,24 +19,25 @@ namespace QtUtilities {
* \brief The DBusNotification class emits D-Bus notifications. * \brief The DBusNotification class emits D-Bus notifications.
* *
* D-Bus notifications are only available if the library has been compiled with * D-Bus notifications are only available if the library has been compiled with
* support for it by specifying * support for it by specifying CMake option `DBUS_NOTIFICATIONS`. If support is
* CMake option `DBUS_NOTIFICATIONS`. If support is available, the macro * available, the macro `QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS` is defined.
* `QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS`
* is defined.
* *
* **Usage** * **Usage**
* *
* First create a new instance. The constructor allows to set basic parameters. * First create a new instance. The constructor allows to set basic parameters.
* To set more parameters, use * To set more parameters, use setter methods. Call show() to actually show the
* setter methods. Call show() to actually show the notification. This method * notification. This method can also be used to update the currently shown notification
* can also be used to update * (it will not be updated automatically by just using the setter methods).
* the currently shown notification (it will not be updated automatically by *
* just using the setter methods). * Instances of this class share static data. So do not call the member functions
* from different threads without proper synchronization - even if using different
* instances. The destructor is safe to call, though.
* *
* \sa https://developer.gnome.org/notification-spec * \sa https://developer.gnome.org/notification-spec
*/ */
/// \cond /// \cond
static QMutex pendingNotificationsMutex;
static std::map<uint, DBusNotification *> pendingNotifications; static std::map<uint, DBusNotification *> pendingNotifications;
OrgFreedesktopNotificationsInterface *DBusNotification::s_dbusInterface = nullptr; OrgFreedesktopNotificationsInterface *DBusNotification::s_dbusInterface = nullptr;
/// \endcond /// \endcond
@ -193,9 +196,12 @@ void DBusNotification::initInterface()
*/ */
DBusNotification::~DBusNotification() DBusNotification::~DBusNotification()
{ {
auto i = pendingNotifications.find(m_id); {
if (i != pendingNotifications.end()) { QMutexLocker lock(&pendingNotificationsMutex);
pendingNotifications.erase(i); auto i = pendingNotifications.find(m_id);
if (i != pendingNotifications.end()) {
pendingNotifications.erase(i);
}
} }
hide(); hide();
} }
@ -373,7 +379,10 @@ void DBusNotification::handleNotifyResult(QDBusPendingCallWatcher *watcher)
deleteLater(); deleteLater();
emit error(); emit error();
} else { } else {
pendingNotifications[m_id = returnValue.argumentAt<0>()] = this; {
QMutexLocker lock(&pendingNotificationsMutex);
pendingNotifications[m_id = returnValue.argumentAt<0>()] = this;
}
emit shown(); emit shown();
} }
} }
@ -383,6 +392,7 @@ void DBusNotification::handleNotifyResult(QDBusPendingCallWatcher *watcher)
*/ */
void DBusNotification::handleNotificationClosed(uint id, uint reason) void DBusNotification::handleNotificationClosed(uint id, uint reason)
{ {
QMutexLocker lock(&pendingNotificationsMutex);
auto i = pendingNotifications.find(id); auto i = pendingNotifications.find(id);
if (i != pendingNotifications.end()) { if (i != pendingNotifications.end()) {
DBusNotification *notification = i->second; DBusNotification *notification = i->second;
@ -397,6 +407,7 @@ void DBusNotification::handleNotificationClosed(uint id, uint reason)
*/ */
void DBusNotification::handleActionInvoked(uint id, const QString &action) void DBusNotification::handleActionInvoked(uint id, const QString &action)
{ {
QMutexLocker lock(&pendingNotificationsMutex);
auto i = pendingNotifications.find(id); auto i = pendingNotifications.find(id);
if (i != pendingNotifications.end()) { if (i != pendingNotifications.end()) {
DBusNotification *notification = i->second; DBusNotification *notification = i->second;