diff --git a/.CI/CreateUbuntuDeb.sh b/.CI/CreateUbuntuDeb.sh index 5c31b625b56..39e01563d49 100755 --- a/.CI/CreateUbuntuDeb.sh +++ b/.CI/CreateUbuntuDeb.sh @@ -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" diff --git a/.cirrus.yml b/.cirrus.yml index 1cec7bc4815..08ba53cfad8 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -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 diff --git a/.docker/Dockerfile-ubuntu-20.04-base b/.docker/Dockerfile-ubuntu-20.04-base index d193850f085..c047c4902ea 100644 --- a/.docker/Dockerfile-ubuntu-20.04-base +++ b/.docker/Dockerfile-ubuntu-20.04-base @@ -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 \ diff --git a/.docker/Dockerfile-ubuntu-22.04-base b/.docker/Dockerfile-ubuntu-22.04-base index 5ce5b583d3c..18f86dc9bdb 100644 --- a/.docker/Dockerfile-ubuntu-22.04-base +++ b/.docker/Dockerfile-ubuntu-22.04-base @@ -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 \ diff --git a/.docker/Dockerfile-ubuntu-22.04-qt6-build b/.docker/Dockerfile-ubuntu-22.04-qt6-build index bee6f5ec925..d083b1bb653 100644 --- a/.docker/Dockerfile-ubuntu-22.04-qt6-build +++ b/.docker/Dockerfile-ubuntu-22.04-qt6-build @@ -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 \ diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index 9e0e286e429..0de37cb1ee0 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -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, diff --git a/BUILDING_ON_FREEBSD.md b/BUILDING_ON_FREEBSD.md index e7111390f05..22a08e047f2 100644 --- a/BUILDING_ON_FREEBSD.md +++ b/BUILDING_ON_FREEBSD.md @@ -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 diff --git a/BUILDING_ON_LINUX.md b/BUILDING_ON_LINUX.md index 595d932bc37..6fca34cdb01 100644 --- a/BUILDING_ON_LINUX.md +++ b/BUILDING_ON_LINUX.md @@ -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. @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8506f2387d7..41a1f96e06b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 18cc7216e64..5490287e743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e621676d4c6..24ddbe7b632 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1062,6 +1062,15 @@ 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 libnotify) + include_directories(${LIBRARY_PROJECT} ${LIBNOTIFY_INCLUDE_DIRS}) + target_link_libraries(${LIBRARY_PROJECT} PRIVATE ${LIBNOTIFY_LIBRARIES}) + target_link_directories(${LIBRARY_PROJECT} PRIVATE ${LIBNOTIFY_LIBRARY_DIRS}) + target_compile_definitions(${LIBRARY_PROJECT} PUBLIC CHATTERINO_WITH_LIBNOTIFY) + endif () endif () if (WIN32) diff --git a/src/controllers/commands/builtin/chatterino/Debugging.cpp b/src/controllers/commands/builtin/chatterino/Debugging.cpp index 3dad9f685b5..6262cda4b2f 100644 --- a/src/controllers/commands/builtin/chatterino/Debugging.cpp +++ b/src/controllers/commands/builtin/chatterino/Debugging.cpp @@ -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" @@ -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 @@ -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( diff --git a/src/singletons/Toasts.cpp b/src/singletons/Toasts.cpp index 86f7b9d1851..eef0d60a67a 100644 --- a/src/singletons/Toasts.cpp +++ b/src/singletons/Toasts.cpp @@ -16,6 +16,8 @@ #ifdef Q_OS_WIN # include +#elif defined(CHATTERINO_WITH_LIBNOTIFY) +# include #endif #include @@ -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) @@ -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 @@ -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 diff --git a/src/singletons/Toasts.hpp b/src/singletons/Toasts.hpp index b57f5c3f995..a945f11bf89 100644 --- a/src/singletons/Toasts.hpp +++ b/src/singletons/Toasts.hpp @@ -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 }; diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index 005f6ef843b..a6f20d011a2 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -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().withoutMargin(); { openIn