Allow querying capabilities of DBus notification daemon

This commit is contained in:
Martchus 2018-03-31 23:35:39 +02:00
parent 1f66e83209
commit 6727f97ac6
3 changed files with 123 additions and 12 deletions

View File

@ -8,7 +8,7 @@ set(META_APP_AUTHOR "Martchus")
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
set(META_APP_DESCRIPTION "Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models") set(META_APP_DESCRIPTION "Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models")
set(META_VERSION_MAJOR 5) set(META_VERSION_MAJOR 5)
set(META_VERSION_MINOR 9) set(META_VERSION_MINOR 10)
set(META_VERSION_PATCH 0) set(META_VERSION_PATCH 0)
set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}) set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH})

View File

@ -36,7 +36,7 @@ namespace MiscUtils {
/// \cond /// \cond
static std::map<uint, DBusNotification *> pendingNotifications; static std::map<uint, DBusNotification *> pendingNotifications;
OrgFreedesktopNotificationsInterface *DBusNotification::m_dbusInterface = nullptr; OrgFreedesktopNotificationsInterface *DBusNotification::s_dbusInterface = nullptr;
/// \endcond /// \endcond
/*! /*!
@ -186,11 +186,11 @@ DBusNotification::DBusNotification(const QString &title, const QString &icon, in
*/ */
void DBusNotification::initInterface() void DBusNotification::initInterface()
{ {
if (!m_dbusInterface) { if (!s_dbusInterface) {
m_dbusInterface = new OrgFreedesktopNotificationsInterface( s_dbusInterface = new OrgFreedesktopNotificationsInterface(
QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), QDBusConnection::sessionBus()); QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), QDBusConnection::sessionBus());
connect(m_dbusInterface, &OrgFreedesktopNotificationsInterface::ActionInvoked, &DBusNotification::handleActionInvoked); connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::ActionInvoked, &DBusNotification::handleActionInvoked);
connect(m_dbusInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, &DBusNotification::handleNotificationClosed); connect(s_dbusInterface, &OrgFreedesktopNotificationsInterface::NotificationClosed, &DBusNotification::handleNotificationClosed);
} }
} }
@ -212,7 +212,7 @@ DBusNotification::~DBusNotification()
bool DBusNotification::isAvailable() bool DBusNotification::isAvailable()
{ {
initInterface(); initInterface();
return m_dbusInterface->isValid(); return s_dbusInterface->isValid();
} }
/*! /*!
@ -273,14 +273,14 @@ void DBusNotification::deleteOnCloseOrError()
*/ */
bool DBusNotification::show() bool DBusNotification::show()
{ {
if (!m_dbusInterface->isValid()) { if (!s_dbusInterface->isValid()) {
emit error(); emit error();
return false; return false;
} }
delete m_watcher; delete m_watcher;
m_watcher = new QDBusPendingCallWatcher( m_watcher = new QDBusPendingCallWatcher(
m_dbusInterface->Notify(QCoreApplication::applicationName(), m_id, m_icon, m_title, m_msg, m_actions, m_hints, m_timeout), this); s_dbusInterface->Notify(QCoreApplication::applicationName(), m_id, m_icon, m_title, m_msg, m_actions, m_hints, m_timeout), this);
connect(m_watcher, &QDBusPendingCallWatcher::finished, this, &DBusNotification::handleNotifyResult); connect(m_watcher, &QDBusPendingCallWatcher::finished, this, &DBusNotification::handleNotifyResult);
return true; return true;
} }
@ -324,15 +324,38 @@ bool DBusNotification::update(const QString &line)
return show(); return show();
} }
bool DBusNotification::queryCapabilities(const std::function<void(Capabilities &&capabilities)> &callback)
{
// ensure DBus-interface is initialized and valid
initInterface();
if (!s_dbusInterface->isValid()) {
return false;
}
// invoke GetCapabilities() and pass the return value to the callback when available
const auto *const watcher = new QDBusPendingCallWatcher(s_dbusInterface->GetCapabilities());
connect(watcher, &QDBusPendingCallWatcher::finished, [&callback](QDBusPendingCallWatcher *watcher) {
watcher->deleteLater();
const QDBusPendingReply<QStringList> returnValue(*watcher);
if (returnValue.isError()) {
callback(Capabilities());
} else {
callback(Capabilities(move(returnValue.value())));
}
});
return true;
}
/*! /*!
* \brief Hides the notification (if still visible). * \brief Hides the notification (if still visible).
* \remarks On success, the signal closed() is emitted with the reason * \remarks On success, the signal closed() is emitted with the reason
* NotificationCloseReason::Manually. * NotificationCloseReason::Manually.
* \todo Add return value in v6.
*/ */
void DBusNotification::hide() void DBusNotification::hide()
{ {
if (m_id) { if (m_id) {
m_dbusInterface->CloseNotification(m_id); s_dbusInterface->CloseNotification(m_id);
} }
} }
@ -389,7 +412,7 @@ void DBusNotification::handleActionInvoked(uint id, const QString &action)
pendingNotifications.erase(i); pendingNotifications.erase(i);
// however, lxqt-notificationd does not close the notification // however, lxqt-notificationd does not close the notification
// -> close manually for consistent behaviour // -> close manually for consistent behaviour
m_dbusInterface->CloseNotification(i->first); s_dbusInterface->CloseNotification(i->first);
} }
} }

