From acc573a8c5413cd5e03081938810690c79e29b47 Mon Sep 17 00:00:00 2001 From: LosFarmosCTL <80157503+LosFarmosCTL@users.noreply.github.com> Date: Sat, 2 Oct 2021 12:58:28 +0200 Subject: [PATCH 1/2] Restart the application bundle instead of the underlying executable when crashing on macOS (#3268) On macOS, programs are contained in ".app" application bundles. When chatterino restarts on a crash, it currently just looks for the executable path obtained via QApplication::applicationFilePath() and starts that again, which for macOS is the underlying unix executable inside of the application bundle. Unfortunately, for macOS those 2 are absolutely different, resulting in i.e. a second chatterino icon being added to the dock, due to the OS not recognizing that it is the same application. --- CHANGELOG.md | 1 + src/RunGui.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b971a65978a..8b602b1c60c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Bugfix: Fixed own IRC messages not having metadata and a link to a usercard. (#3203) - Bugfix: Fixed some channels still not loading in rare cases. (#3219) - Bugfix: Fixed a bug with usernames or emotes completing from the wrong position. (#3229) +- Bugfix: Fixed second chatterino icon appearing in the dock when restarting on a crash in macOS. (#3268) - Dev: Renamed CMake's build option `USE_SYSTEM_QT5KEYCHAIN` to `USE_SYSTEM_QTKEYCHAIN`. (#3103) - Dev: Add benchmarks that can be compiled with the `BUILD_BENCHMARKS` CMake flag. Off by default. (#3038) diff --git a/src/RunGui.cpp b/src/RunGui.cpp index 998c726b63f..cd7f3e11648 100644 --- a/src/RunGui.cpp +++ b/src/RunGui.cpp @@ -28,6 +28,10 @@ # include #endif +#ifdef Q_OS_MAC +# include "corefoundation/CFBundle.h" +#endif + namespace chatterino { namespace { void installCustomPalette() @@ -122,8 +126,29 @@ namespace { std::chrono::steady_clock::now() - signalsInitTime > 30s) { QProcess proc; + +#ifdef Q_OS_MAC + // On macOS, programs are bundled into ".app" Application bundles, + // when restarting chatterino that bundle should be opened with the "open" + // terminal command instead of directly starting the underlying executable, + // as those are 2 different things for the OS and i.e. do not use + // the same dock icon (resulting in a second chatterino icon on restarting) + CFURLRef appUrlRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFStringRef macPath = + CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle); + const char *pathPtr = + CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding()); + + proc.setProgram("open"); + proc.setArguments({pathPtr, "--args", "--crash-recovery"}); + + CFRelease(appUrlRef); + CFRelease(macPath); +#else proc.setProgram(QApplication::applicationFilePath()); proc.setArguments({"--crash-recovery"}); +#endif + proc.startDetached(); } From 0ba7c0f3c58a3a5a3f0a61a71e89797f831d523d Mon Sep 17 00:00:00 2001 From: gempir Date: Sat, 2 Oct 2021 14:17:24 +0200 Subject: [PATCH 2/2] Add highlights for first messages (#3267) Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + src/controllers/highlights/HighlightModel.cpp | 31 +++++++++++++++++++ .../highlights/HighlightPhrase.cpp | 2 ++ .../highlights/HighlightPhrase.hpp | 1 + src/messages/Message.cpp | 6 ++++ src/messages/Message.hpp | 1 + src/messages/layouts/MessageLayout.cpp | 13 ++++++-- src/providers/colors/ColorProvider.cpp | 14 +++++++++ src/providers/colors/ColorProvider.hpp | 3 +- src/providers/twitch/TwitchMessageBuilder.cpp | 6 ++++ src/singletons/Settings.hpp | 7 +++++ src/widgets/Window.cpp | 3 ++ 12 files changed, 84 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b602b1c60c..41af9f8946c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Minor: Fixed `/streamlink` command not stripping leading @'s or #'s (#3215) - Minor: Strip leading @ and trailing , from username in `/popout` command. (#3217) - Minor: Added `flags.reward_message` filter variable (#3231) +- Minor: Added highlights for first messages (#3267) - Bugfix: Fixed colored usernames sometimes not working. (#3170) - Bugfix: Restored ability to send duplicate `/me` messages. (#3166) - Bugfix: Notifications for moderators about other moderators deleting messages can now be disabled. (#3121) diff --git a/src/controllers/highlights/HighlightModel.cpp b/src/controllers/highlights/HighlightModel.cpp index c24616665da..aae88e5020a 100644 --- a/src/controllers/highlights/HighlightModel.cpp +++ b/src/controllers/highlights/HighlightModel.cpp @@ -150,6 +150,29 @@ void HighlightModel::afterInit() setColorItem(redeemedRow[Column::Color], *RedeemedColor, false); this->insertCustomRow(redeemedRow, 3); + + std::vector firstMessageRow = this->createRow(); + setBoolItem(firstMessageRow[Column::Pattern], + getSettings()->enableFirstMessageHighlight.getValue(), true, + false); + firstMessageRow[Column::Pattern]->setData("First Messages", + Qt::DisplayRole); + firstMessageRow[Column::ShowInMentions]->setFlags({}); + firstMessageRow[Column::FlashTaskbar]->setFlags({}); + firstMessageRow[Column::PlaySound]->setFlags({}); + firstMessageRow[Column::UseRegex]->setFlags({}); + firstMessageRow[Column::CaseSensitive]->setFlags({}); + + QUrl FirstMessageSound = + QUrl(getSettings()->firstMessageHighlightSoundUrl.getValue()); + setFilePathItem(firstMessageRow[Column::SoundPath], FirstMessageSound, + false); + + auto FirstMessageColor = + ColorProvider::instance().color(ColorType::FirstMessageHighlight); + setColorItem(firstMessageRow[Column::Color], *FirstMessageColor, false); + + this->insertCustomRow(firstMessageRow, 4); } void HighlightModel::customRowSetData(const std::vector &row, @@ -304,6 +327,14 @@ void HighlightModel::customRowSetData(const std::vector &row, .updateColor(ColorType::RedeemedHighlight, QColor(colorName)); } + else if (rowIndex == 4) + { + getSettings()->firstMessageHighlightColor.setValue( + colorName); + const_cast(ColorProvider::instance()) + .updateColor(ColorType::FirstMessageHighlight, + QColor(colorName)); + } } } break; diff --git a/src/controllers/highlights/HighlightPhrase.cpp b/src/controllers/highlights/HighlightPhrase.cpp index 63590413113..ab8436c3175 100644 --- a/src/controllers/highlights/HighlightPhrase.cpp +++ b/src/controllers/highlights/HighlightPhrase.cpp @@ -12,6 +12,8 @@ namespace { QColor HighlightPhrase::FALLBACK_HIGHLIGHT_COLOR = QColor(127, 63, 73, 127); QColor HighlightPhrase::FALLBACK_REDEEMED_HIGHLIGHT_COLOR = QColor(28, 126, 141, 60); +QColor HighlightPhrase::FALLBACK_FIRST_MESSAGE_HIGHLIGHT_COLOR = + QColor(72, 127, 63, 60); QColor HighlightPhrase::FALLBACK_SUB_COLOR = QColor(196, 102, 255, 100); bool HighlightPhrase::operator==(const HighlightPhrase &other) const diff --git a/src/controllers/highlights/HighlightPhrase.hpp b/src/controllers/highlights/HighlightPhrase.hpp index 496da667b0a..41ab8b682a1 100644 --- a/src/controllers/highlights/HighlightPhrase.hpp +++ b/src/controllers/highlights/HighlightPhrase.hpp @@ -82,6 +82,7 @@ class HighlightPhrase static QColor FALLBACK_HIGHLIGHT_COLOR; static QColor FALLBACK_REDEEMED_HIGHLIGHT_COLOR; static QColor FALLBACK_SUB_COLOR; + static QColor FALLBACK_FIRST_MESSAGE_HIGHLIGHT_COLOR; private: QString pattern_; diff --git a/src/messages/Message.cpp b/src/messages/Message.cpp index b6708aca2e5..7f312905045 100644 --- a/src/messages/Message.cpp +++ b/src/messages/Message.cpp @@ -42,6 +42,12 @@ SBHighlight Message::getScrollBarHighlight() const ColorProvider::instance().color(ColorType::RedeemedHighlight), SBHighlight::Default, true); } + else if (this->flags.has(MessageFlag::FirstMessage)) + { + return SBHighlight( + ColorProvider::instance().color(ColorType::FirstMessageHighlight), + SBHighlight::Default, true); + } return SBHighlight(); } diff --git a/src/messages/Message.hpp b/src/messages/Message.hpp index b91313545fa..9321b570bc2 100644 --- a/src/messages/Message.hpp +++ b/src/messages/Message.hpp @@ -38,6 +38,7 @@ enum class MessageFlag : uint32_t { RedeemedHighlight = (1 << 20), RedeemedChannelPointReward = (1 << 21), ShowInMentions = (1 << 22), + FirstMessage = (1 << 23), }; using MessageFlags = FlagsEnum; diff --git a/src/messages/layouts/MessageLayout.cpp b/src/messages/layouts/MessageLayout.cpp index b59b12ce77a..1135556e0f7 100644 --- a/src/messages/layouts/MessageLayout.cpp +++ b/src/messages/layouts/MessageLayout.cpp @@ -293,9 +293,16 @@ void MessageLayout::updateBuffer(QPixmap *buffer, int /*messageIndex*/, } }(); - if ((this->message_->flags.has(MessageFlag::Highlighted) || - this->message_->flags.has(MessageFlag::HighlightedWhisper)) && - !this->flags.has(MessageLayoutFlag::IgnoreHighlights)) + if (this->message_->flags.has(MessageFlag::FirstMessage) && + getSettings()->enableFirstMessageHighlight.getValue()) + { + backgroundColor = blendColors( + backgroundColor, + *ColorProvider::instance().color(ColorType::FirstMessageHighlight)); + } + else if ((this->message_->flags.has(MessageFlag::Highlighted) || + this->message_->flags.has(MessageFlag::HighlightedWhisper)) && + !this->flags.has(MessageLayoutFlag::IgnoreHighlights)) { // Blend highlight color with usual background color backgroundColor = diff --git a/src/providers/colors/ColorProvider.cpp b/src/providers/colors/ColorProvider.cpp index b29488ef39c..350db35360e 100644 --- a/src/providers/colors/ColorProvider.cpp +++ b/src/providers/colors/ColorProvider.cpp @@ -119,6 +119,20 @@ void ColorProvider::initTypeColorMap() std::make_shared( HighlightPhrase::FALLBACK_REDEEMED_HIGHLIGHT_COLOR)}); } + + customColor = getSettings()->firstMessageHighlightColor; + if (QColor(customColor).isValid()) + { + this->typeColorMap_.insert({ColorType::FirstMessageHighlight, + std::make_shared(customColor)}); + } + else + { + this->typeColorMap_.insert( + {ColorType::FirstMessageHighlight, + std::make_shared( + HighlightPhrase::FALLBACK_FIRST_MESSAGE_HIGHLIGHT_COLOR)}); + } } void ColorProvider::initDefaultColors() diff --git a/src/providers/colors/ColorProvider.hpp b/src/providers/colors/ColorProvider.hpp index 5d2d50128a4..4540caaf36d 100644 --- a/src/providers/colors/ColorProvider.hpp +++ b/src/providers/colors/ColorProvider.hpp @@ -11,7 +11,8 @@ enum class ColorType { SelfHighlight, Subscription, Whisper, - RedeemedHighlight + RedeemedHighlight, + FirstMessageHighlight, }; class ColorProvider diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 42fd676ae54..1c594ceb000 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -180,6 +180,12 @@ MessagePtr TwitchMessageBuilder::build() this->message().flags.set(MessageFlag::RedeemedHighlight); } + if (this->tags.contains("first-msg") && + this->tags["first-msg"].toString() == "1") + { + this->message().flags.set(MessageFlag::FirstMessage); + } + // timestamp this->emplace( calculateMessageTimestamp(this->ircMessage)); diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 73c603453c9..1d967a9d826 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -273,6 +273,13 @@ class Settings : public ABSettings, public ConcurrentSettings QStringSetting redeemedHighlightColor = { "/highlighting/redeemedHighlightColor", ""}; + BoolSetting enableFirstMessageHighlight = { + "/highlighting/firstMessageHighlight/highlighted", true}; + QStringSetting firstMessageHighlightSoundUrl = { + "/highlighting/firstMessageHighlightSoundUrl", ""}; + QStringSetting firstMessageHighlightColor = { + "/highlighting/firstMessageHighlightColor", ""}; + BoolSetting enableSubHighlight = { "/highlighting/subHighlight/subsHighlighted", true}; BoolSetting enableSubHighlightSound = { diff --git a/src/widgets/Window.cpp b/src/widgets/Window.cpp index dea06c69c32..7233e735aad 100644 --- a/src/widgets/Window.cpp +++ b/src/widgets/Window.cpp @@ -219,6 +219,9 @@ void Window::addDebugStuff() miscMessages.emplace_back(R"(@badges=;color=#00AD2B;display-name=Iamme420\s;emotes=;id=d47a1e4b-a3c6-4b9e-9bf1-51b8f3dbc76e;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1529670347537;turbo=0;user-id=56422869;user-type= :iamme420!iamme420@iamme420.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS)"); miscMessages.emplace_back(R"(@badge-info=founder/47;badges=moderator/1,founder/0,premium/1;color=#00FF80;display-name=gempir;emotes=;flags=;id=d4514490-202e-43cb-b429-ef01a9d9c2fe;mod=1;room-id=11148817;subscriber=0;tmi-sent-ts=1575198233854;turbo=0;user-id=77829817;user-type=mod :gempir!gempir@gempir.tmi.twitch.tv PRIVMSG #pajlada :offline chat gachiBASS)"); + // "first time chat" message + miscMessages.emplace_back(R"(@badge-info=;badges=glhf-pledge/1;client-nonce=5d2627b0cbe56fa05faf5420def4807d;color=#1E90FF;display-name=oldcoeur;emote-only=1;emotes=84608:0-7;first-msg=1;flags=;id=7412fea4-8683-4cc9-a506-4228127a5c2d;mod=0;room-id=11148817;subscriber=0;tmi-sent-ts=1623429859222;turbo=0;user-id=139147886;user-type= :oldcoeur!oldcoeur@oldcoeur.tmi.twitch.tv PRIVMSG #pajlada :cmonBruh)"); + // various link tests linkMessages.emplace_back(R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should pass: )" + getValidLinks().join(' ')); linkMessages.emplace_back(R"(@badge-info=subscriber/48;badges=broadcaster/1,subscriber/36,partner/1;color=#CC44FF;display-name=pajlada;emotes=;flags=;id=3c23cf3c-0864-4699-a76b-089350141147;mod=0;room-id=11148817;subscriber=1;tmi-sent-ts=1577628844607;turbo=0;user-id=11148817;user-type= :pajlada!pajlada@pajlada.tmi.twitch.tv PRIVMSG #pajlada : Links that should NOT pass: )" + getInvalidLinks().join(' '));