summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--saltoqd/notificationmanager.cpp3
-rw-r--r--saltoqd/notificationmanager.h3
-rw-r--r--saltoqd/notificationmonitor.cpp287
-rw-r--r--saltoqd/notificationmonitor.h35
-rw-r--r--saltoqd/org.freedesktop.Notifications.xml3
-rw-r--r--saltoqd/saltoqd.pro4
-rw-r--r--saltoqd/toqconnection.cpp9
-rw-r--r--saltoqd/toqmanager.cpp4
-rw-r--r--saltoqd/toqmanager.h2
9 files changed, 323 insertions, 27 deletions
diff --git a/saltoqd/notificationmanager.cpp b/saltoqd/notificationmanager.cpp
index 45020cb..a2142fc 100644
--- a/saltoqd/notificationmanager.cpp
+++ b/saltoqd/notificationmanager.cpp
@@ -1,6 +1,7 @@
#include "notificationmanager.h"
+#include "notificationmonitor.h"
NotificationManager::NotificationManager(ToqManager *toq) :
- QObject(toq), _toq(toq)
+ QObject(toq), _toq(toq), _monitor(NotificationMonitor::instance())
{
}
diff --git a/saltoqd/notificationmanager.h b/saltoqd/notificationmanager.h
index 1889336..78c32ed 100644
--- a/saltoqd/notificationmanager.h
+++ b/saltoqd/notificationmanager.h
@@ -3,6 +3,8 @@
#include "toqmanager.h"
+class NotificationMonitor;
+
class NotificationManager : public QObject
{
Q_OBJECT
@@ -11,6 +13,7 @@ public:
private:
ToqManager *_toq;
+ NotificationMonitor *_monitor;
};
#endif // NOTIFICATIONMANAGER_H
diff --git a/saltoqd/notificationmonitor.cpp b/saltoqd/notificationmonitor.cpp
index f22ce02..2c6621d 100644
--- a/saltoqd/notificationmonitor.cpp
+++ b/saltoqd/notificationmonitor.cpp
@@ -1,30 +1,254 @@
#include <QtCore/QDebug>
-#include <QtGui/QIcon>
-#include <QtDBus/QDBusConnection>
-#include <QtDBus/QDBusConnectionInterface>
+#include <QtCore/QSocketNotifier>
+#include <dbus/dbus.h>
#include "notificationmonitor.h"
#include "notifications_adaptor.h"
-static NotificationMonitor *global_monitor = 0;
+namespace
+{
+
+NotificationMonitor *global_monitor = 0;
+
+DBusConnection *bus_connection;
+
+QHash<quint32, QVariantHash> pending_confirmation;
+
+dbus_bool_t bus_watch_add(DBusWatch *watch, void *data)
+{
+ NotificationMonitor *monitor = static_cast<NotificationMonitor*>(data);
+ int socket = dbus_watch_get_socket(watch);
+ int flags = dbus_watch_get_flags(watch);
+ QSocketNotifier::Type type;
+ switch (flags) {
+ case DBUS_WATCH_READABLE:
+ type = QSocketNotifier::Read;
+ break;
+ case DBUS_WATCH_WRITABLE:
+ type = QSocketNotifier::Write;
+ break;
+ default:
+ qWarning() << "Can't add this type of watch" << flags;
+ return FALSE;
+ }
+
+ QSocketNotifier *notifier = new QSocketNotifier(socket, type, monitor);
+ dbus_watch_set_data(watch, notifier, NULL);
+
+ notifier->setEnabled(dbus_watch_get_enabled(watch));
+
+ notifier->connect(notifier, &QSocketNotifier::activated,
+ [watch]() {
+ dbus_watch_handle(watch, dbus_watch_get_flags(watch));
+
+ while (dbus_connection_get_dispatch_status(bus_connection) == DBUS_DISPATCH_DATA_REMAINS) {
+ dbus_connection_dispatch(bus_connection);
+ }
+ });
+
+ return TRUE;
+}
+
+void bus_watch_remove(DBusWatch *watch, void *data)
+{
+ QSocketNotifier *notifier = static_cast<QSocketNotifier*>(dbus_watch_get_data(watch));
+ Q_UNUSED(data);
+ delete notifier;
+}
+
+void bus_watch_toggle(DBusWatch *watch, void *data)
+{
+ QSocketNotifier *notifier = static_cast<QSocketNotifier*>(dbus_watch_get_data(watch));
+ Q_UNUSED(data);
+ notifier->setEnabled(dbus_watch_get_enabled(watch));
+}
+
+QVariantHash parse_notify_call(DBusMessage *msg)
+{
+ QVariantHash r;
+ DBusMessageIter iter, sub;
+ const char *app_name, *app_icon, *summary, *body;
+ quint32 replaces_id;
+ qint32 expire_timeout;
+
+ if (strcmp(dbus_message_get_signature(msg), "susssasa{sv}i") != 0) {
+ qWarning() << "Invalid signature";
+ return r;
+ }
+
+ dbus_message_iter_init(msg, &iter);
+ Q_ASSERT(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic(&iter, &app_name);
+ dbus_message_iter_next(&iter);
+ Q_ASSERT(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32);
+ dbus_message_iter_get_basic(&iter, &replaces_id);
+ dbus_message_iter_next(&iter);
+ Q_ASSERT(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
+ dbus_message_iter_get_basic(&iter, &app_icon);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &summary);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &body);
+ dbus_message_iter_next(&iter);
+
+ QStringList actions;
+ dbus_message_iter_recurse(&iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
+ const char *action;
+ dbus_message_iter_get_basic(&sub, &action);
+ actions.append(QString::fromUtf8(action));
+ dbus_message_iter_next(&sub);
+ }
+ r.insert("actions", QVariant::fromValue(actions));
+ dbus_message_iter_next(&iter);
+
+ dbus_message_iter_recurse(&iter, &sub);
+ while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&sub, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+
+ dbus_message_iter_recurse(&entry, &value);
+ if (strcmp(key, "category") == 0 && dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
+ const char *s;
+ dbus_message_iter_get_basic(&value, &s);
+ r.insert("category", QString::fromUtf8(s));
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ dbus_message_iter_next(&iter);
+ Q_ASSERT(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_INT32);
+ dbus_message_iter_get_basic(&iter, &expire_timeout);
+
+ r.insert("sender", QString::fromUtf8(app_name));
+ r.insert("app_icon", QString::fromUtf8(app_icon));
+ r.insert("summary", QString::fromUtf8(summary));
+ r.insert("body", QString::fromUtf8(body));
+
+ return r;
+}
+
+DBusHandlerResult message_filter(DBusConnection *conn, DBusMessage *msg, void *user_data)
+{
+ NotificationMonitor *monitor = static_cast<NotificationMonitor*>(user_data);
+ DBusError error = DBUS_ERROR_INIT;
+ Q_UNUSED(conn);
+ switch (dbus_message_get_type(msg)) {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ if (dbus_message_is_method_call(msg, "org.freedesktop.Notifications", "Notify")) {
+ quint32 serial = dbus_message_get_serial(msg);
+ QVariantHash content = parse_notify_call(msg);
+ pending_confirmation.insert(serial, content);
+ }
+ break;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ if (pending_confirmation.contains(dbus_message_get_reply_serial(msg))) {
+ quint32 id;
+ if (dbus_message_get_args(msg, &error, DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID)) {
+ QVariantHash content = pending_confirmation.take(dbus_message_get_reply_serial(msg));
+ monitor->processIncomingNotification(id, content);
+ } else {
+ qWarning() << "Could not parse notification method return";
+ }
+ }
+ break;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ if (dbus_message_is_signal(msg, "org.freedesktop.Notifications", "NotificationClosed")) {
+ quint32 id, reason;
+ if (dbus_message_get_args(msg, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_UINT32, &reason,
+ DBUS_TYPE_INVALID)) {
+ monitor->processCloseNotification(id, reason);
+ } else {
+ qWarning() << "Failed to parse notification signal arguments";
+ }
+
+ }
+ break;
+ }
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+void send_message_with_string(const char *service, const char *path, const char *iface, const char *method, const char *arg)
+{
+ DBusMessage *msg = dbus_message_new_method_call(service, path, iface, method);
+ Q_ASSERT(msg);
+ dbus_message_set_no_reply(msg, TRUE);
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &arg,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(bus_connection, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+void add_match_rule(const char *rule)
+{
+ send_message_with_string("org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "AddMatch", rule);
+}
+
+void remove_match_rule(const char *rule)
+{
+ send_message_with_string("org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "RemoveMatch", rule);
+}
+
+}
+
+IncomingNotification::IncomingNotification(QObject *parent) :
+ QObject(parent)
+{
+}
NotificationMonitor::NotificationMonitor(QObject *parent) :
QObject(parent)
{
- QDBusConnection bus = QDBusConnection::sessionBus();
- QDBusConnectionInterface *dbus = bus.interface();
- dbus->call("AddMatch",
- "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
- new NotificationsAdaptor(this);
- bus.registerObject("/org/freedesktop/Notifications", this);
+ Q_ASSERT(!bus_connection);
+ DBusError error = DBUS_ERROR_INIT;
+ bus_connection = dbus_bus_get_private(DBUS_BUS_SESSION, &error);
+ if (!bus_connection) {
+ qWarning() << "Could not connect to the session bus";
+ return;
+ }
+
+ dbus_connection_set_exit_on_disconnect(bus_connection, FALSE);
+
+ dbus_connection_set_watch_functions(bus_connection, bus_watch_add,
+ bus_watch_remove, bus_watch_toggle,
+ this, NULL);
+
+ add_match_rule("type='method_call',interface='org.freedesktop.Notifications',member='Notify',eavesdrop='true'");
+ add_match_rule("type='method_return',sender='org.freedesktop.Notifications',eavesdrop='true'");
+ add_match_rule("type='signal',sender='org.freedesktop.Notifications',path='/org/freedesktop/Notifications',interface='org.freedesktop.Notifications',member='NotificationClosed'");
+
+ dbus_bool_t result = dbus_connection_add_filter(bus_connection, message_filter,
+ this, NULL);
+ if (!result) {
+ qWarning() << "Could not add filter";
+ }
+
+ qDebug() << "Starting notification monitor";
}
NotificationMonitor::~NotificationMonitor()
{
- QDBusConnection bus = QDBusConnection::sessionBus();
- QDBusConnectionInterface *dbus = bus.interface();
- dbus->call("RemoveMatch",
- "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
+ Q_ASSERT(bus_connection);
+
+ remove_match_rule("type='method_call',interface='org.freedesktop.Notifications',member='Notify',eavesdrop='true'");
+ remove_match_rule("type='method_return',sender='org.freedesktop.Notifications',eavesdrop='true'");
+ remove_match_rule("type='signal',sender='org.freedesktop.Notifications',path='/org/freedesktop/Notifications',interface='org.freedesktop.Notifications',member='NotificationClosed'");
+
+ dbus_connection_remove_filter(bus_connection, message_filter, this);
+
+ dbus_connection_close(bus_connection);
+ dbus_connection_unref(bus_connection);
+ bus_connection = NULL;
}
NotificationMonitor *NotificationMonitor::instance()
@@ -35,6 +259,33 @@ NotificationMonitor *NotificationMonitor::instance()
return global_monitor;
}
+void NotificationMonitor::processIncomingNotification(quint32 id, const QVariantHash &content)
+{
+ qDebug() << "Incoming notification" << id << content;
+ IncomingNotification *n = _notifs.value(id, 0);
+ if (n) {
+ // TODO emit changed signals for individual fields
+ } else {
+ n = new IncomingNotification(this);
+ n->_sender = content["app_name"].toString();
+ n->_summary = content["summary"].toString();
+
+ emit notification(n);
+ }
+}
+
+void NotificationMonitor::processCloseNotification(quint32 id, quint32 reason)
+{
+ qDebug() << "Close notification" << id << reason;
+ IncomingNotification *n = _notifs.value(id, 0);
+ if (n) {
+ _notifs.remove(id);
+ n->deleteLater();
+ }
+}
+
+#if 0
+
uint NotificationMonitor::Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantHash &hints, int expire_timeout)
{
QIcon icon;
@@ -77,3 +328,11 @@ uint NotificationMonitor::Notify(const QString &app_name, uint replaces_id, cons
return 0;
}
+
+void NotificationMonitor::CloseNotification(uint id)
+{
+ qDebug() << "Close notification" << id;
+}
+
+#endif
+
diff --git a/saltoqd/notificationmonitor.h b/saltoqd/notificationmonitor.h
index c0f7691..8ac49c5 100644
--- a/saltoqd/notificationmonitor.h
+++ b/saltoqd/notificationmonitor.h
@@ -2,10 +2,32 @@
#define NOTIFICATIONMONITOR_H
#include <QtCore/QObject>
+#include <QtCore/QMap>
#include <QtCore/QDateTime>
-#include <QtDBus/QDBusContext>
-class NotificationMonitor : public QObject, protected QDBusContext
+class IncomingNotification : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString sender READ sender)
+ Q_PROPERTY(QString summary READ summary NOTIFY summaryChanged)
+
+ explicit IncomingNotification(QObject *parent = 0);
+
+public:
+ inline QString sender() const { return _sender; }
+ inline QString summary() const { return _summary; }
+
+signals:
+ void summaryChanged();
+
+private:
+ friend class NotificationMonitor;
+
+ QString _sender;
+ QString _summary;
+};
+
+class NotificationMonitor : public QObject
{
Q_OBJECT
@@ -14,15 +36,16 @@ public:
static NotificationMonitor *instance();
+ void processIncomingNotification(quint32 id, const QVariantHash &content);
+ void processCloseNotification(quint32 id, quint32 reason);
+
signals:
- void incomingNotification(const QString &sender, const QIcon &icon, const QString &summary, int count, const QString &body, const QDateTime &dateTime);
+ void notification(IncomingNotification *n);
private:
explicit NotificationMonitor(QObject *parent = 0);
+ QMap<quint32, IncomingNotification*> _notifs;
-private slots:
- friend class NotificationsAdaptor;
- uint Notify(const QString &app_name, uint replaces_id, const QString &app_icon, const QString &summary, const QString &body, const QStringList &actions, const QVariantHash &hints, int expire_timeout);
};
#endif // NOTIFICATIONMONITOR_H
diff --git a/saltoqd/org.freedesktop.Notifications.xml b/saltoqd/org.freedesktop.Notifications.xml
index d3f8bef..3e645a0 100644
--- a/saltoqd/org.freedesktop.Notifications.xml
+++ b/saltoqd/org.freedesktop.Notifications.xml
@@ -14,4 +14,7 @@
<arg name="id" type="u" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In6" value="QVariantHash"/>
</method>
+ <method name="CloseNotification">
+ <arg name="id" type="u" direction="in"/>
+ </method>
</node>
diff --git a/saltoqd/saltoqd.pro b/saltoqd/saltoqd.pro
index 332dcb8..c664b6f 100644
--- a/saltoqd/saltoqd.pro
+++ b/saltoqd/saltoqd.pro
@@ -5,8 +5,8 @@ QT += dbus bluetooth contacts
CONFIG += c++11 link_pkgconfig
-PKGCONFIG += zlib mlite5 commhistory-qt5 openobex qtcontacts-sqlite-qt5-extensions
-INCLUDEPATH += /usr/include/commhistory-qt5 /usr/include/mlite5
+PKGCONFIG += zlib dbus-1 mlite5 commhistory-qt5 openobex qtcontacts-sqlite-qt5-extensions
+INCLUDEPATH += /usr/include/dbus-1.0 /usr/include/mlite5 /usr/include/commhistory-qt5
SOURCES += main.cpp \
toqconnection.cpp \
diff --git a/saltoqd/toqconnection.cpp b/saltoqd/toqconnection.cpp
index 4cc1d3e..6c1035e 100644
--- a/saltoqd/toqconnection.cpp
+++ b/saltoqd/toqconnection.cpp
@@ -6,6 +6,8 @@
#include "toqconnection.h"
static const int HEADER_LENGTH = 10;
+static const int FIRST_CONNECTION_INTERVAL = 1000;
+static const int RETRY_CONNECTION_INTERVAL = 30000;
ToqConnection::ToqConnection(QObject *parent) :
QObject(parent),
@@ -17,7 +19,6 @@ ToqConnection::ToqConnection(QObject *parent) :
this, &ToqConnection::tryConnect);
_reconnectTimer->setSingleShot(true);
- _reconnectTimer->setInterval(1000);
}
QString ToqConnection::nameOfEndpoint(Endpoint ep)
@@ -57,7 +58,7 @@ void ToqConnection::setAddress(const QBluetoothAddress &address)
if (isConnected()) {
_socket->disconnectFromService();
} else {
- _reconnectTimer->start();
+ _reconnectTimer->start(FIRST_CONNECTION_INTERVAL);
}
}
}
@@ -157,7 +158,9 @@ void ToqConnection::handleSocketDisconnected()
qDebug() << "Disconnected";
_socket->deleteLater();
_socket = 0;
- _reconnectTimer->start();
+ if (!_address.isNull()) {
+ _reconnectTimer->start(RETRY_CONNECTION_INTERVAL);
+ }
emit disconnected();
emit connectedChanged();
}
diff --git a/saltoqd/toqmanager.cpp b/saltoqd/toqmanager.cpp
index f03ba54..ea93d2a 100644
--- a/saltoqd/toqmanager.cpp
+++ b/saltoqd/toqmanager.cpp
@@ -11,6 +11,7 @@
#include "commmanager.h"
#include "voicecallmanager.h"
#include "weathermanager.h"
+#include "notificationmanager.h"
static const bool PROTO_DEBUG = true;
@@ -27,7 +28,8 @@ ToqManager::ToqManager(MDConfGroup *settings, QObject *parent) :
_contactsManager(new ContactsManager(_storageManager, this)),
_commManager(new CommManager(_settings, _storageManager, _contactsManager, this)),
_voiceCallManager(new VoiceCallManager(this)),
- _weatherManager(new WeatherManager(_fmsManager, this))
+ _weatherManager(new WeatherManager(_fmsManager, this)),
+ _notificationManager(new NotificationManager(this))
{
connect(_conn, &ToqConnection::messageReceived,
this, &ToqManager::handleToqMessage);
diff --git a/saltoqd/toqmanager.h b/saltoqd/toqmanager.h
index 1b2773c..7e6d19a 100644
--- a/saltoqd/toqmanager.h
+++ b/saltoqd/toqmanager.h
@@ -16,6 +16,7 @@ class ContactsManager;
class CommManager;
class VoiceCallManager;
class WeatherManager;
+class NotificationManager;
class ToqManager : public QObject
{
@@ -63,6 +64,7 @@ private:
CommManager *_commManager;
VoiceCallManager *_voiceCallManager;
WeatherManager *_weatherManager;
+ NotificationManager *_notificationManager;
};
inline bool ToqManager::isConnected() const