summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMax Sandholm <max@sandholm.org>2018-07-11 17:33:02 +0300
committermujx <mujx@users.noreply.github.com>2018-07-11 17:33:02 +0300
commit80ebe3f29debb7f2020757252d1e2b4ae8a45869 (patch)
tree07a9bb42e559503787fbde1fd4eec7922bbafed0 /src
parentUse QSharedPointer::data to be compatible with Qt < 5.11 (diff)
downloadnheko-80ebe3f29debb7f2020757252d1e2b4ae8a45869.tar.xz
Working D-Bus desktop notifications (#361)
* Working D-Bus desktop notifications

* Remove return type on constructor

* Fix the Windows placeholder class

* Fix wrong variable name

* Fix windows and macOS versions of notificationsmanager
Diffstat (limited to 'src')
-rw-r--r--src/ChatPage.cc17
-rw-r--r--src/notifications/ManagerLinux.cpp155
-rw-r--r--src/notifications/ManagerMac.mm32
-rw-r--r--src/notifications/ManagerWin.cpp27
4 files changed, 221 insertions, 10 deletions
diff --git a/src/ChatPage.cc b/src/ChatPage.cc

index 29747fbe..336ea7c3 100644 --- a/src/ChatPage.cc +++ b/src/ChatPage.cc
@@ -56,6 +56,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) : QWidget(parent) , isConnected_(true) , userSettings_{userSettings} + , notificationsManager(this) { setObjectName("chatPage"); @@ -541,6 +542,15 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent) room_list_->setRoomFilter(communities_[communityId]->getRoomList()); }); + connect(&notificationsManager, + &NotificationsManager::notificationClicked, + this, + [this](const QString &roomid, const QString &eventid) { + Q_UNUSED(eventid) + room_list_->highlightSelectedRoom(roomid); + activateWindow(); + }); + setGroupViewState(userSettings_->isGroupViewEnabled()); connect(userSettings_.data(), @@ -998,11 +1008,14 @@ ChatPage::sendDesktopNotifications(const mtx::responses::Notifications &res) if (isRoomActive(room_id)) continue; - NotificationsManager::postNotification( + notificationsManager.postNotification( + room_id, + QString::fromStdString(event_id), QString::fromStdString( cache::client()->singleRoomInfo(item.room_id).name), Cache::displayName(room_id, user_id), - utils::event_body(item.event)); + utils::event_body(item.event), + cache::client()->getRoomAvatar(room_id)); } } catch (const lmdb::error &e) { nhlog::db()->warn("error while sending desktop notification: {}", e.what()); diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp
index a913128e..80fdb9d8 100644 --- a/src/notifications/ManagerLinux.cpp +++ b/src/notifications/ManagerLinux.cpp
@@ -1,7 +1,158 @@ #include "notifications/Manager.h" +#include <QImage> +#include <QDebug> +#include <QtDBus/QDBusMessage> +#include <QtDBus/QDBusMetaType> +#include <QtDBus/QDBusConnection> + +NotificationsManager::NotificationsManager(QObject *parent) : + QObject(parent), + dbus( + "org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus(), + this) +{ + qDBusRegisterMetaType<QImage>(); + + //connectSlot("ActionInvoked", SLOT(actionInvoked(uint, QString))); + //connectSlot("NotificationClosed", SLOT(notificationClosed(uint, uint))); + QDBusConnection::sessionBus().connect( + "org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + "ActionInvoked", + this, + SLOT(actionInvoked(uint, QString))); + QDBusConnection::sessionBus().connect( + "org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + "NotificationClosed", + this, + SLOT(notificationClosed(uint, uint))); +} + +void +NotificationsManager::postNotification(const QString &roomid, + const QString &eventid, + const QString &roomname, + const QString &sender, + const QString &text, + const QImage &icon) +{ + uint id = showNotification(roomname, sender+": "+text, icon); + notificationIds[id] = roomEventId{roomid,eventid}; +} +/** + * This function is based on code from + * https://github.com/rohieb/StratumsphereTrayIcon + * Copyright (C) 2012 Roland Hieber <rohieb@rohieb.name> + * Licensed under the GNU General Public License, version 3 + */ +uint +NotificationsManager::showNotification(const QString summary, const QString text, const QImage image) +{ + QVariantMap hints; + hints["image_data"] = image; + QList<QVariant> argumentList; + argumentList << "nheko"; //app_name + argumentList << (uint)0; // replace_id + argumentList << ""; // app_icon + argumentList << summary; // summary + argumentList << text; // body + argumentList << (QStringList("default")<<"reply"); // actions + argumentList << hints; // hints + argumentList << (int)0; // timeout in ms + + static QDBusInterface notifyApp( + "org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications"); + QDBusMessage reply = notifyApp.callWithArgumentList( + QDBus::AutoDetect, + "Notify", + argumentList); + if(reply.type() == QDBusMessage::ErrorMessage) { + qDebug() << "D-Bus Error:" << reply.errorMessage(); + return 0; + } else { + return reply.arguments().first().toUInt(); + } + return true; +} + void -NotificationsManager::postNotification(const QString &, const QString &, const QString &) +NotificationsManager::actionInvoked(uint id, QString action) { - // TODO: To be implemented + if (action == "default" && notificationIds.contains(id)) { + roomEventId idEntry = notificationIds[id]; + emit notificationClicked(idEntry.roomId, idEntry.eventId); + } +} + +void +NotificationsManager::notificationClosed(uint id, uint reason) +{ + Q_UNUSED(reason); + notificationIds.remove(id); +} + +/** + * Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify + * + * This function is from the Clementine project (see + * http://www.clementine-player.org) and licensed under the GNU General Public + * License, version 3 or later. + * + * Copyright 2010, David Sansome <me@davidsansome.com> + */ +QDBusArgument& operator<<(QDBusArgument& arg, const QImage& image) { + if(image.isNull()) { + arg.beginStructure(); + arg << 0 << 0 << 0 << false << 0 << 0 << QByteArray(); + arg.endStructure(); + return arg; + } + + QImage scaled = image.scaledToHeight(100, Qt::SmoothTransformation); + scaled = scaled.convertToFormat(QImage::Format_ARGB32); + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + // ABGR -> ARGB + QImage i = scaled.rgbSwapped(); +#else + // ABGR -> GBAR + QImage i(scaled.size(), scaled.format()); + for (int y = 0; y < i.height(); ++y) { + QRgb* p = (QRgb*) scaled.scanLine(y); + QRgb* q = (QRgb*) i.scanLine(y); + QRgb* end = p + scaled.width(); + while (p < end) { + *q = qRgba(qGreen(*p), qBlue(*p), qAlpha(*p), qRed(*p)); + p++; + q++; + } + } +#endif + + arg.beginStructure(); + arg << i.width(); + arg << i.height(); + arg << i.bytesPerLine(); + arg << i.hasAlphaChannel(); + int channels = i.isGrayscale() ? 1 : (i.hasAlphaChannel() ? 4 : 3); + arg << i.depth() / channels; + arg << channels; + arg << QByteArray(reinterpret_cast<const char*>(i.bits()), i.byteCount()); + arg.endStructure(); + return arg; +} + +const QDBusArgument& operator>>(const QDBusArgument& arg, QImage&) { + // This is needed to link but shouldn't be called. + Q_ASSERT(0); + return arg; } diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm
index 48fb46ca..66ef713f 100644 --- a/src/notifications/ManagerMac.mm +++ b/src/notifications/ManagerMac.mm
@@ -7,16 +7,42 @@ - (void)set_identityImage:(NSImage *)image; @end +NotificationsManager::NotificationsManager(QObject *parent): QObject(parent) +{ + +} + void -NotificationsManager::postNotification(const QString &roomName, const QString &userName, const QString &message) +NotificationsManager::postNotification( + const QString &roomId, + const QString &eventId, + const QString &roomName, + const QString &senderName, + const QString &text, + const QImage &icon) { + Q_UNUSED(roomId); + Q_UNUSED(eventId); + Q_UNUSED(icon); + NSUserNotification * notif = [[NSUserNotification alloc] init]; notif.title = roomName.toNSString(); - notif.subtitle = QString("%1 sent a message").arg(userName).toNSString(); - notif.informativeText = message.toNSString(); + notif.subtitle = QString("%1 sent a message").arg(senderName).toNSString(); + notif.informativeText = text.toNSString(); notif.soundName = NSUserNotificationDefaultSoundName; [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notif]; [notif autorelease]; } + +//unused +void +NotificationsManager::actionInvoked(uint, QString) +{ +} + +void +NotificationsManager::notificationClosed(uint, uint) +{ +} diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp
index 7503e852..90367d9a 100644 --- a/src/notifications/ManagerWin.cpp +++ b/src/notifications/ManagerWin.cpp
@@ -27,15 +27,25 @@ init() } } +NotificationsManager::NotificationsManager(QObject *parent): QObject(parent) +{ + +} + void -NotificationsManager::postNotification(const QString &room, const QString &user, const QString &msg) +NotificationsManager::postNotification(const QString &, //roomid + const QString &, //eventid + const QString &roomname, + const QString &sender, + const QString &text, + const QImage &) //icon { if (!isInitialized) init(); auto templ = WinToastTemplate(WinToastTemplate::ImageAndText02); - if (room != user) - templ.setTextField(QString("%1 - %2").arg(user).arg(room).toStdWString(), + if (roomname != sender) + templ.setTextField(QString("%1 - %2").arg(sender).arg(roomname).toStdWString(), WinToastTemplate::FirstLine); else templ.setTextField(QString("%1").arg(user).toStdWString(), @@ -46,3 +56,14 @@ NotificationsManager::postNotification(const QString &room, const QString &user, WinToast::instance()->showToast(templ, new CustomHandler()); } + +//unused +void +NotificationsManager::actionInvoked(uint, QString) +{ +} + +void +NotificationsManager::notificationClosed(uint, uint) +{ +}