notifications: add initial support for desktop-to-xxx notifications
Eavesdrop on the Notify call of the org.freedesktop.Notifications dbus-interface, proxy all caught notifications to our peer device and track them in the internal notifications-list. Also fix "cancel" requests from peer devices, by cutting of kdeconnect-android's id-prefix.
This commit is contained in:
parent
2ca1d9720e
commit
2a74eb68f8
7 changed files with 171 additions and 3 deletions
|
@ -4,6 +4,7 @@ set(kdeconnect_notifications_SRCS
|
||||||
notification.cpp
|
notification.cpp
|
||||||
notificationsplugin.cpp
|
notificationsplugin.cpp
|
||||||
notificationsdbusinterface.cpp
|
notificationsdbusinterface.cpp
|
||||||
|
notificationslistener.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
kdeconnect_add_plugin(kdeconnect_notifications JSON kdeconnect_notifications.json SOURCES ${kdeconnect_notifications_SRCS})
|
kdeconnect_add_plugin(kdeconnect_notifications JSON kdeconnect_notifications.json SOURCES ${kdeconnect_notifications_SRCS})
|
||||||
|
|
|
@ -45,6 +45,7 @@ NotificationsDbusInterface::NotificationsDbusInterface(KdeConnectPlugin* plugin)
|
||||||
|
|
||||||
NotificationsDbusInterface::~NotificationsDbusInterface()
|
NotificationsDbusInterface::~NotificationsDbusInterface()
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Destroying NotificationsDbusInterface";
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationsDbusInterface::clearNotifications()
|
void NotificationsDbusInterface::clearNotifications()
|
||||||
|
@ -60,7 +61,21 @@ QStringList NotificationsDbusInterface::activeNotifications()
|
||||||
void NotificationsDbusInterface::processPackage(const NetworkPackage& np)
|
void NotificationsDbusInterface::processPackage(const NetworkPackage& np)
|
||||||
{
|
{
|
||||||
if (np.get<bool>("isCancel")) {
|
if (np.get<bool>("isCancel")) {
|
||||||
removeNotification(np.get<QString>("id"));
|
QString id = np.get<QString>("id");
|
||||||
|
// cut off kdeconnect-android's prefix if there:
|
||||||
|
if (id.startsWith("org.kde.kdeconnect_tp::"))
|
||||||
|
id = id.mid(id.indexOf("::") + 2);
|
||||||
|
removeNotification(id);
|
||||||
|
} else if (np.get<bool>("isRequest")) {
|
||||||
|
for (const auto& n: mNotifications) {
|
||||||
|
NetworkPackage np(PACKAGE_TYPE_NOTIFICATION);
|
||||||
|
np.set("id", n->internalId());
|
||||||
|
np.set("appName", n->appName());
|
||||||
|
np.set("ticker", n->ticker());
|
||||||
|
np.set("isClearable", n->dismissable());
|
||||||
|
np.set("requestAnswer", true);
|
||||||
|
mPlugin->sendPackage(np);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//TODO: Uncoment when we are able to display app icon on plasmoid
|
//TODO: Uncoment when we are able to display app icon on plasmoid
|
||||||
|
@ -114,7 +129,7 @@ void NotificationsDbusInterface::removeNotification(const QString& internalId)
|
||||||
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "removeNotification" << internalId;
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "removeNotification" << internalId;
|
||||||
|
|
||||||
if (!mInternalIdToPublicId.contains(internalId)) {
|
if (!mInternalIdToPublicId.contains(internalId)) {
|
||||||
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found";
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Not found: " << internalId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
void processPackage(const NetworkPackage& np);
|
void processPackage(const NetworkPackage& np);
|
||||||
void clearNotifications();
|
void clearNotifications();
|
||||||
void dismissRequested(const QString& notification);
|
void dismissRequested(const QString& notification);
|
||||||
|
void addNotification(Notification* noti);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
Q_SCRIPTABLE QStringList activeNotifications();
|
Q_SCRIPTABLE QStringList activeNotifications();
|
||||||
|
@ -54,7 +55,6 @@ Q_SIGNALS:
|
||||||
Q_SCRIPTABLE void notificationRemoved(const QString& publicId);
|
Q_SCRIPTABLE void notificationRemoved(const QString& publicId);
|
||||||
|
|
||||||
private /*methods*/:
|
private /*methods*/:
|
||||||
void addNotification(Notification* noti);
|
|
||||||
void removeNotification(const QString& internalId);
|
void removeNotification(const QString& internalId);
|
||||||
QString newId(); //Generates successive identifitiers to use as public ids
|
QString newId(); //Generates successive identifitiers to use as public ids
|
||||||
|
|
||||||
|
|
101
plugins/notifications/notificationslistener.cpp
Normal file
101
plugins/notifications/notificationslistener.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2015 Holger Kaelberer <holger.k@elberer.de>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtDBus/QDBusConnection>
|
||||||
|
#include <QtDBus/QDBusInterface>
|
||||||
|
#include <QtDebug>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
#include <core/device.h>
|
||||||
|
#include <core/kdeconnectplugin.h>
|
||||||
|
|
||||||
|
#include "notificationslistener.h"
|
||||||
|
#include "notificationsplugin.h"
|
||||||
|
#include "notification_debug.h"
|
||||||
|
#include "notificationsdbusinterface.h"
|
||||||
|
|
||||||
|
NotificationsListener::NotificationsListener(KdeConnectPlugin* aPlugin,
|
||||||
|
NotificationsDbusInterface* aDbusInterface)
|
||||||
|
: QDBusAbstractAdaptor(aPlugin),
|
||||||
|
mPlugin(aPlugin),
|
||||||
|
dbusInterface(aDbusInterface)
|
||||||
|
{
|
||||||
|
bool ret = QDBusConnection::sessionBus()
|
||||||
|
.registerObject("/org/freedesktop/Notifications",
|
||||||
|
this,
|
||||||
|
QDBusConnection::ExportScriptableContents);
|
||||||
|
if (!ret)
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_NOTIFICATION)
|
||||||
|
<< "Error registering notifications listener for device"
|
||||||
|
<< mPlugin->device()->name() << ":"
|
||||||
|
<< QDBusConnection::sessionBus().lastError();
|
||||||
|
else
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION)
|
||||||
|
<< "Registered notifications listener for device"
|
||||||
|
<< mPlugin->device()->name();
|
||||||
|
|
||||||
|
QDBusInterface iface("org.freedesktop.DBus", "/org/freedesktop/DBus",
|
||||||
|
"org.freedesktop.DBus");
|
||||||
|
iface.call("AddMatch",
|
||||||
|
"interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationsListener::~NotificationsListener()
|
||||||
|
{
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Destroying NotificationsListener";
|
||||||
|
QDBusInterface iface("org.freedesktop.DBus", "/org/freedesktop/DBus",
|
||||||
|
"org.freedesktop.DBus");
|
||||||
|
QDBusMessage res = iface.call("RemoveMatch",
|
||||||
|
"interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
|
||||||
|
QDBusConnection::sessionBus().unregisterObject("/org/freedesktop/Notifications");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint NotificationsListener::Notify(const QString &appName, uint replacesId,
|
||||||
|
const QString &appIcon,
|
||||||
|
const QString &summary, const QString &body,
|
||||||
|
const QStringList &actions,
|
||||||
|
const QVariantMap &hints, int timeout)
|
||||||
|
{
|
||||||
|
static int id = 0;
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Got notification appName=" << appName << "replacesId=" << replacesId << "appIcon=" << appIcon << "summary=" << summary << "body=" << body << "actions=" << actions << "hints=" << hints << "timeout=" << timeout;
|
||||||
|
Q_UNUSED(hints);
|
||||||
|
Q_UNUSED(actions);
|
||||||
|
Q_UNUSED(appIcon);
|
||||||
|
Q_UNUSED(body);
|
||||||
|
|
||||||
|
// skip our own notifications
|
||||||
|
if (appName == QLatin1String("KDE Connect"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
NetworkPackage np(PACKAGE_TYPE_NOTIFICATION);
|
||||||
|
np.set("id", QString::number(replacesId > 0 ? replacesId : ++id));
|
||||||
|
np.set("appName", appName);
|
||||||
|
np.set("ticker", summary);
|
||||||
|
np.set("isClearable", timeout == 0); // KNotifications are persistent if
|
||||||
|
// timeout == 0, for other notifications
|
||||||
|
// clearability is pointless
|
||||||
|
|
||||||
|
Notification *notification = new Notification(np, QString(), this);
|
||||||
|
dbusInterface->addNotification(notification);
|
||||||
|
|
||||||
|
mPlugin->sendPackage(np);
|
||||||
|
|
||||||
|
return (replacesId > 0 ? replacesId : id);
|
||||||
|
}
|
46
plugins/notifications/notificationslistener.h
Normal file
46
plugins/notifications/notificationslistener.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2015 Holger Kaelberer <holger.k@elberer.de>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtDBus/QDBusAbstractAdaptor>
|
||||||
|
#include <core/device.h>
|
||||||
|
|
||||||
|
class KdeConnectPlugin;
|
||||||
|
class NotificationsDbusInterface;
|
||||||
|
class Notification;
|
||||||
|
|
||||||
|
class NotificationsListener : public QDBusAbstractAdaptor
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_CLASSINFO("D-Bus Interface", "org.freedesktop.Notifications")
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NotificationsListener(KdeConnectPlugin* aPlugin,
|
||||||
|
NotificationsDbusInterface* aDbusInterface);
|
||||||
|
virtual ~NotificationsListener();
|
||||||
|
|
||||||
|
private:
|
||||||
|
KdeConnectPlugin* mPlugin;
|
||||||
|
NotificationsDbusInterface* dbusInterface;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
Q_SCRIPTABLE uint Notify(const QString&, uint, const QString&,
|
||||||
|
const QString&, const QString&,
|
||||||
|
const QStringList&, const QVariantMap&, int);
|
||||||
|
};
|
|
@ -21,6 +21,7 @@
|
||||||
#include "notificationsplugin.h"
|
#include "notificationsplugin.h"
|
||||||
|
|
||||||
#include "notificationsdbusinterface.h"
|
#include "notificationsdbusinterface.h"
|
||||||
|
#include "notificationslistener.h"
|
||||||
#include "notification_debug.h"
|
#include "notification_debug.h"
|
||||||
|
|
||||||
#include <KPluginFactory>
|
#include <KPluginFactory>
|
||||||
|
@ -33,6 +34,7 @@ NotificationsPlugin::NotificationsPlugin(QObject* parent, const QVariantList& ar
|
||||||
: KdeConnectPlugin(parent, args)
|
: KdeConnectPlugin(parent, args)
|
||||||
{
|
{
|
||||||
notificationsDbusInterface = new NotificationsDbusInterface(this);
|
notificationsDbusInterface = new NotificationsDbusInterface(this);
|
||||||
|
notificationsListener = new NotificationsListener(this, notificationsDbusInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationsPlugin::connected()
|
void NotificationsPlugin::connected()
|
||||||
|
@ -44,6 +46,7 @@ void NotificationsPlugin::connected()
|
||||||
|
|
||||||
NotificationsPlugin::~NotificationsPlugin()
|
NotificationsPlugin::~NotificationsPlugin()
|
||||||
{
|
{
|
||||||
|
qCDebug(KDECONNECT_PLUGIN_NOTIFICATION) << "Destroying NotificationsPlugin";
|
||||||
//FIXME: Qt dbus does not allow to remove an adaptor! (it causes a crash in
|
//FIXME: Qt dbus does not allow to remove an adaptor! (it causes a crash in
|
||||||
// the next dbus access to its parent). The implication of not deleting this
|
// the next dbus access to its parent). The implication of not deleting this
|
||||||
// is that disabling the plugin leaks the interface. As a mitigation we are
|
// is that disabling the plugin leaks the interface. As a mitigation we are
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
* KdeConnectPlugin at the same time (both are QObject)
|
* KdeConnectPlugin at the same time (both are QObject)
|
||||||
*/
|
*/
|
||||||
class NotificationsDbusInterface;
|
class NotificationsDbusInterface;
|
||||||
|
class NotificationsListener;
|
||||||
|
|
||||||
class NotificationsPlugin
|
class NotificationsPlugin
|
||||||
: public KdeConnectPlugin
|
: public KdeConnectPlugin
|
||||||
|
@ -48,6 +49,7 @@ public Q_SLOTS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NotificationsDbusInterface* notificationsDbusInterface;
|
NotificationsDbusInterface* notificationsDbusInterface;
|
||||||
|
NotificationsListener* notificationsListener;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue