Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Linux support for Live Notifications toasts w/ libnotify #5881

Merged
merged 2 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .CI/CreateUbuntuDeb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ deb_path="Chatterino-ubuntu-${ubuntu_release}-x86_64.deb"
case "$ubuntu_release" in
20.04)
# Qt6 static-linked deb, see https://github.com/Chatterino/docker
dependencies="libc6, libstdc++6, libblkid1, libbsd0, libexpat1, libffi7, libfontconfig1, libfreetype6, libglib2.0-0, libglvnd0, libglx0, libgraphite2-3, libharfbuzz0b, libicu66, libjpeg-turbo8, libmount1, libopengl0, libpcre2-16-0, libpcre3, libpng16-16, libselinux1, libssl1.1, libuuid1, libx11-xcb1, libxau6, libxcb1, libxcb-cursor0, libxcb-glx0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0, libxcb-render0, libxcb-render-util0, libxcb-shape0, libxcb-shm0, libxcb-sync1, libxcb-util1, libxcb-xfixes0, libxcb-xkb1, libxdmcp6, libxkbcommon0, libxkbcommon-x11-0, zlib1g"
dependencies="libc6, libstdc++6, libblkid1, libbsd0, libexpat1, libffi7, libfontconfig1, libfreetype6, libglib2.0-0, libglvnd0, libglx0, libgraphite2-3, libharfbuzz0b, libicu66, libjpeg-turbo8, libmount1, libnotify4, libopengl0, libpcre2-16-0, libpcre3, libpng16-16, libselinux1, libssl1.1, libuuid1, libx11-xcb1, libxau6, libxcb1, libxcb-cursor0, libxcb-glx0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0, libxcb-render0, libxcb-render-util0, libxcb-shape0, libxcb-shm0, libxcb-sync1, libxcb-util1, libxcb-xfixes0, libxcb-xkb1, libxdmcp6, libxkbcommon0, libxkbcommon-x11-0, zlib1g"
;;
22.04)
# Qt6 static-linked deb, see https://github.com/Chatterino/docker
dependencies="libc6, libstdc++6, libglx0, libopengl0, libpng16-16, libharfbuzz0b, libfreetype6, libfontconfig1, libjpeg-turbo8, libxcb-glx0, libegl1, libx11-6, libxkbcommon0, libx11-xcb1, libxkbcommon-x11-0, libxcb-cursor0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0, libxcb-render-util0, libxcb-shm0, libxcb-sync1, libxcb-xfixes0, libxcb-render0, libxcb-shape0, libxcb-xkb1, libxcb1, libbrotli1, libglib2.0-0, zlib1g, libicu70, libpcre2-16-0, libssl3, libgraphite2-3, libexpat1, libuuid1, libxcb-util1, libxau6, libxdmcp6, libffi8, libmount1, libselinux1, libpcre3, libbsd0, libblkid1, libpcre2-8-0, libmd0"
dependencies="libc6, libstdc++6, libglx0, libopengl0, libpng16-16, libharfbuzz0b, libfreetype6, libfontconfig1, libjpeg-turbo8, libxcb-glx0, libegl1, libx11-6, libxkbcommon0, libx11-xcb1, libxkbcommon-x11-0, libxcb-cursor0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0, libxcb-render-util0, libxcb-shm0, libxcb-sync1, libxcb-xfixes0, libxcb-render0, libxcb-shape0, libxcb-xkb1, libxcb1, libbrotli1, libglib2.0-0, zlib1g, libicu70, libpcre2-16-0, libssl3, libgraphite2-3, libexpat1, libuuid1, libxcb-util1, libxau6, libxdmcp6, libffi8, libmount1, libnotify4, libselinux1, libpcre3, libbsd0, libblkid1, libpcre2-8-0, libmd0"
;;
24.04)
# Qt6 static-linked deb, see https://github.com/Chatterino/docker
dependencies="libc6, libstdc++6, libglx0, libopengl0, libpng16-16, libharfbuzz0b, libfreetype6, libfontconfig1, libjpeg-turbo8, libxcb-glx0, libegl1, libx11-6, libxkbcommon0, libx11-xcb1, libxkbcommon-x11-0, libxcb-cursor0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0, libxcb-render-util0, libxcb-shm0, libxcb-sync1, libxcb-xfixes0, libxcb-render0, libxcb-shape0, libxcb-xkb1, libxcb1, libbrotli1, libglib2.0-0, zlib1g, libicu74, libpcre2-16-0, libssl3, libgraphite2-3, libexpat1, libuuid1, libxcb-util1, libxau6, libxdmcp6, libffi8, libmount1, libselinux1, libpcre3, libbsd0, libblkid1, libpcre2-8-0, libmd0"
dependencies="libc6, libstdc++6, libglx0, libopengl0, libpng16-16, libharfbuzz0b, libfreetype6, libfontconfig1, libjpeg-turbo8, libxcb-glx0, libegl1, libx11-6, libxkbcommon0, libx11-xcb1, libxkbcommon-x11-0, libxcb-cursor0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0, libxcb-render-util0, libxcb-shm0, libxcb-sync1, libxcb-xfixes0, libxcb-render0, libxcb-shape0, libxcb-xkb1, libxcb1, libbrotli1, libglib2.0-0, zlib1g, libicu74, libpcre2-16-0, libssl3, libgraphite2-3, libexpat1, libuuid1, libxcb-util1, libxau6, libxdmcp6, libffi8, libmount1, libnotify4, libselinux1, libpcre3, libbsd0, libblkid1, libpcre2-8-0, libmd0"
;;
*)
echo "Unsupported Ubuntu release $ubuntu_release"
Expand Down
2 changes: 1 addition & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ freebsd_instance:

task:
install_script:
- pkg install -y boost-libs git qt6-base qt6-svg qt6-5compat qt6-imageformats qtkeychain-qt6 cmake
- pkg install -y boost-libs git libnotify qt6-base qt6-svg qt6-5compat qt6-imageformats qtkeychain-qt6 cmake pkgconf
script: |
git submodule init
git submodule update
Expand Down
2 changes: 2 additions & 0 deletions .docker/Dockerfile-ubuntu-20.04-base
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ RUN apt-get update && apt-get -y install --no-install-recommends \
libxcb-randr0-dev \
libboost-system-dev \
libboost-filesystem-dev \
libnotify4 \
libnotify-dev \
libpulse-dev \
libxkbcommon-x11-0 \
build-essential \
Expand Down
2 changes: 2 additions & 0 deletions .docker/Dockerfile-ubuntu-22.04-base
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ RUN apt-get update && apt-get -y install --no-install-recommends \
libxcb-randr0-dev \
libboost-system-dev \
libboost-filesystem-dev \
libnotify4 \
libnotify-dev \
libpulse-dev \
libxkbcommon-x11-0 \
build-essential \
Expand Down
2 changes: 2 additions & 0 deletions .docker/Dockerfile-ubuntu-22.04-qt6-build
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ RUN apt-get update && apt-get -y install --no-install-recommends \
libxcb-randr0-dev \
libboost-system-dev \
libboost-filesystem-dev \
libnotify4 \
libnotify-dev \
libpulse-dev \
libxkbcommon-x11-0 \
build-essential \
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/clang-tidy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
rapidjson-dev,
libbenchmark-dev,
build-essential,
libnotify4, libnotify-dev,
libgl1-mesa-dev, libgstreamer-gl1.0-0, libpulse-dev,
libxcb-glx0, libxcb-icccm4, libxcb-image0, libxcb-keysyms1, libxcb-randr0,
libxcb-render-util0, libxcb-render0, libxcb-shape0, libxcb-shm0, libxcb-sync1,
Expand Down
2 changes: 1 addition & 1 deletion BUILDING_ON_FREEBSD.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ high that this also works on older FreeBSD releases, architectures and
FreeBSD 15.0-SNAP.

