Browse Source
Make notifications clickable on Linux by assigning "default" action. Don't react to unrelated notifications clicked by keeping track of qBittorrent notifications IDs and filter out unrelated ones. Make D-Bus Notifications interface proxy class to be maintained manually and fix coding style in it. Closes #9084. PR #17282.adaptive-webui-19844
Vladimir Golovnev
2 years ago
committed by
GitHub
11 changed files with 339 additions and 172 deletions
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent. |
||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* In addition, as a special exception, the copyright holders give permission to |
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||
* modified versions of it that use the same license as the "OpenSSL" library), |
||||
* and distribute the linked executables. You must obey the GNU General Public |
||||
* License in all respects for all of the code used other than "OpenSSL". If you |
||||
* modify file(s), you may extend this exception to your version of the file(s), |
||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||
* exception statement from your version. |
||||
*/ |
||||
|
||||
#include "dbusnotificationsinterface.h" |
||||
|
||||
#include <QDBusConnection> |
||||
#include <QString> |
||||
#include <QVariant> |
||||
|
||||
#include "base/global.h" |
||||
|
||||
DBusNotificationsInterface::DBusNotificationsInterface(const QString &service |
||||
, const QString &path, const QDBusConnection &connection, QObject *parent) |
||||
: QDBusAbstractInterface(service, path, DBUS_INTERFACE_NAME, connection, parent) |
||||
{ |
||||
} |
||||
|
||||
QDBusPendingReply<QStringList> DBusNotificationsInterface::getCapabilities() |
||||
{ |
||||
return asyncCall(u"GetCapabilities"_qs); |
||||
} |
||||
|
||||
QDBusPendingReply<QString, QString, QString, QString> DBusNotificationsInterface::getServerInformation() |
||||
{ |
||||
return asyncCall(u"GetServerInformation"_qs); |
||||
} |
||||
|
||||
QDBusReply<QString> DBusNotificationsInterface::getServerInformation(QString &vendor, QString &version, QString &specVersion) |
||||
{ |
||||
const QDBusMessage reply = call(QDBus::Block, u"GetServerInformation"_qs); |
||||
if ((reply.type() == QDBusMessage::ReplyMessage) && (reply.arguments().count() == 4)) |
||||
{ |
||||
vendor = qdbus_cast<QString>(reply.arguments().at(1)); |
||||
version = qdbus_cast<QString>(reply.arguments().at(2)); |
||||
specVersion = qdbus_cast<QString>(reply.arguments().at(3)); |
||||
} |
||||
|
||||
return reply; |
||||
} |
||||
|
||||
QDBusPendingReply<uint> DBusNotificationsInterface::notify(const QString &appName |
||||
, const uint id, const QString &icon, const QString &summary, const QString &body |
||||
, const QStringList &actions, const QVariantMap &hints, const int timeout) |
||||
{ |
||||
return asyncCall(u"Notify"_qs, appName, id, icon, summary, body, actions, hints, timeout); |
||||
} |
||||
|
||||
QDBusPendingReply<> DBusNotificationsInterface::closeNotification(const uint id) |
||||
{ |
||||
return asyncCall(u"CloseNotification"_qs, id); |
||||
} |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent. |
||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* In addition, as a special exception, the copyright holders give permission to |
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||
* modified versions of it that use the same license as the "OpenSSL" library), |
||||
* and distribute the linked executables. You must obey the GNU General Public |
||||
* License in all respects for all of the code used other than "OpenSSL". If you |
||||
* modify file(s), you may extend this exception to your version of the file(s), |
||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||
* exception statement from your version. |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <QDBusAbstractInterface> |
||||
#include <QDBusPendingReply> |
||||
#include <QDBusReply> |
||||
#include <QStringList> |
||||
|
||||
class QDBusConnection; |
||||
class QString; |
||||
class QVariant; |
||||
|
||||
class DBusNotificationsInterface final : public QDBusAbstractInterface |
||||
{ |
||||
Q_OBJECT |
||||
Q_DISABLE_COPY_MOVE(DBusNotificationsInterface) |
||||
|
||||
public: |
||||
inline static const char DBUS_INTERFACE_NAME[] = "org.freedesktop.Notifications"; |
||||
|
||||
DBusNotificationsInterface(const QString &service, const QString &path |
||||
, const QDBusConnection &connection, QObject *parent = nullptr); |
||||
|
||||
public slots: |
||||
QDBusPendingReply<QStringList> getCapabilities(); |
||||
QDBusPendingReply<QString, QString, QString, QString> getServerInformation(); |
||||
QDBusReply<QString> getServerInformation(QString &vendor, QString &version, QString &specVersion); |
||||
QDBusPendingReply<uint> notify(const QString &appName |
||||
, uint id, const QString &icon, const QString &summary, const QString &body |
||||
, const QStringList &actions, const QVariantMap &hints, int timeout); |
||||
QDBusPendingReply<> closeNotification(uint id); |
||||
|
||||
signals: |
||||
// Signal names must exactly match the ones from corresponding D-Bus interface
|
||||
void ActionInvoked(uint id, const QString &action); |
||||
void NotificationClosed(uint id, uint reason); |
||||
}; |
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent. |
||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru> |
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* In addition, as a special exception, the copyright holders give permission to |
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||
* modified versions of it that use the same license as the "OpenSSL" library), |
||||
* and distribute the linked executables. You must obey the GNU General Public |
||||
* License in all respects for all of the code used other than "OpenSSL". If you |
||||
* modify file(s), you may extend this exception to your version of the file(s), |
||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||
* exception statement from your version. |
||||
*/ |
||||
|
||||
#include "dbusnotifier.h" |
||||
|
||||
#include <QDBusConnection> |
||||
#include <QDBusPendingCallWatcher> |
||||
#include <QDBusPendingReply> |
||||
|
||||
#include "base/global.h" |
||||
#include "dbusnotificationsinterface.h" |
||||
|
||||
DBusNotifier::DBusNotifier(QObject *parent) |
||||
: QObject(parent) |
||||
, m_notificationsInterface {new DBusNotificationsInterface(u"org.freedesktop.Notifications"_qs |
||||
, u"/org/freedesktop/Notifications"_qs, QDBusConnection::sessionBus(), this)} |
||||
{ |
||||
// Testing for 'DBusNotificationsInterface::isValid()' isn't helpful here.
|
||||
// If the notification daemon is configured to run 'as needed'
|
||||
// the above check can be false if the daemon wasn't started
|
||||
// by another application. In this case DBus will be able to
|
||||
// start the notification daemon and complete our request. Such
|
||||
// a daemon is xfce4-notifyd, DBus autostarts it and after
|
||||
// some inactivity shuts it down. Other DEs, like GNOME, choose
|
||||
// to start their daemons at the session startup and have it sit
|
||||
// idling for the whole session.
|
||||
|
||||
connect(m_notificationsInterface, &DBusNotificationsInterface::ActionInvoked, this, &DBusNotifier::onActionInvoked); |
||||
connect(m_notificationsInterface, &DBusNotificationsInterface::NotificationClosed, this, &DBusNotifier::onNotificationClosed); |
||||
} |
||||
|
||||
void DBusNotifier::showMessage(const QString &title, const QString &message, const int timeout) |
||||
{ |
||||
// Assign "default" action to notification to make it clickable
|
||||
const QStringList actions {u"default"_qs, {}}; |
||||
const QVariantMap hints {{u"desktop-entry"_qs, u"org.qbittorrent.qBittorrent"_qs}}; |
||||
const QDBusPendingReply<uint> reply = m_notificationsInterface->notify(u"qBittorrent"_qs, 0 |
||||
, u"qbittorrent"_qs, title, message, actions, hints, timeout); |
||||
auto *watcher = new QDBusPendingCallWatcher(reply, this); |
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) |
||||
{ |
||||
const QDBusPendingReply<uint> reply = *self; |
||||
if (!reply.isError()) |
||||
{ |
||||
const uint messageID = reply.value(); |
||||
m_activeMessages.insert(messageID); |
||||
} |
||||
|
||||
self->deleteLater(); |
||||
}); |
||||
} |
||||
|
||||
void DBusNotifier::onActionInvoked(const uint messageID, const QString &action) |
||||
{ |
||||
Q_UNUSED(action); |
||||
|
||||
// Check whether the notification is sent by qBittorrent
|
||||
// to avoid reacting to unrelated notifictions
|
||||
if (m_activeMessages.contains(messageID)) |
||||
emit messageClicked(); |
||||
} |
||||
|
||||
void DBusNotifier::onNotificationClosed(const uint messageID, const uint reason) |
||||
{ |
||||
Q_UNUSED(reason); |
||||
|
||||
m_activeMessages.remove(messageID); |
||||
} |
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent. |
||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru> |
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* In addition, as a special exception, the copyright holders give permission to |
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||
* modified versions of it that use the same license as the "OpenSSL" library), |
||||
* and distribute the linked executables. You must obey the GNU General Public |
||||
* License in all respects for all of the code used other than "OpenSSL". If you |
||||
* modify file(s), you may extend this exception to your version of the file(s), |
||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||
* exception statement from your version. |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <QObject> |
||||
#include <QSet> |
||||
|
||||
class DBusNotificationsInterface; |
||||
|
||||
class DBusNotifier final : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
Q_DISABLE_COPY_MOVE(DBusNotifier) |
||||
|
||||
public: |
||||
explicit DBusNotifier(QObject *parent = nullptr); |
||||
|
||||
void showMessage(const QString &title, const QString &message, int timeout); |
||||
|
||||
signals: |
||||
void messageClicked(); |
||||
|
||||
private: |
||||
void onActionInvoked(uint messageID, const QString &action); |
||||
void onNotificationClosed(uint messageID, uint reason); |
||||
|
||||
DBusNotificationsInterface *m_notificationsInterface = nullptr; |
||||
QSet<uint> m_activeMessages; |
||||
}; |
@ -1,25 +0,0 @@
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* This file was generated by qdbusxml2cpp version 0.8 |
||||
* Command line was: qdbusxml2cpp -p notifications.h:notifications.cpp notifications.xml |
||||
* |
||||
* qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. |
||||
* |
||||
* This is an auto-generated file. |
||||
* This file may have been hand-edited. Look for HAND-EDIT comments |
||||
* before re-generating it. |
||||
*/ |
||||
|
||||
#include "notifications.h" |
||||
|
||||
/*
|
||||
* Implementation of interface class OrgFreedesktopNotificationsInterface |
||||
*/ |
||||
|
||||
OrgFreedesktopNotificationsInterface::OrgFreedesktopNotificationsInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) |
||||
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) |
||||
{ |
||||
} |
||||
|
||||
OrgFreedesktopNotificationsInterface::~OrgFreedesktopNotificationsInterface() |
||||
{ |
||||
} |
@ -1,84 +0,0 @@
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* This file was generated by qdbusxml2cpp version 0.8 |
||||
* Command line was: qdbusxml2cpp -p notifications.h:notifications.cpp notifications.xml |
||||
* |
||||
* qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. |
||||
* |
||||
* This is an auto-generated file. |
||||
* Do not edit! All changes made to it will be lost. |
||||
*/ |
||||
|
||||
#ifndef NOTIFICATIONS_H |
||||
#define NOTIFICATIONS_H |
||||
|
||||
#include <QtCore/QObject> |
||||
#include <QtCore/QByteArray> |
||||
#include <QtCore/QList> |
||||
#include <QtCore/QMap> |
||||
#include <QtCore/QString> |
||||
#include <QtCore/QStringList> |
||||
#include <QtCore/QVariant> |
||||
#include <QtDBus/QtDBus> |
||||
|
||||
/*
|
||||
* Proxy class for interface org.freedesktop.Notifications |
||||
*/ |
||||
class OrgFreedesktopNotificationsInterface: public QDBusAbstractInterface |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
static inline const char *staticInterfaceName() |
||||
{ return "org.freedesktop.Notifications"; } |
||||
|
||||
public: |
||||
OrgFreedesktopNotificationsInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); |
||||
|
||||
~OrgFreedesktopNotificationsInterface(); |
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
inline QDBusPendingReply<> CloseNotification(uint id) |
||||
{ |
||||
QList<QVariant> argumentList; |
||||
argumentList << QVariant::fromValue(id); |
||||
return asyncCallWithArgumentList(QStringLiteral("CloseNotification"), argumentList); |
||||
} |
||||
|
||||
inline QDBusPendingReply<QStringList> GetCapabilities() |
||||
{ |
||||
QList<QVariant> argumentList; |
||||
return asyncCallWithArgumentList(QStringLiteral("GetCapabilities"), argumentList); |
||||
} |
||||
|
||||
inline QDBusPendingReply<QString, QString, QString, QString> GetServerInformation() |
||||
{ |
||||
QList<QVariant> argumentList; |
||||
return asyncCallWithArgumentList(QStringLiteral("GetServerInformation"), argumentList); |
||||
} |
||||
inline QDBusReply<QString> GetServerInformation(QString &return_vendor, QString &return_version, QString &return_spec_version) |
||||
{ |
||||
QList<QVariant> argumentList; |
||||
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("GetServerInformation"), argumentList); |
||||
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) { |
||||
return_vendor = qdbus_cast<QString>(reply.arguments().at(1)); |
||||
return_version = qdbus_cast<QString>(reply.arguments().at(2)); |
||||
return_spec_version = qdbus_cast<QString>(reply.arguments().at(3)); |
||||
} |
||||
return reply; |
||||
} |
||||
|
||||
inline QDBusPendingReply<uint> Notify(const QString &app_name, uint id, const QString &icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantMap &hints, int timeout) |
||||
{ |
||||
QList<QVariant> argumentList; |
||||
argumentList << QVariant::fromValue(app_name) << QVariant::fromValue(id) << QVariant::fromValue(icon) << QVariant::fromValue(summary) << QVariant::fromValue(body) << QVariant::fromValue(actions) << QVariant::fromValue(hints) << QVariant::fromValue(timeout); |
||||
return asyncCallWithArgumentList(QStringLiteral("Notify"), argumentList); |
||||
} |
||||
|
||||
Q_SIGNALS: // SIGNALS
|
||||
}; |
||||
|
||||
namespace org { |
||||
namespace freedesktop { |
||||
typedef ::OrgFreedesktopNotificationsInterface Notifications; |
||||
} |
||||
} |
||||
#endif |
@ -1,30 +0,0 @@
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" |
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
||||
<node> |
||||
<interface name="org.freedesktop.Notifications"> |
||||
<method name="GetServerInformation"> |
||||
<arg name="return_name" type="s" direction="out"/> |
||||
<arg name="return_vendor" type="s" direction="out"/> |
||||
<arg name="return_version" type="s" direction="out"/> |
||||
<arg name="return_spec_version" type="s" direction="out"/> |
||||
</method> |
||||
<method name="GetCapabilities"> |
||||
<arg name="return_caps" type="as" direction="out"/> |
||||
</method> |
||||
<method name="CloseNotification"> |
||||
<arg name="id" type="u" direction="in"/> |
||||
</method> |
||||
<method name="Notify"> |
||||
<arg name="app_name" type="s" direction="in"/> |
||||
<arg name="id" type="u" direction="in"/> |
||||
<arg name="icon" type="s" direction="in"/> |
||||
<arg name="summary" type="s" direction="in"/> |
||||
<arg name="body" type="s" direction="in"/> |
||||
<arg name="actions" type="as" direction="in"/> |
||||
<arg name="hints" type="a{sv}" direction="in"/> |
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In6" value="QVariantMap"/> |
||||
<arg name="timeout" type="i" direction="in"/> |
||||
<arg name="return_id" type="u" direction="out"/> |
||||
</method> |
||||
</interface> |
||||
</node> |
Loading…
Reference in new issue