Qt Utilities  5.6.0
Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models
dbusnotification.cpp
Go to the documentation of this file.
1 #include "./dbusnotification.h"
2 #include "notificationsinterface.h"
3 
4 #include <QCoreApplication>
5 #include <QDBusConnection>
6 #include <QDBusPendingReply>
7 
8 #include <map>
9 
10 using namespace std;
11 
12 namespace MiscUtils {
13 
31 static std::map<uint, DBusNotification *> pendingNotifications;
33 OrgFreedesktopNotificationsInterface *DBusNotification::m_dbusInterface = nullptr;
35 
39 DBusNotification::DBusNotification(const QString &title, NotificationIcon icon, int timeout, QObject *parent) :
40  QObject(parent),
41  m_id(0),
42  m_watcher(nullptr),
43  m_title(title),
44  m_timeout(timeout)
45 {
46  initInterface();
47  setIcon(icon);
48 }
49 
53 DBusNotification::DBusNotification(const QString &title, const QString &icon, int timeout, QObject *parent) :
54  QObject(parent),
55  m_id(0),
56  m_watcher(nullptr),
57  m_title(title),
58  m_icon(icon),
59  m_timeout(timeout)
60 {
61  initInterface();
62 }
63 
67 void DBusNotification::initInterface()
68 {
69  if(!m_dbusInterface) {
70  m_dbusInterface = new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), QDBusConnection::sessionBus());
71  connect(m_dbusInterface, &OrgFreedesktopNotificationsInterface::ActionInvoked, &DBusNotification::handleActionInvoked);
72  connect(m_dbusInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, &DBusNotification::handleNotificationClosed);
73  }
74 }
75 
80 {
81  auto i = pendingNotifications.find(m_id);
82  if(i != pendingNotifications.end()) {
83  pendingNotifications.erase(i);
84  }
85  hide();
86 }
87 
92 {
93  initInterface();
94  return m_dbusInterface->isValid();
95 }
96 
101 {
102  switch(icon) {
104  m_icon = QStringLiteral("dialog-information"); break;
106  m_icon = QStringLiteral("dialog-warning"); break;
108  m_icon = QStringLiteral("dialog-critical"); break;
109  default:
110  ;
111  }
112 }
113 
118 {
119  connect(this, &DBusNotification::closed, this, &DBusNotification::deleteLater);
120  connect(this, &DBusNotification::error, this, &DBusNotification::deleteLater);
121 }
122 
129 {
130  if(!m_dbusInterface->isValid()) {
131  emit error();
132  return false;
133  }
134 
135  delete m_watcher;
136  m_watcher = new QDBusPendingCallWatcher(m_dbusInterface->Notify(QCoreApplication::applicationName(), m_id, m_icon, m_title, m_msg, m_actions, m_hints, m_timeout), this);
137  connect(m_watcher, &QDBusPendingCallWatcher::finished, this, &DBusNotification::handleNotifyResult);
138  return true;
139 }
140 
146 bool DBusNotification::show(const QString &message)
147 {
148  m_msg = message;
149  return show();
150 }
151 
161 bool DBusNotification::update(const QString &line)
162 {
163  if(!isVisible() || m_msg.isEmpty()) {
164  m_msg = line;
165  } else {
166  if(!m_msg.startsWith(QStringLiteral("•"))) {
167  m_msg.insert(0, QStringLiteral("• "));
168  }
169  m_msg.append(QStringLiteral("\n• "));
170  m_msg.append(line);
171  }
172  return show();
173 }
174 
180 {
181  if(m_id) {
182  m_dbusInterface->CloseNotification(m_id);
183  }
184 }
185 
189 void DBusNotification::handleNotifyResult(QDBusPendingCallWatcher *watcher)
190 {
191  if(watcher != m_watcher) {
192  return;
193  }
194 
195  watcher->deleteLater();
196  m_watcher = nullptr;
197 
198  QDBusPendingReply<uint> returnValue = *watcher;
199  if (returnValue.isError()) {
200  deleteLater();
201  emit error();
202  } else {
203  pendingNotifications[m_id = returnValue.argumentAt<0>()] = this;
204  emit shown();
205  }
206 }
207 
211 void DBusNotification::handleNotificationClosed(uint id, uint reason)
212 {
213  auto i = pendingNotifications.find(id);
214  if(i != pendingNotifications.end()) {
215  DBusNotification *notification = i->second;
216  notification->m_id = 0;
217  emit notification->closed(reason >= 1 && reason <= 3 ? static_cast<NotificationCloseReason>(reason) : NotificationCloseReason::Undefined);
218  pendingNotifications.erase(i);
219  }
220 }
221 
225 void DBusNotification::handleActionInvoked(uint id, const QString &action)
226 {
227  auto i = pendingNotifications.find(id);
228  if(i != pendingNotifications.end()) {
229  DBusNotification *notification = i->second;
230  emit notification->actionInvoked(action);
231  // Plasma 5 also closes the notification but doesn't emit the NotificationClose signal
232  // -> just consider the notification closed
234  notification->m_id = 0;
235  pendingNotifications.erase(i);
236  // however, lxqt-notificationd does not close the notification
237  // -> close manually for consistent behaviour
238  m_dbusInterface->CloseNotification(i->first);
239  }
240 }
241 
290 }
void setIcon(const QString &icon)
Sets the icon name.
void closed(NotificationCloseReason reason)
Emitted when the notification has been closed.
const QString & title() const
bool update(const QString &line)
Updates the message and shows/updates the notification.
STL namespace.
void hide()
Hides the notification (if still visible).
void shown()
Emitted when the notification could be shown successful.
static bool isAvailable()
Returns whether the notification D-Bus daemon is running.
bool isVisible() const
Returns whether the notification is (still) visible.
DBusNotification(const QString &title, NotificationIcon icon=NotificationIcon::Information, int timeout=10000, QObject *parent=nullptr)
Creates a new notification (which is not shown instantly).
bool show()
Shows the notification.
void error()
Emitted when the notification couldn&#39;t be shown.
void actionInvoked(const QString &action)
Emitted when action has been invoked.
~DBusNotification()
Closes the notification if still shown and delete the object.
The DBusNotification class emits D-Bus notifications.
void deleteOnCloseOrError()
Makes the notification object delete itself when the notification has been closed or an error occured...
const QString & icon() const
const QString & message() const