View File

@ -4,6 +4,7 @@
#include "../global.h" #include "../global.h"
#include <QObject> #include <QObject>
#include <QSet>
#include <QVariantMap> #include <QVariantMap>
QT_FORWARD_DECLARE_CLASS(QDBusPendingCallWatcher) QT_FORWARD_DECLARE_CLASS(QDBusPendingCallWatcher)
@ -26,6 +27,26 @@ class QT_UTILITIES_EXPORT DBusNotification : public QObject {
Q_PROPERTY(bool visible READ isVisible) Q_PROPERTY(bool visible READ isVisible)
public: public:
class QT_UTILITIES_EXPORT Capabilities : public QSet<QString> {
public:
explicit Capabilities();
explicit Capabilities(const QStringList &capabilities);
bool isValid() const;
bool supportsBody() const;
bool supportsLinks() const;
bool supportsMarkup() const;
bool supportsImages() const;
bool supportsIcon() const;
bool supportsActions() const;
bool supportsAnimatedIcon() const;
bool supportsActionIcons() const;
bool supportsSound() const;
bool supportsPercistence() const;
private:
bool m_valid;
};
explicit DBusNotification( explicit DBusNotification(
const QString &title, NotificationIcon icon = NotificationIcon::Information, int timeout = 10000, QObject *parent = nullptr); const QString &title, NotificationIcon icon = NotificationIcon::Information, int timeout = 10000, QObject *parent = nullptr);
explicit DBusNotification(const QString &title, const QString &icon, int timeout = 10000, QObject *parent = nullptr); explicit DBusNotification(const QString &title, const QString &icon, int timeout = 10000, QObject *parent = nullptr);
@ -53,6 +74,7 @@ public:
QVariant hint(const QString &name, const QString &fallbackNames...) const; QVariant hint(const QString &name, const QString &fallbackNames...) const;
bool isVisible() const; bool isVisible() const;
void deleteOnCloseOrError(); void deleteOnCloseOrError();
static bool queryCapabilities(const std::function<void(Capabilities &&capabilities)> &callback);
public Q_SLOTS: public Q_SLOTS:
bool show(); bool show();
@ -86,9 +108,75 @@ private:
int m_timeout; int m_timeout;
QStringList m_actions; QStringList m_actions;
QVariantMap m_hints; QVariantMap m_hints;
static OrgFreedesktopNotificationsInterface *m_dbusInterface; static OrgFreedesktopNotificationsInterface *s_dbusInterface;
}; };
inline DBusNotification::Capabilities::Capabilities()
: m_valid(false)
{
}
inline DBusNotification::Capabilities::Capabilities(const QStringList &capabilities)
: QSet<QString>(capabilities.toSet())
, m_valid(true)
{
}
inline bool DBusNotification::Capabilities::isValid() const
{
return m_valid;
}
inline bool DBusNotification::Capabilities::supportsBody() const
{
return contains(QStringLiteral("body"));
}
inline bool DBusNotification::Capabilities::supportsLinks() const
{
return contains(QStringLiteral("body-hyperlinks"));
}
inline bool DBusNotification::Capabilities::supportsMarkup() const
{
return contains(QStringLiteral("body-markup"));
}
inline bool DBusNotification::Capabilities::supportsImages() const
{
return contains(QStringLiteral("body-images"));
}
inline bool DBusNotification::Capabilities::supportsIcon() const
{
return contains(QStringLiteral("icon-static")) || supportsAnimatedIcon();
}
inline bool DBusNotification::Capabilities::supportsActions() const
{
return contains(QStringLiteral("actions"));
}
inline bool DBusNotification::Capabilities::supportsAnimatedIcon() const
{
return contains(QStringLiteral("icon-multi"));
}
inline bool DBusNotification::Capabilities::supportsActionIcons() const
{
return contains(QStringLiteral("action-icons"));
}
inline bool DBusNotification::Capabilities::supportsSound() const
{
return contains(QStringLiteral("sound"));
}
inline bool DBusNotification::Capabilities::supportsPercistence() const
{
return contains(QStringLiteral("persistence"));
}
inline const QString &DBusNotification::title() const inline const QString &DBusNotification::title() const
{ {
return m_title; return m_title;