diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 7235f93d..ffc3c6c1 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -54,6 +54,10 @@
#include "ui/UIA.h"
#include "voip/WebRTCSession.h"
+#ifdef NHEKO_DBUS_SYS
+#include "dbus/NhekoDBusApi.h"
+#endif
+
Q_DECLARE_METATYPE(mtx::events::collections::TimelineEvents)
Q_DECLARE_METATYPE(std::vector<DeviceInfo>)
Q_DECLARE_METATYPE(std::vector<mtx::responses::PublicRoomsChunk>)
@@ -282,6 +286,18 @@ MainWindow::registerQmlTypes()
engine()->addImageProvider(QStringLiteral("jdenticon"), new JdenticonProvider());
QObject::connect(engine(), &QQmlEngine::quit, &QGuiApplication::quit);
+
+#ifdef NHEKO_DBUS_SYS
+ if (UserSettings::instance()->exposeDBusApi()) {
+ if (QDBusConnection::sessionBus().isConnected() &&
+ QDBusConnection::sessionBus().registerService(NHEKO_DBUS_SERVICE_NAME)) {
+ nheko::dbus::init();
+ nhlog::ui()->info("Initialized D-Bus");
+ dbusAvailable_ = true;
+ } else
+ nhlog::ui()->warn("Could not connect to D-Bus!");
+ }
+#endif
}
void
diff --git a/src/MainWindow.h b/src/MainWindow.h
index e8c6fafd..3b1ff6f5 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -54,6 +54,10 @@ public:
//! Show the chat page and start communicating with the given access token.
void showChatPage();
+#ifdef NHEKO_DBUS_SYS
+ bool dbusAvailable() const { return dbusAvailable_; }
+#endif
+
protected:
void closeEvent(QCloseEvent *event);
bool event(QEvent *event) override;
@@ -96,4 +100,8 @@ private:
TrayIcon *trayIcon_;
MxcImageProvider *imgProvider = nullptr;
+
+#ifdef NHEKO_DBUS_SYS
+ bool dbusAvailable_{false};
+#endif
};
diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp
index 0a91dde3..6098f0c4 100644
--- a/src/MxcImageProvider.cpp
+++ b/src/MxcImageProvider.cpp
@@ -10,6 +10,7 @@
#include <mtxclient/crypto/client.hpp>
#include <QByteArray>
+#include <QCache>
#include <QDir>
#include <QFileInfo>
#include <QPainter>
@@ -103,6 +104,12 @@ MxcImageProvider::download(const QString &id,
bool crop,
double radius)
{
+ if (id.isEmpty()) {
+ nhlog::net()->warn("Attempted to download image with empty ID");
+ then(id, QSize{}, QImage{}, QString{});
+ return;
+ }
+
std::optional<mtx::crypto::EncryptedFile> encryptionInfo;
auto temp = infos.find("mxc://" + id);
if (temp != infos.end())
@@ -264,6 +271,7 @@ MxcImageProvider::download(const QString &id,
image.setText(QStringLiteral("original filename"),
QString::fromStdString(originalFilename));
image.setText(QStringLiteral("mxc url"), "mxc://" + id);
+
then(id, requestedSize, image, fileInfo.absoluteFilePath());
return;
}
@@ -276,6 +284,7 @@ MxcImageProvider::download(const QString &id,
image.setText(QStringLiteral("original filename"),
QString::fromStdString(originalFilename));
image.setText(QStringLiteral("mxc url"), "mxc://" + id);
+
then(id, requestedSize, image, fileInfo.absoluteFilePath());
});
} catch (std::exception &e) {
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 636bf75f..932c3beb 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -90,6 +90,8 @@ UserSettings::load(std::optional<QString> profile)
privacyScreen_ = settings.value(QStringLiteral("user/privacy_screen"), false).toBool();
privacyScreenTimeout_ =
settings.value(QStringLiteral("user/privacy_screen_timeout"), 0).toInt();
+ exposeDBusApi_ = settings.value(QStringLiteral("user/expose_dbus_api"), false).toBool();
+
mobileMode_ = settings.value(QStringLiteral("user/mobile_mode"), false).toBool();
emojiFont_ = settings.value(QStringLiteral("user/emoji_font_family"), "emoji").toString();
baseFontSize_ =
@@ -248,6 +250,17 @@ UserSettings::setCollapsedSpaces(QList<QStringList> spaces)
}
void
+UserSettings::setExposeDBusApi(bool state)
+{
+ if (exposeDBusApi_ == state)
+ return;
+
+ exposeDBusApi_ = state;
+ emit exposeDBusApiChanged(state);
+ save();
+}
+
+void
UserSettings::setMarkdown(bool state)
{
if (state == markdown_)
@@ -788,6 +801,7 @@ UserSettings::save()
settings.setValue(QStringLiteral("use_identicon"), useIdenticon_);
settings.setValue(QStringLiteral("open_image_external"), openImageExternal_);
settings.setValue(QStringLiteral("open_video_external"), openVideoExternal_);
+ settings.setValue(QStringLiteral("expose_dbus_api"), exposeDBusApi_);
settings.endGroup(); // user
@@ -972,6 +986,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
return tr("User signing key");
case MasterKey:
return tr("Master signing key");
+ case ExposeDBusApi:
+ return tr("Expose room information via D-Bus");
}
} else if (role == Value) {
switch (index.row()) {
@@ -1091,6 +1107,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
.has_value();
case MasterKey:
return cache::secret(mtx::secret_storage::secrets::cross_signing_master).has_value();
+ case ExposeDBusApi:
+ return i->exposeDBusApi();
}
} else if (role == Description) {
switch (index.row()) {
@@ -1235,6 +1253,12 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
"Your most important key. You don't need to have it cached, since not caching "
"it makes it less likely it can be stolen and it is only needed to rotate your "
"other signing keys.");
+ case ExposeDBusApi:
+ return tr("Allow third-party plugins and applications to load information about rooms "
+ "you are in via D-Bus. "
+ "This can have useful applications, but it also could be used for nefarious "
+ "purposes. Enable at your own risk.\n\n"
+ "This setting will take effect upon restart.");
}
} else if (role == Type) {
switch (index.row()) {
@@ -1279,6 +1303,7 @@ UserSettingsModel::data(const QModelIndex &index, int role) const
case OnlyShareKeysWithVerifiedUsers:
case ShareKeysWithTrustedUsers:
case UseOnlineKeyBackup:
+ case ExposeDBusApi:
return Toggle;
case Profile:
case UserId:
@@ -1711,6 +1736,13 @@ UserSettingsModel::setData(const QModelIndex &index, const QVariant &value, int
} else
return false;
}
+ case ExposeDBusApi: {
+ if (value.userType() == QMetaType::Bool) {
+ i->setExposeDBusApi(value.toBool());
+ return true;
+ } else
+ return false;
+ }
}
}
return false;
@@ -1940,4 +1972,7 @@ UserSettingsModel::UserSettingsModel(QObject *p)
connect(MainWindow::instance(), &MainWindow::secretsChanged, this, [this]() {
emit dataChanged(index(OnlineBackupKey), index(MasterKey), {Value, Good});
});
+ connect(s.get(), &UserSettings::exposeDBusApiChanged, this, [this] {
+ emit dataChanged(index(ExposeDBusApi), index(ExposeDBusApi), {Value});
+ });
}
diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index c34bf1fc..bcc45cdc 100644
--- a/src/UserSettingsPage.h
+++ b/src/UserSettingsPage.h
@@ -115,6 +115,8 @@ class UserSettings : public QObject
recentReactionsChanged)
Q_PROPERTY(QStringList hiddenWidgets READ hiddenWidgets WRITE setHiddenWidgets NOTIFY
hiddenWidgetsChanged)
+ Q_PROPERTY(
+ bool exposeDBusApi READ exposeDBusApi WRITE setExposeDBusApi NOTIFY exposeDBusApiChanged)
UserSettings();
@@ -191,6 +193,7 @@ public:
void setOpenImageExternal(bool state);
void setOpenVideoExternal(bool state);
void setCollapsedSpaces(QList<QStringList> spaces);
+ void setExposeDBusApi(bool state);
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
bool messageHoverHighlight() const { return messageHoverHighlight_; }
@@ -255,6 +258,7 @@ public:
bool openImageExternal() const { return openImageExternal_; }
bool openVideoExternal() const { return openVideoExternal_; }
QList<QStringList> collapsedSpaces() const { return collapsedSpaces_; }
+ bool exposeDBusApi() const { return exposeDBusApi_; }
signals:
void groupViewStateChanged(bool state);
@@ -310,6 +314,7 @@ signals:
void hiddenPinsChanged();
void hiddenWidgetsChanged();
void recentReactionsChanged();
+ void exposeDBusApiChanged(bool state);
private:
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
@@ -373,6 +378,7 @@ private:
bool useIdenticon_;
bool openImageExternal_;
bool openVideoExternal_;
+ bool exposeDBusApi_;
QSettings settings;
@@ -398,6 +404,9 @@ class UserSettingsModel : public QAbstractListModel
UseIdenticon,
PrivacyScreen,
PrivacyScreenTimeout,
+#ifdef NHEKO_DBUS_SYS
+ ExposeDBusApi,
+#endif
TimelineSection,
TimelineMaxWidth,
@@ -458,6 +467,9 @@ class UserSettingsModel : public QAbstractListModel
#ifdef Q_OS_MAC
ScaleFactor,
#endif
+#ifndef NHEKO_DBUS_SYS
+ ExposeDBusApi,
+#endif
};
public:
diff --git a/src/dbus/NhekoDBusApi.cpp b/src/dbus/NhekoDBusApi.cpp
new file mode 100644
index 00000000..edc3fa8a
--- /dev/null
+++ b/src/dbus/NhekoDBusApi.cpp
@@ -0,0 +1,166 @@
+// SPDX-FileCopyrightText: 2010 David Sansome <me@davidsansome.com>
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "NhekoDBusApi.h"
+
+#include <QDBusMetaType>
+
+namespace nheko::dbus {
+void
+init()
+{
+ qDBusRegisterMetaType<RoomInfoItem>();
+ qDBusRegisterMetaType<QVector<RoomInfoItem>>();
+ qDBusRegisterMetaType<QImage>();
+ qDBusRegisterMetaType<QVersionNumber>();
+}
+
+bool
+apiVersionIsCompatible(const QVersionNumber &clientAppVersion)
+{
+ if (clientAppVersion.majorVersion() != nheko::dbus::apiVersion.majorVersion())
+ return false;
+ if (clientAppVersion.minorVersion() > nheko::dbus::apiVersion.minorVersion())
+ return false;
+ if (clientAppVersion.minorVersion() == nheko::dbus::apiVersion.minorVersion() &&
+ clientAppVersion.microVersion() < nheko::dbus::apiVersion.microVersion())
+ return false;
+
+ return true;
+}
+
+RoomInfoItem::RoomInfoItem(const QString &roomId,
+ const QString &alias,
+ const QString &title,
+ const QImage &image,
+ const int unreadNotifications,
+ QObject *parent)
+ : QObject{parent}
+ , roomId_{roomId}
+ , alias_{alias}
+ , roomName_{title}
+ , image_{image}
+ , unreadNotifications_{unreadNotifications}
+{}
+
+RoomInfoItem::RoomInfoItem(const RoomInfoItem &other)
+ : QObject{other.parent()}
+ , roomId_{other.roomId_}
+ , alias_{other.alias_}
+ , roomName_{other.roomName_}
+ , image_{other.image_}
+ , unreadNotifications_{other.unreadNotifications_}
+{}
+
+RoomInfoItem &
+RoomInfoItem::operator=(const RoomInfoItem &other)
+{
+ roomId_ = other.roomId_;
+ alias_ = other.alias_;
+ roomName_ = other.roomName_;
+ image_ = other.image_;
+ unreadNotifications_ = other.unreadNotifications_;
+ return *this;
+}
+
+QDBusArgument &
+operator<<(QDBusArgument &arg, const RoomInfoItem &item)
+{
+ arg.beginStructure();
+ arg << item.roomId_ << item.alias_ << item.roomName_ << item.image_
+ << item.unreadNotifications_;
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &
+operator>>(const QDBusArgument &arg, RoomInfoItem &item)
+{
+ arg.beginStructure();
+ arg >> item.roomId_ >> item.alias_ >> item.roomName_ >> item.image_ >>
+ item.unreadNotifications_;
+ if (item.image_.isNull())
+ item.image_ = QImage{QStringLiteral(":/icons/ui/speech-bubbles.svg")};
+
+ arg.endStructure();
+ return arg;
+}
+} // nheko::dbus
+
+/**
+ * Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify
+ *
+ * This function is heavily based on a function from the Clementine project (see
+ * http://www.clementine-player.org) and licensed under the GNU General Public
+ * License, version 3 or later.
+ *
+ * SPDX-FileCopyrightText: 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 i = image.height() > 100 || image.width() > 100
+ ? image.scaledToHeight(100, Qt::SmoothTransformation)
+ : image;
+ i = std::move(i).convertToFormat(QImage::Format_RGBA8888);
+
+ 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.sizeInBytes());
+ arg.endStructure();
+
+ return arg;
+}
+
+// This function, however, was merely reverse-engineered from the above function
+// and is not from the Clementine project.
+const QDBusArgument &
+operator>>(const QDBusArgument &arg, QImage &image)
+{
+ // garbage is used as a sort of /dev/null
+ int width, height, garbage;
+ QByteArray bits;
+
+ arg.beginStructure();
+ arg >> width >> height >> garbage >> garbage >> garbage >> garbage >> bits;
+ arg.endStructure();
+
+ image = QImage(reinterpret_cast<uchar *>(bits.data()), width, height, QImage::Format_RGBA8888);
+
+ return arg;
+}
+
+QDBusArgument &
+operator<<(QDBusArgument &arg, const QVersionNumber &v)
+{
+ arg.beginStructure();
+ arg << v.toString();
+ arg.endStructure();
+ return arg;
+}
+
+const QDBusArgument &
+operator>>(const QDBusArgument &arg, QVersionNumber &v)
+{
+ arg.beginStructure();
+ QString temp;
+ arg >> temp;
+ v = QVersionNumber::fromString(temp);
+ arg.endStructure();
+ return arg;
+}
diff --git a/src/dbus/NhekoDBusApi.h b/src/dbus/NhekoDBusApi.h
new file mode 100644
index 00000000..47cc108a
--- /dev/null
+++ b/src/dbus/NhekoDBusApi.h
@@ -0,0 +1,80 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NHEKODBUSAPI_H
+#define NHEKODBUSAPI_H
+
+#include <QDBusArgument>
+#include <QIcon>
+#include <QObject>
+#include <QVersionNumber>
+
+namespace nheko::dbus {
+
+//! Registers all necessary classes with D-Bus. Call this before using any nheko D-Bus classes.
+void
+init();
+
+//! The nheko D-Bus API version provided by this file. The API version number follows semantic
+//! versioning as defined by https://semver.org.
+const QVersionNumber apiVersion{0, 0, 1};
+
+//! Compare the installed Nheko API to the version that your client app targets to see if they
+//! are compatible.
+bool
+apiVersionIsCompatible(const QVersionNumber &clientAppVersion);
+
+class RoomInfoItem : public QObject
+{
+ Q_OBJECT
+
+public:
+ RoomInfoItem(const QString &roomId = QString{},
+ const QString &alias = QString{},
+ const QString &title = QString{},
+ const QImage &image = QImage{},
+ const int unreadNotifications = 0,
+ QObject *parent = nullptr);
+
+ RoomInfoItem(const RoomInfoItem &other);
+
+ const QString &roomId() const { return roomId_; }
+ const QString &alias() const { return alias_; }
+ const QString &roomName() const { return roomName_; }
+ const QImage &image() const { return image_; }
+ int unreadNotifications() const { return unreadNotifications_; }
+
+ RoomInfoItem &operator=(const RoomInfoItem &other);
+ friend QDBusArgument &operator<<(QDBusArgument &arg, const nheko::dbus::RoomInfoItem &item);
+ friend const QDBusArgument &
+ operator>>(const QDBusArgument &arg, nheko::dbus::RoomInfoItem &item);
+
+private:
+ QString roomId_;
+ QString alias_;
+ QString roomName_;
+ QImage image_;
+ int unreadNotifications_;
+};
+
+QDBusArgument &
+operator<<(QDBusArgument &arg, const RoomInfoItem &item);
+const QDBusArgument &
+operator>>(const QDBusArgument &arg, RoomInfoItem &item);
+} // nheko::dbus
+Q_DECLARE_METATYPE(nheko::dbus::RoomInfoItem)
+
+QDBusArgument &
+operator<<(QDBusArgument &arg, const QImage &image);
+const QDBusArgument &
+operator>>(const QDBusArgument &arg, QImage &);
+
+QDBusArgument &
+operator<<(QDBusArgument &arg, const QVersionNumber &v);
+const QDBusArgument &
+operator>>(const QDBusArgument &arg, QVersionNumber &v);
+
+#define NHEKO_DBUS_SERVICE_NAME "io.github.Nheko-Reborn.nheko"
+
+#endif // NHEKODBUSAPI_H
diff --git a/src/dbus/NhekoDBusBackend.cpp b/src/dbus/NhekoDBusBackend.cpp
new file mode 100644
index 00000000..3645aea6
--- /dev/null
+++ b/src/dbus/NhekoDBusBackend.cpp
@@ -0,0 +1,87 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "NhekoDBusBackend.h"
+
+#include "Cache_p.h"
+#include "ChatPage.h"
+#include "Logging.h"
+#include "MainWindow.h"
+#include "MxcImageProvider.h"
+#include "timeline/RoomlistModel.h"
+
+#include <QDBusConnection>
+
+NhekoDBusBackend::NhekoDBusBackend(RoomlistModel *parent)
+ : QObject{parent}
+ , m_parent{parent}
+{}
+
+QVector<nheko::dbus::RoomInfoItem>
+NhekoDBusBackend::getRooms(const QDBusMessage &message)
+{
+ const auto roomListModel = m_parent->models;
+ QSharedPointer<QVector<nheko::dbus::RoomInfoItem>> model{
+ new QVector<nheko::dbus::RoomInfoItem>};
+
+ for (const auto &room : roomListModel) {
+ MainWindow::instance()->imageProvider()->download(
+ room->roomAvatarUrl().remove("mxc://"),
+ {96, 96},
+ [message, room, model, roomListModel](
+ const QString &, const QSize &, const QImage &image, const QString &) {
+ const auto aliases = cache::client()->getRoomAliases(room->roomId().toStdString());
+ QString alias;
+ if (aliases.has_value()) {
+ const auto &val = aliases.value();
+ if (!val.alias.empty())
+ alias = QString::fromStdString(val.alias);
+ else if (val.alt_aliases.size() > 0)
+ alias = QString::fromStdString(val.alt_aliases.front());
+ }
+
+ model->push_back(nheko::dbus::RoomInfoItem{
+ room->roomId(), room->roomName(), alias, image, room->notificationCount()});
+
+ if (model->length() == roomListModel.size()) {
+ auto reply = message.createReply();
+ nhlog::ui()->debug("Sending {} rooms over D-Bus...", model->size());
+ reply << QVariant::fromValue(*model);
+ QDBusConnection::sessionBus().send(reply);
+ nhlog::ui()->debug("Rooms successfully sent to D-Bus.");
+ }
+ },
+ true);
+ }
+
+ return {};
+}
+
+void
+NhekoDBusBackend::activateRoom(const QString &alias) const
+{
+ bringWindowToTop();
+ m_parent->setCurrentRoom(alias);
+}
+
+void
+NhekoDBusBackend::joinRoom(const QString &alias) const
+{
+ bringWindowToTop();
+ ChatPage::instance()->joinRoom(alias);
+}
+
+void
+NhekoDBusBackend::startDirectChat(const QString &userId) const
+{
+ bringWindowToTop();
+ ChatPage::instance()->startChat(userId);
+}
+
+void
+NhekoDBusBackend::bringWindowToTop() const
+{
+ MainWindow::instance()->show();
+ MainWindow::instance()->raise();
+}
diff --git a/src/dbus/NhekoDBusBackend.h b/src/dbus/NhekoDBusBackend.h
new file mode 100644
index 00000000..02fd87d5
--- /dev/null
+++ b/src/dbus/NhekoDBusBackend.h
@@ -0,0 +1,45 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NHEKODBUSBACKEND_H
+#define NHEKODBUSBACKEND_H
+
+#include <QDBusMessage>
+#include <QObject>
+
+#include "NhekoDBusApi.h"
+#include "config/nheko.h"
+
+class RoomlistModel;
+
+class NhekoDBusBackend : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "im.nheko.Nheko")
+
+public:
+ NhekoDBusBackend(RoomlistModel *parent);
+
+public slots:
+ //! Get the nheko D-Bus API version.
+ Q_SCRIPTABLE QVersionNumber apiVersion() const { return nheko::dbus::apiVersion; }
+ //! Get the nheko version.
+ Q_SCRIPTABLE QString nhekoVersionString() const { return nheko::version; }
+ //! Call this function to get a list of all joined rooms.
+ Q_SCRIPTABLE QVector<nheko::dbus::RoomInfoItem> getRooms(const QDBusMessage &message);
+ //! Activates a currently joined room.
+ Q_SCRIPTABLE void activateRoom(const QString &alias) const;
+ //! Joins a room. It is your responsibility to ask for confirmation (if desired).
+ Q_SCRIPTABLE void joinRoom(const QString &alias) const;
+ //! Starts or activates a direct chat. It is your responsibility to ask for confirmation (if
+ //! desired).
+ Q_SCRIPTABLE void startDirectChat(const QString &userId) const;
+
+private:
+ void bringWindowToTop() const;
+
+ RoomlistModel *m_parent;
+};
+
+#endif // NHEKODBUSBACKEND_H
diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h
index 2a399a27..0a5f4caa 100644
--- a/src/notifications/Manager.h
+++ b/src/notifications/Manager.h
@@ -11,11 +11,6 @@
#include <mtx/responses/notifications.hpp>
-// convenience definition
-#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_HAIKU)
-#define NHEKO_DBUS_SYS
-#endif
-
#if defined(NHEKO_DBUS_SYS)
#include <QtDBus/QDBusArgument>
#include <QtDBus/QDBusInterface>
diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp
index 76f290a8..225a6533 100644
--- a/src/notifications/ManagerLinux.cpp
+++ b/src/notifications/ManagerLinux.cpp
@@ -27,6 +27,7 @@
#include "MxcImageProvider.h"
#include "UserSettingsPage.h"
#include "Utils.h"
+#include "dbus/NhekoDBusApi.h"
NotificationsManager::NotificationsManager(QObject *parent)
: QObject(parent)
@@ -269,49 +270,3 @@ 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.
- *
- * SPDX-FileCopyrightText: 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 i = image.height() > 100 || image.width() > 100
- ? image.scaledToHeight(100, Qt::SmoothTransformation)
- : image;
- i = std::move(i).convertToFormat(QImage::Format_RGBA8888);
-
- arg.beginStructure();
- arg << i.width();
- arg << i.height();
- arg << i.bytesPerLine();
- arg << i.hasAlphaChannel();
- int channels = i.hasAlphaChannel() ? 4 : 3;
- arg << i.depth() / channels;
- arg << channels;
- arg << QByteArray(reinterpret_cast<const char *>(i.bits()), i.sizeInBytes());
- 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/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 31e5a33d..ea4f6fa8 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -15,6 +15,10 @@
#include "TimelineViewManager.h"
#include "UserSettingsPage.h"
+#ifdef NHEKO_DBUS_SYS
+#include <QDBusConnection>
+#endif
+
RoomlistModel::RoomlistModel(TimelineViewManager *parent)
: QAbstractListModel(parent)
, manager(parent)
@@ -604,6 +608,15 @@ RoomlistModel::initializeRooms()
nhlog::db()->info("Restored {} rooms from cache", rowCount());
endResetModel();
+
+#ifdef NHEKO_DBUS_SYS
+ if (MainWindow::instance()->dbusAvailable()) {
+ dbusInterface_ = new NhekoDBusBackend{this};
+ if (!QDBusConnection::sessionBus().registerObject(
+ "/", dbusInterface_, QDBusConnection::ExportScriptableSlots))
+ nhlog::ui()->warn("Failed to register rooms with D-Bus");
+ }
+#endif
}
void
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 73ccd929..9546d434 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -17,6 +17,10 @@
#include "TimelineModel.h"
+#ifdef NHEKO_DBUS_SYS
+#include "dbus/NhekoDBusBackend.h"
+#endif
+
class TimelineViewManager;
class RoomPreview
@@ -138,6 +142,11 @@ private:
std::map<QString, std::vector<QString>> directChatToUser;
+#ifdef NHEKO_DBUS_SYS
+ NhekoDBusBackend *dbusInterface_;
+ friend class NhekoDBusBackend;
+#endif
+
friend class FilteredRoomlistModel;
};
|