1. Install build dependencies from package sources (or build from the
ports tree): `# pkg install boost-libs git qt6-base qt6-svg qt6-5compat qt6-imageformats qtkeychain-qt6 cmake`
ports tree): `# pkg install boost-libs git libnotify qt6-base qt6-svg qt6-5compat qt6-imageformats qtkeychain-qt6 cmake`
1. In the project directory, create a build directory and enter it
```sh
mkdir build
Expand Down
8 changes: 4 additions & 4 deletions BUILDING_ON_LINUX.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ The built binary should be exportable from the final image & able to run on your
### Debian 12 (bookworm) or later

```sh
sudo apt install qt6-base-dev qt6-5compat-dev qt6-svg-dev qt6-image-formats-plugins libboost1.81-dev libssl-dev cmake g++ git
sudo apt install qt6-base-dev qt6-5compat-dev qt6-svg-dev qt6-image-formats-plugins libboost1.81-dev libnotify-dev libssl-dev cmake g++ git
```

### Arch Linux

```sh
sudo pacman -S --needed qt6-base qt6-tools boost-libs openssl qt6-imageformats qt6-5compat qt6-svg boost rapidjson pkgconf openssl cmake
sudo pacman -S --needed qt6-base qt6-tools boost-libs openssl qt6-imageformats qt6-5compat qt6-svg boost libnotify rapidjson pkgconf openssl cmake
```

If you use Wayland, you will also need to ensure `qt6-wayland` is installed.
Expand All @@ -35,13 +35,13 @@ Alternatively you can use the [chatterino2-git](https://aur.archlinux.org/packag
_Most likely works the same for other Red Hat-like distros. Substitute `dnf` with `yum`._

```sh
sudo dnf install qt6-qtbase-devel qt6-qtimageformats qt6-qtsvg-devel qt6-qt5compat-devel g++ git openssl-devel boost-devel cmake
sudo dnf install qt6-qtbase-devel qt6-qtimageformats qt6-qtsvg-devel qt6-qt5compat-devel g++ git openssl-devel boost-devel libnotify-devel cmake
```

### NixOS 18.09+

```sh
nix-shell -p openssl boost qt6.full pkg-config cmake
nix-shell -p openssl boost qt6.full pkg-config cmake libnotify
```

## Compile
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Minor: When (re-)connecting, visible channels are now joined first. (#5850)
- Minor: Added the ability to filter on messages by the author's user ID (example: `author.user_id == "22484632"`). (#5862)
- Minor: Improved error messaging of the `/clip` command. (#5879)
- Minor: Added Linux support for Live Notifications toasts. (#5881)
- Bugfix: Fixed a potential way to escape the Lua Plugin sandbox. (#5846)
- Bugfix: Fixed a crash relating to Lua HTTP. (#5800)
- Bugfix: Fixed a crash that could occur on Linux and macOS when clicking "Install" from the update prompt. (#5818)
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ option(USE_SYSTEM_MINIAUDIO "Build Chatterino with your system miniaudio" OFF)
option(BUILD_WITH_CRASHPAD "Build chatterino with crashpad" OFF)
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
option(BUILD_WITH_QT6 "Build with Qt6" On)
option(BUILD_WITH_LIBNOTIFY "Build with libnotify" ON)
option(CHATTERINO_GENERATE_COVERAGE "Generate coverage files" OFF)
# We don't use translations, and we don't want qtkeychain to build translations
option(BUILD_TRANSLATIONS "" OFF)
Expand Down
7 changes: 7 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,13 @@ if (UNIX)
message(STATUS "Linking with CMake DL libs: '${CMAKE_DL_LIBS}'")
target_link_libraries(${LIBRARY_PROJECT} PUBLIC ${CMAKE_DL_LIBS})
endif ()

if (NOT APPLE AND BUILD_WITH_LIBNOTIFY)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBNOTIFY REQUIRED IMPORTED_TARGET libnotify)
target_link_libraries(${LIBRARY_PROJECT} PRIVATE PkgConfig::LIBNOTIFY)
target_compile_definitions(${LIBRARY_PROJECT} PUBLIC CHATTERINO_WITH_LIBNOTIFY)
endif ()
endif ()

if (WIN32)
Expand Down
11 changes: 11 additions & 0 deletions src/controllers/commands/builtin/chatterino/Debugging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "common/Env.hpp"
#include "common/Literals.hpp"
#include "controllers/commands/CommandContext.hpp"
#include "controllers/notifications/NotificationController.hpp"
#include "messages/Image.hpp"
#include "messages/Message.hpp"
#include "messages/MessageBuilder.hpp"
Expand All @@ -13,6 +14,7 @@
#include "providers/twitch/TwitchChannel.hpp"
#include "providers/twitch/TwitchIrcServer.hpp"
#include "singletons/Theme.hpp"
#include "singletons/Toasts.hpp"
#include "util/PostToThread.hpp"

#include <QApplication>
Expand Down Expand Up @@ -180,6 +182,15 @@ QString debugTest(const CommandContext &ctx)
.arg(nowMillis);
getApp()->getTwitch()->addFakeMessage(ircText);
}
else if (command == "desktop-notify")
{
auto title = ctx.twitchChannel->accessStreamStatus()->title;

getApp()->getToasts()->sendChannelNotification(
ctx.twitchChannel->getName(), title, Platform::Twitch);
ctx.channel->addSystemMessage(
QString("debug-test sent desktop notification"));
}
else
{
ctx.channel->addSystemMessage(
Expand Down
57 changes: 51 additions & 6 deletions src/singletons/Toasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#ifdef Q_OS_WIN
# include <wintoastlib.h>
#elif defined(CHATTERINO_WITH_LIBNOTIFY)
# include <libnotify/notify.h>
#endif

#include <QDesktopServices>
Expand Down Expand Up @@ -77,18 +79,25 @@ Toasts::~Toasts()
{
WinToast::instance()->clear();
}
#elif defined(CHATTERINO_WITH_LIBNOTIFY)
if (this->initialized_)
{
notify_uninit();
}
#endif
}

bool Toasts::isEnabled()
{
auto enabled = getSettings()->notificationToast &&
!(getApp()->getStreamerMode()->isEnabled() &&
getSettings()->streamerModeSuppressLiveNotifications);

#ifdef Q_OS_WIN
return WinToast::isCompatible() && getSettings()->notificationToast &&
!(getApp()->getStreamerMode()->isEnabled() &&
getSettings()->streamerModeSuppressLiveNotifications);
#else
return false;
enabled = enabled && WinToast::isCompatible();
#endif

return enabled;
}

QString Toasts::findStringFromReaction(const ToastReaction &reaction)
Expand Down Expand Up @@ -123,10 +132,14 @@ void Toasts::sendChannelNotification(const QString &channelName,
auto sendChannelNotification = [this, channelName, channelTitle, p] {
this->sendWindowsNotification(channelName, channelTitle, p);
};
#elif defined(CHATTERINO_WITH_LIBNOTIFY)
auto sendChannelNotification = [this, channelName, channelTitle] {
this->sendLibnotify(channelName, channelTitle);
};
#else
(void)channelTitle;
auto sendChannelNotification = [] {
// Unimplemented for macOS and Linux
// Unimplemented for macOS
};
#endif
// Fetch user profile avatar
Expand Down Expand Up @@ -282,6 +295,38 @@ void Toasts::sendWindowsNotification(const QString &channelName,
}
}

#elif defined(CHATTERINO_WITH_LIBNOTIFY)

void Toasts::ensureInitialized()
{
if (this->initialized_)
{
return;
}
auto result = notify_init("chatterino2");

if (result == 0)
{
qCWarning(chatterinoNotification) << "Failed to initialize libnotify";
}
this->initialized_ = true;
}

void Toasts::sendLibnotify(const QString &channelName,
const QString &channelTitle)
{
this->ensureInitialized();

qCDebug(chatterinoNotification) << "sending to libnotify";

QString str = channelName % u" is live!";

NotifyNotification *notif = notify_notification_new(
str.toUtf8().constData(), channelTitle.toUtf8().constData(), nullptr);

notify_notification_show(notif, nullptr);
g_object_unref(notif);
}
#endif

} // namespace chatterino
Expand Down
5 changes: 5 additions & 0 deletions src/singletons/Toasts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class Toasts final
void sendWindowsNotification(const QString &channelName,
const QString &channelTitle, Platform p);

bool initialized_ = false;
#elif defined(CHATTERINO_WITH_LIBNOTIFY)
void ensureInitialized();
void sendLibnotify(const QString &channelName, const QString &channelTitle);

bool initialized_ = false;
#endif
};
Expand Down
4 changes: 3 additions & 1 deletion src/widgets/settingspages/NotificationPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ NotificationPage::NotificationPage()
settings.append(this->createCheckBox(
"Suppress live notifications on startup",
getSettings()->suppressInitialLiveNotification));
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN) || defined(CHATTERINO_WITH_LIBNOTIFY)
settings.append(this->createCheckBox(
"Show notification", getSettings()->notificationToast));
#endif
#ifdef Q_OS_WIN
auto openIn = settings.emplace<QHBoxLayout>().withoutMargin();
{
openIn
Expand Down
Loading