diff --git a/CHANGELOG.md b/CHANGELOG.md index a44f5641..986cdb3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Minor: Added Linux support for Live Notifications toasts. (#5881, #5971, #5976) - Minor: Messages can now be deleted from the context menu in a channel. (#5956) - Minor: Overlay windows now inherit the global zoom level and can be zoomed independently. (#6016) +- Minor: The `/watching` channel is now supported on all platforms. (#6031) - Minor: The font weight of chat messages can now be changed. (#6037) - Bugfix: Fixed a potential way to escape the Lua Plugin sandbox. (#5846) - Bugfix: Fixed a crash relating to Lua HTTP. (#5800) diff --git a/src/Application.cpp b/src/Application.cpp index 8b545b1a..1809ee8f 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -607,11 +607,9 @@ void Application::initNm(const Paths &paths) { (void)paths; -#ifdef Q_OS_WIN -# if defined QT_NO_DEBUG || defined CHATTERINO_DEBUG_NM +#if defined QT_NO_DEBUG || defined CHATTERINO_DEBUG_NM registerNmHost(paths); this->nmServer.start(); -# endif #endif } diff --git a/src/singletons/NativeMessaging.cpp b/src/singletons/NativeMessaging.cpp index ec4421ca..d491db87 100644 --- a/src/singletons/NativeMessaging.cpp +++ b/src/singletons/NativeMessaging.cpp @@ -12,12 +12,14 @@ #include "util/PostToThread.hpp" #include +#include #include #include #include #include #include #include +#include #ifdef Q_OS_WIN # include "widgets/AttachedWindow.hpp" @@ -25,21 +27,92 @@ namespace { +using namespace chatterino; using namespace chatterino::literals; const QString EXTENSION_ID = u"glknmaideaikkmemifbfkhnomoknepka"_s; constexpr const size_t MESSAGE_SIZE = 1024; +struct Config { +#ifdef Q_OS_WIN + QString fileName; + QString registryKey; +#else + QString directory; +#endif +}; + +const Config FIREFOX{ +#ifdef Q_OS_WIN + .fileName = u"native-messaging-manifest-firefox.json"_s, + .registryKey = + u"HKCU\\Software\\Mozilla\\NativeMessagingHosts\\com.chatterino.chatterino"_s, +#elif defined(Q_OS_MACOS) + .directory = + u"~/Library/Application Support/Mozilla/NativeMessagingHosts"_s, +#else + .directory = u"~/.mozilla/native-messaging-hosts"_s, +#endif +}; + +const Config CHROME{ +#ifdef Q_OS_WIN + .fileName = u"native-messaging-manifest-chrome.json"_s, + .registryKey = + u"HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\com.chatterino.chatterino"_s, +#elif defined(Q_OS_MACOS) + .directory = + u"~/Library/Application Support/Google/Chrome/NativeMessagingHosts"_s, +#else + .directory = u"~/.config/google-chrome/NativeMessagingHosts"_s, +#endif +}; + +void writeManifestTo(QString directory, const QString &filename, + const QJsonDocument &json) +{ + if (directory.startsWith('~')) + { + directory = QDir::homePath() % QStringView{directory}.sliced(1); + } + + QDir dir(directory); + if (!dir.mkpath(u"."_s)) + { + qCWarning(chatterinoNativeMessage) << "Failed to create" << directory; + return; + } + QFile file(dir.filePath(filename)); + if (!file.open(QFile::WriteOnly | QFile::Truncate)) + { + qCWarning(chatterinoNativeMessage) + << "Failed to open" << filename << "in" << directory; + return; + } + file.write(json.toJson()); +} + +void registerNmManifest([[maybe_unused]] const Paths &paths, + const Config &config, const QJsonDocument &document) +{ +#ifdef Q_OS_WIN + writeManifestTo(paths.miscDirectory, config.fileName, document); + + QSettings registry(config.registryKey, QSettings::NativeFormat); + registry.setValue("Default", + QString(paths.miscDirectory % u'/' % config.fileName)); +#else + writeManifestTo(config.directory, u"com.chatterino.chatterino.json"_s, + document); +#endif +} + } // namespace namespace chatterino { using namespace literals; -void registerNmManifest(const Paths &paths, const QString &manifestFilename, - const QString ®istryKeyName, - const QJsonDocument &document); - void registerNmHost(const Paths &paths) { if (Modes::instance().isPortable) @@ -78,10 +151,7 @@ void registerNmHost(const Paths &paths) obj.insert("allowed_origins", allowedOriginsArr); - registerNmManifest(paths, "/native-messaging-manifest-chrome.json", - "HKCU\\Software\\Google\\Chrome\\NativeMessagingHost" - "s\\com.chatterino.chatterino", - QJsonDocument(obj)); + registerNmManifest(paths, CHROME, QJsonDocument{obj}); } // firefox @@ -100,32 +170,10 @@ void registerNmHost(const Paths &paths) obj.insert("allowed_extensions", allowedExtensions); - registerNmManifest(paths, "/native-messaging-manifest-firefox.json", - "HKCU\\Software\\Mozilla\\NativeMessagingHosts\\com." - "chatterino.chatterino", - QJsonDocument(obj)); + registerNmManifest(paths, FIREFOX, QJsonDocument{obj}); } } -void registerNmManifest(const Paths &paths, const QString &manifestFilename, - const QString ®istryKeyName, - const QJsonDocument &document) -{ - (void)registryKeyName; - - // save the manifest - QString manifestPath = paths.miscDirectory + manifestFilename; - QFile file(manifestPath); - file.open(QIODevice::WriteOnly | QIODevice::Truncate); - file.write(document.toJson()); - file.flush(); - -#ifdef Q_OS_WIN - QSettings registry(registryKeyName, QSettings::NativeFormat); - registry.setValue("Default", manifestPath); -#endif -} - std::string &getNmQueueName(const Paths &paths) { static std::string name = @@ -158,9 +206,9 @@ namespace nm::client { // SERVER NativeMessagingServer::NativeMessagingServer() - : thread(*this) + : thread(new ReceiverThread(*this)) { - this->thread.setObjectName("NativeMessagingReceiver"); + this->thread->setObjectName("C2NMReceiver"); } NativeMessagingServer::~NativeMessagingServer() @@ -169,18 +217,24 @@ NativeMessagingServer::~NativeMessagingServer() { qCWarning(chatterinoNativeMessage) << "Failed to remove message queue"; } - this->thread.requestInterruption(); - this->thread.quit(); + this->thread->requestInterruption(); + this->thread->quit(); // Most likely, the receiver thread will still wait for a message - if (!this->thread.wait(250)) + if (!this->thread->wait(100)) { - this->thread.terminate(); + this->thread->terminate(); + + if (!this->thread->wait(100)) + { + qCWarning(chatterinoNativeMessage) + << "Failed to terminate thread cleanly"; + } } } void NativeMessagingServer::start() { - this->thread.start(); + this->thread->start(); } NativeMessagingServer::ReceiverThread::ReceiverThread( diff --git a/src/singletons/NativeMessaging.hpp b/src/singletons/NativeMessaging.hpp index 0d3ba454..bfe7de3d 100644 --- a/src/singletons/NativeMessaging.hpp +++ b/src/singletons/NativeMessaging.hpp @@ -59,7 +59,7 @@ private: void syncChannels(const QJsonArray &twitchChannels); - ReceiverThread thread; + ReceiverThread *thread; /// This vector contains all channels that are open the user's browser. /// These channels are joined to be able to switch channels more quickly.