Skip to content

Commit

Permalink
feat: Add DBus desktop notification support.
Browse files Browse the repository at this point in the history
This is nicer than the Qt built-in tray notifications. It only works on
Linux. On other systems, tray notifications are pretty ok.
  • Loading branch information
iphydf committed Dec 11, 2024
1 parent 24b3643 commit 1897c1d
Show file tree
Hide file tree
Showing 67 changed files with 1,002 additions and 50 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ set(${PROJECT_NAME}_SOURCES
src/platform/capslock_x11.cpp
src/platform/desktop_notifications/desktopnotify.cpp
src/platform/desktop_notifications/desktopnotify.h
src/platform/desktop_notifications/desktopnotifybackend_dbus.cpp
src/platform/desktop_notifications/desktopnotifybackend_noop.cpp
src/platform/desktop_notifications/desktopnotifybackend.h
src/platform/posixsignalnotifier.cpp
src/platform/posixsignalnotifier.h
src/platform/timer.h
Expand Down
8 changes: 8 additions & 0 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ add_dependency(
Qt6::Widgets
Qt6::Xml)

# Optional dependency for desktop notifications.
find_package(Qt6DBus)

if(Qt6DBus_FOUND)
add_dependency(Qt6::DBus)
message(STATUS "Using DBus for desktop notifications")
endif()

include(CMakeParseArguments)

set(TOXCORE_MINIMUM_VERSION "0.2.20")
Expand Down
2 changes: 2 additions & 0 deletions src/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ qt_moc(
"persistence/settings.h",
"persistence/smileypack.h",
"platform/desktop_notifications/desktopnotify.h",
"platform/desktop_notifications/desktopnotifybackend_dbus.h",
"platform/posixsignalnotifier.h",
"video/camerasource.h",
"video/corevideosource.h",
Expand Down Expand Up @@ -203,6 +204,7 @@ cc_library(
"@openal",
"@qt//:qt_concurrent",
"@qt//:qt_core",
"@qt//:qt_dbus",
"@qt//:qt_gui",
"@qt//:qt_network",
"@qt//:qt_svg",
Expand Down
5 changes: 4 additions & 1 deletion src/persistence/inotificationsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ class INotificationSettings
virtual void setShowWindow(bool newValue) = 0;

virtual bool getDesktopNotify() const = 0;
virtual void setDesktopNotify(bool enabled) = 0;
virtual void setDesktopNotify(bool newValue) = 0;

virtual bool getNotifySystemBackend() const = 0;
virtual void setNotifySystemBackend(bool newValue) = 0;

virtual bool getNotifySound() const = 0;
virtual void setNotifySound(bool newValue) = 0;
Expand Down
21 changes: 18 additions & 3 deletions src/persistence/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ void Settings::loadGlobal()
showWindow = s.value("showWindow", true).toBool();
notify = s.value("notify", true).toBool();
desktopNotify = s.value("desktopNotify", true).toBool();
notifySystemBackend = s.value("notifySystemBackend", true).toBool();
conferenceAlwaysNotify = s.value("conferenceAlwaysNotify", true).toBool();
conferencePosition = s.value("conferencePosition", true).toBool();
separateWindow = s.value("separateWindow", false).toBool();
Expand Down Expand Up @@ -658,6 +659,7 @@ void Settings::saveGlobal()
s.setValue("showWindow", showWindow);
s.setValue("notify", notify);
s.setValue("desktopNotify", desktopNotify);
s.setValue("notifySystemBackend", notifySystemBackend);
s.setValue("conferenceAlwaysNotify", conferenceAlwaysNotify);
s.setValue("separateWindow", separateWindow);
s.setValue("dontGroupWindows", dontGroupWindows);
Expand Down Expand Up @@ -1616,10 +1618,23 @@ bool Settings::getDesktopNotify() const
return desktopNotify;
}

void Settings::setDesktopNotify(bool enabled)
void Settings::setDesktopNotify(bool newValue)
{
if (setVal(desktopNotify, enabled)) {
emit desktopNotifyChanged(enabled);
if (setVal(desktopNotify, newValue)) {
emit desktopNotifyChanged(newValue);
}
}

bool Settings::getNotifySystemBackend() const
{
QMutexLocker<QRecursiveMutex> locker{&bigLock};
return notifySystemBackend;
}

void Settings::setNotifySystemBackend(bool newValue)
{
if (setVal(notifySystemBackend, newValue)) {
emit notifySystemBackendChanged(newValue);
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/persistence/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public slots:
void minimizeToTrayChanged(bool enabled);
void notifyChanged(bool enabled);
void desktopNotifyChanged(bool enabled);
void notifySystemBackendChanged(bool enabled);
void showWindowChanged(bool enabled);
void makeToxPortableChanged(bool enabled);
void busySoundChanged(bool enabled);
Expand Down Expand Up @@ -315,7 +316,10 @@ public slots:
void setShowWindow(bool newValue) override;

bool getDesktopNotify() const override;
void setDesktopNotify(bool enabled) override;
void setDesktopNotify(bool newValue) override;

bool getNotifySystemBackend() const override;
void setNotifySystemBackend(bool newValue) override;

bool getNotifySound() const override;
void setNotifySound(bool newValue) override;
Expand Down Expand Up @@ -597,6 +601,7 @@ private slots:
bool checkUpdates;
bool notify;
bool desktopNotify;
bool notifySystemBackend;
bool showWindow;
bool notifySound;
bool notifyHide;
Expand Down
45 changes: 35 additions & 10 deletions src/platform/desktop_notifications/desktopnotify.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2019 by The qTox Project Contributors
* Copyright © 2024 The TokTok team.
*/

#include "desktopnotify.h"

#include "src/persistence/settings.h"
#include "desktopnotifybackend.h"
#include "src/persistence/inotificationsettings.h"

#include <QSystemTrayIcon>

DesktopNotify::DesktopNotify(Settings& settings, QSystemTrayIcon* icon)
: settings_{settings}
, icon_{icon}
struct DesktopNotify::Private
{
if (icon_) {
connect(icon_, &QSystemTrayIcon::messageClicked, this, &DesktopNotify::notificationClosed);
INotificationSettings& settings;
QSystemTrayIcon* icon;
DesktopNotifyBackend* dbus;
};

DesktopNotify::DesktopNotify(INotificationSettings& settings, QObject* parent)
: QObject(parent)
, d{std::make_unique<Private>(Private{
settings,
nullptr,
new DesktopNotifyBackend(this),
})}
{
connect(d->dbus, &DesktopNotifyBackend::messageClicked, this, &DesktopNotify::notificationClosed);
if (d->icon) {
connect(d->icon, &QSystemTrayIcon::messageClicked, this, &DesktopNotify::notificationClosed);
}
}

DesktopNotify::~DesktopNotify() = default;

void DesktopNotify::setIcon(QSystemTrayIcon* icon)
{
d->icon = icon;
}

void DesktopNotify::notifyMessage(const NotificationData& notificationData)
{
if (!(settings_.getNotify() && settings_.getDesktopNotify())) {
if (!(d->settings.getNotify() && d->settings.getDesktopNotify())) {
return;
}

if (icon_) {
icon_->showMessage(notificationData.title, notificationData.message, notificationData.pixmap);
// Try system-backends first.
if (d->settings.getNotifySystemBackend()) {
if (d->dbus->showMessage(notificationData.title, notificationData.message, notificationData.pixmap)) {
return;
}
}

// Fallback to QSystemTrayIcon.
if (d->icon) {
d->icon->showMessage(notificationData.title, notificationData.message, notificationData.pixmap);
}
}
30 changes: 19 additions & 11 deletions src/platform/desktop_notifications/desktopnotify.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,37 @@

#include <QObject>

class QSystemTrayIcon;
class Settings;
#include <memory>

class QSystemTrayIcon;
class INotificationSettings;

/**
* @brief Show desktop notifications.
*
* Icon is optional, if not provided, no notifications will be shown unless
* another backend exists.
*
* If DBus is available and a desktop notification server responds to us,
* it is preferred over tray notifications.
*/
class DesktopNotify : public QObject
{
Q_OBJECT

public:
/**
* Icon is optional, if not provided, no notifications will be shown.
*
* In the future, we may implement a fallback notification system if there's no
* system tray available.
*/
DesktopNotify(Settings& settings, QSystemTrayIcon* icon);
DesktopNotify(INotificationSettings& settings, QObject* parent);
~DesktopNotify();

void setIcon(QSystemTrayIcon* icon);

public slots:
void notifyMessage(const NotificationData& notificationData);

signals:
void notificationClosed();

private:
Settings& settings_;
QSystemTrayIcon* icon_;
struct Private;
const std::unique_ptr<Private> d;
};
31 changes: 31 additions & 0 deletions src/platform/desktop_notifications/desktopnotifybackend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2024 The TokTok team.
*/

#pragma once

#include <QObject>

#include <memory>

class DesktopNotifyBackend : public QObject
{
Q_OBJECT

public:
explicit DesktopNotifyBackend(QObject* parent);
~DesktopNotifyBackend();

bool showMessage(const QString& title, const QString& message, const QPixmap& pixmap);

signals:
void messageClicked();

private slots:
void notificationActionInvoked(QString actionKey, QString actionValue);
void notificationActionInvoked(uint actionKey, QString actionValue);

private:
struct Private;
const std::unique_ptr<Private> d;
};
Loading

0 comments on commit 1897c1d

Please sign in to comment.