From 51ece94f588a60c578504309f9eeea22a831f0fa Mon Sep 17 00:00:00 2001 From: pajlada Date: Sun, 19 Dec 2021 15:57:56 +0100 Subject: [PATCH] Update Settings and Signals version (#3398) Co-authored-by: zneix --- CHANGELOG.md | 1 + lib/settings | 2 +- lib/signals | 2 +- src/messages/layouts/MessageLayoutElement.cpp | 11 +- src/messages/layouts/MessageLayoutElement.hpp | 4 +- src/providers/irc/AbstractIrcServer.cpp | 57 +++---- src/providers/irc/IrcConnection2.cpp | 6 + src/providers/irc/IrcConnection2.hpp | 1 + src/providers/twitch/TwitchChannel.cpp | 14 +- src/providers/twitch/TwitchChannel.hpp | 6 +- src/singletons/TooltipPreviewImage.cpp | 8 +- src/singletons/TooltipPreviewImage.hpp | 4 +- src/singletons/WindowManager.hpp | 1 + src/widgets/BaseWindow.cpp | 4 +- src/widgets/BaseWindow.hpp | 1 - src/widgets/Notebook.cpp | 4 +- src/widgets/Notebook.hpp | 4 +- src/widgets/dialogs/LastRunCrashDialog.cpp | 2 +- src/widgets/dialogs/LastRunCrashDialog.hpp | 5 +- src/widgets/dialogs/UserInfoPopup.cpp | 43 ++--- src/widgets/dialogs/UserInfoPopup.hpp | 5 +- src/widgets/helper/ChannelView.cpp | 156 +++++++++--------- src/widgets/helper/ChannelView.hpp | 6 +- src/widgets/helper/NotebookTab.hpp | 4 +- src/widgets/settingspages/GeneralPageView.hpp | 3 +- .../settingspages/NotificationPage.cpp | 9 +- .../settingspages/NotificationPage.hpp | 3 +- src/widgets/settingspages/SettingsPage.cpp | 8 +- src/widgets/settingspages/SettingsPage.hpp | 2 +- src/widgets/splits/Split.cpp | 57 +++---- src/widgets/splits/Split.hpp | 4 +- src/widgets/splits/SplitContainer.cpp | 47 +++--- src/widgets/splits/SplitContainer.hpp | 4 +- src/widgets/splits/SplitHeader.cpp | 44 ++--- src/widgets/splits/SplitHeader.hpp | 6 +- src/widgets/splits/SplitInput.cpp | 4 +- src/widgets/splits/SplitInput.hpp | 2 +- src/widgets/splits/SplitOverlay.cpp | 2 +- src/widgets/splits/SplitOverlay.hpp | 4 +- 39 files changed, 282 insertions(+), 268 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 024de95f..eee2332f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ - Bugfix: Fixed Chatterino attempting to send empty messages (#3355) - Bugfix: Fixed IRC highlights not triggering sounds or alerts properly. (#3368) - Bugfix: Fixed IRC /kick command crashing if parameters were malformed. (#3382) +- Bugfix: Fixed crash that would occur if the user tries to modify the currently connected IRC connection. (#3398) - Bugfix: Fixed a crash that could occur on certain Linux systems when toggling the Always on Top flag. (#3385) - Bugfix: Fixed zero-width emotes sometimes wrapping lines incorrectly. (#3389) - Bugfix: Fixed using special chars in Windows username breaking the storage of custom commands (#3397) diff --git a/lib/settings b/lib/settings index 7cf8431d..04792d85 160000 --- a/lib/settings +++ b/lib/settings @@ -1 +1 @@ -Subproject commit 7cf8431d644332107a51a46c1e3de70e64692f0c +Subproject commit 04792d853c7f83c9d7ab4df00279442a658d3be3 diff --git a/lib/signals b/lib/signals index baf5bb04..25e4ec3b 160000 --- a/lib/signals +++ b/lib/signals @@ -1 +1 @@ -Subproject commit baf5bb04bd13b090e405e0447c89a811f7e23ddc +Subproject commit 25e4ec3b8d6ea94a5e65a26e7cfcbbce3b87c5d6 diff --git a/src/messages/layouts/MessageLayoutElement.cpp b/src/messages/layouts/MessageLayoutElement.cpp index 89e13b48..fba47287 100644 --- a/src/messages/layouts/MessageLayoutElement.cpp +++ b/src/messages/layouts/MessageLayoutElement.cpp @@ -222,13 +222,10 @@ TextLayoutElement::TextLayoutElement(MessageElement &_creator, QString &_text, void TextLayoutElement::listenToLinkChanges() { - this->managedConnections_.emplace_back( - static_cast(this->getCreator()) - .linkChanged.connect([this]() { - // log("Old link: {}", this->getCreator().getLink().value); - // log("This link: {}", this->getLink().value); - this->setLink(this->getCreator().getLink()); - })); + this->managedConnections_.managedConnect( + static_cast(this->getCreator()).linkChanged, [this]() { + this->setLink(this->getCreator().getLink()); + }); } void TextLayoutElement::addCopyTextToString(QString &str, int from, diff --git a/src/messages/layouts/MessageLayoutElement.hpp b/src/messages/layouts/MessageLayoutElement.hpp index 8cdc6a94..1c7db037 100644 --- a/src/messages/layouts/MessageLayoutElement.hpp +++ b/src/messages/layouts/MessageLayoutElement.hpp @@ -11,6 +11,8 @@ #include "messages/MessageColor.hpp" #include "messages/MessageElement.hpp" +#include + class QPainter; namespace chatterino { @@ -114,7 +116,7 @@ protected: FontStyle style_; float scale_; - std::vector managedConnections_; + pajlada::Signals::SignalHolder managedConnections_; }; // TEXT ICON diff --git a/src/providers/irc/AbstractIrcServer.cpp b/src/providers/irc/AbstractIrcServer.cpp index fadd79c8..d7485d14 100644 --- a/src/providers/irc/AbstractIrcServer.cpp +++ b/src/providers/irc/AbstractIrcServer.cpp @@ -47,11 +47,12 @@ AbstractIrcServer::AbstractIrcServer() &Communi::IrcConnection::connected, this, [this] { this->onWriteConnected(this->writeConnection_.get()); }); - this->writeConnection_->connectionLost.connect([this](bool timeout) { - qCDebug(chatterinoIrc) - << "Write connection reconnect requested. Timeout:" << timeout; - this->writeConnection_->smartReconnect.invoke(); - }); + this->connections_.managedConnect( + this->writeConnection_->connectionLost, [this](bool timeout) { + qCDebug(chatterinoIrc) + << "Write connection reconnect requested. Timeout:" << timeout; + this->writeConnection_->smartReconnect.invoke(); + }); // Listen to read connection message signals this->readConnection_.reset(new IrcConnection); @@ -75,18 +76,19 @@ AbstractIrcServer::AbstractIrcServer() &Communi::IrcConnection::disconnected, this, [this] { this->onDisconnected(); }); - this->readConnection_->connectionLost.connect([this](bool timeout) { - qCDebug(chatterinoIrc) - << "Read connection reconnect requested. Timeout:" << timeout; - if (timeout) - { - // Show additional message since this is going to interrupt a - // connection that is still "connected" - this->addGlobalSystemMessage( - "Server connection timed out, reconnecting"); - } - this->readConnection_->smartReconnect.invoke(); - }); + this->connections_.managedConnect( + this->readConnection_->connectionLost, [this](bool timeout) { + qCDebug(chatterinoIrc) + << "Read connection reconnect requested. Timeout:" << timeout; + if (timeout) + { + // Show additional message since this is going to interrupt a + // connection that is still "connected" + this->addGlobalSystemMessage( + "Server connection timed out, reconnecting"); + } + this->readConnection_->smartReconnect.invoke(); + }); } void AbstractIrcServer::initializeIrc() @@ -217,19 +219,18 @@ ChannelPtr AbstractIrcServer::getOrAddChannel(const QString &dirtyChannelName) } this->channels.insert(channelName, chan); - this->connections_.emplace_back( - chan->destroyed.connect([this, channelName] { - // fourtf: issues when the server itself is destroyed + this->connections_.managedConnect(chan->destroyed, [this, channelName] { + // fourtf: issues when the server itself is destroyed - qCDebug(chatterinoIrc) << "[AbstractIrcServer::addChannel]" - << channelName << "was destroyed"; - this->channels.remove(channelName); + qCDebug(chatterinoIrc) << "[AbstractIrcServer::addChannel]" + << channelName << "was destroyed"; + this->channels.remove(channelName); - if (this->readConnection_) - { - this->readConnection_->sendRaw("PART #" + channelName); - } - })); + if (this->readConnection_) + { + this->readConnection_->sendRaw("PART #" + channelName); + } + }); // join IRC channel { diff --git a/src/providers/irc/IrcConnection2.cpp b/src/providers/irc/IrcConnection2.cpp index 152d71a2..7e4c4537 100644 --- a/src/providers/irc/IrcConnection2.cpp +++ b/src/providers/irc/IrcConnection2.cpp @@ -117,6 +117,12 @@ IrcConnection::IrcConnection(QObject *parent) }); } +IrcConnection::~IrcConnection() +{ + // Prematurely disconnect all QObject connections + this->disconnect(); +} + void IrcConnection::open() { this->expectConnectionLoss_ = false; diff --git a/src/providers/irc/IrcConnection2.hpp b/src/providers/irc/IrcConnection2.hpp index 261d172f..1149bbeb 100644 --- a/src/providers/irc/IrcConnection2.hpp +++ b/src/providers/irc/IrcConnection2.hpp @@ -13,6 +13,7 @@ class IrcConnection : public Communi::IrcConnection { public: IrcConnection(QObject *parent = nullptr); + ~IrcConnection() override; // Signal to notify that we're unexpectedly no longer connected, either due // to a connection error or if we think we've timed out. It's up to the diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 21f65669..6adf70b2 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -158,14 +158,16 @@ TwitchChannel::TwitchChannel(const QString &name) { qCDebug(chatterinoTwitch) << "[TwitchChannel" << name << "] Opened"; - this->managedConnect(getApp()->accounts->twitch.currentUserChanged, [=] { - this->setMod(false); - }); + this->signalHolder_.managedConnect( + getApp()->accounts->twitch.currentUserChanged, [=] { + this->setMod(false); + }); // pubsub - this->managedConnect(getApp()->accounts->twitch.currentUserChanged, [=] { - this->refreshPubsub(); - }); + this->signalHolder_.managedConnect( + getApp()->accounts->twitch.currentUserChanged, [=] { + this->refreshPubsub(); + }); this->refreshPubsub(); this->userStateChanged.connect([this] { this->refreshPubsub(); diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 84d4adaf..f51ca7ca 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -35,9 +35,7 @@ class BttvEmotes; class TwitchIrcServer; -class TwitchChannel : public Channel, - public ChannelChatters, - pajlada::Signals::SignalHolder +class TwitchChannel : public Channel, public ChannelChatters { public: struct StreamStatus { @@ -184,6 +182,8 @@ private: QElapsedTimer clipCreationTimer_; bool isClipCreationInProgress{false}; + pajlada::Signals::SignalHolder signalHolder_; + friend class TwitchIrcServer; friend class TwitchMessageBuilder; friend class IrcMessageHandler; diff --git a/src/singletons/TooltipPreviewImage.cpp b/src/singletons/TooltipPreviewImage.cpp index 637d2e50..7b33039e 100644 --- a/src/singletons/TooltipPreviewImage.cpp +++ b/src/singletons/TooltipPreviewImage.cpp @@ -16,19 +16,19 @@ TooltipPreviewImage::TooltipPreviewImage() { auto windows = getApp()->windows; - this->connections_.push_back(windows->gifRepaintRequested.connect([&] { + this->connections_.managedConnect(windows->gifRepaintRequested, [&] { if (this->image_ && this->image_->animated()) { this->refreshTooltipWidgetPixmap(); } - })); + }); - this->connections_.push_back(windows->miscUpdate.connect([&] { + this->connections_.managedConnect(windows->miscUpdate, [&] { if (this->attemptRefresh) { this->refreshTooltipWidgetPixmap(); } - })); + }); } void TooltipPreviewImage::setImage(ImagePtr image) diff --git a/src/singletons/TooltipPreviewImage.hpp b/src/singletons/TooltipPreviewImage.hpp index aeccdf9d..309d1ef1 100644 --- a/src/singletons/TooltipPreviewImage.hpp +++ b/src/singletons/TooltipPreviewImage.hpp @@ -2,6 +2,8 @@ #include "messages/Image.hpp" +#include + namespace chatterino { class TooltipPreviewImage @@ -21,7 +23,7 @@ private: int imageWidth_ = 0; int imageHeight_ = 0; - std::vector connections_; + pajlada::Signals::SignalHolder connections_; // attemptRefresh is set to true in case we want to preview an image that has not loaded yet (if pixmapOrLoad fails) bool attemptRefresh{false}; diff --git a/src/singletons/WindowManager.hpp b/src/singletons/WindowManager.hpp index 87151d20..c3d7c75f 100644 --- a/src/singletons/WindowManager.hpp +++ b/src/singletons/WindowManager.hpp @@ -5,6 +5,7 @@ #include "common/FlagsEnum.hpp" #include "common/Singleton.hpp" #include "common/WindowDescriptors.hpp" + #include "pajlada/settings/settinglistener.hpp" #include "widgets/splits/SplitContainer.hpp" diff --git a/src/widgets/BaseWindow.cpp b/src/widgets/BaseWindow.cpp index f3ded0b1..9725ee73 100644 --- a/src/widgets/BaseWindow.cpp +++ b/src/widgets/BaseWindow.cpp @@ -229,7 +229,7 @@ void BaseWindow::init() 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); }, - this->managedConnections_); + this->connections_); }); } #else @@ -245,7 +245,7 @@ void BaseWindow::init() this->show(); } }, - this->managedConnections_); + this->connections_); } #endif } diff --git a/src/widgets/BaseWindow.hpp b/src/widgets/BaseWindow.hpp index 913e6651..9c9d9bc2 100644 --- a/src/widgets/BaseWindow.hpp +++ b/src/widgets/BaseWindow.hpp @@ -134,7 +134,6 @@ private: #endif pajlada::Signals::SignalHolder connections_; - std::vector managedConnections_; friend class BaseWidget; }; diff --git a/src/widgets/Notebook.cpp b/src/widgets/Notebook.cpp index 1ee79819..2526ed05 100644 --- a/src/widgets/Notebook.cpp +++ b/src/widgets/Notebook.cpp @@ -759,7 +759,7 @@ void SplitNotebook::addCustomButtons() [settingsBtn](bool hide, auto) { settingsBtn->setVisible(!hide); }, - this->connections_); + this->signalHolder_); settingsBtn->setIcon(NotebookButton::Settings); @@ -774,7 +774,7 @@ void SplitNotebook::addCustomButtons() [userBtn](bool hide, auto) { userBtn->setVisible(!hide); }, - this->connections_); + this->signalHolder_); userBtn->setIcon(NotebookButton::User); QObject::connect(userBtn, &NotebookButton::leftClicked, [this, userBtn] { diff --git a/src/widgets/Notebook.hpp b/src/widgets/Notebook.hpp index f9418e82..153dd533 100644 --- a/src/widgets/Notebook.hpp +++ b/src/widgets/Notebook.hpp @@ -101,7 +101,7 @@ private: NotebookTabDirection tabDirection_ = NotebookTabDirection::Horizontal; }; -class SplitNotebook : public Notebook, pajlada::Signals::SignalHolder +class SplitNotebook : public Notebook { public: SplitNotebook(Window *parent); @@ -117,8 +117,6 @@ private: void addCustomButtons(); pajlada::Signals::SignalHolder signalHolder_; - - std::vector connections_; }; } // namespace chatterino diff --git a/src/widgets/dialogs/LastRunCrashDialog.cpp b/src/widgets/dialogs/LastRunCrashDialog.cpp index 0fa5a2f8..7fb9d1f4 100644 --- a/src/widgets/dialogs/LastRunCrashDialog.cpp +++ b/src/widgets/dialogs/LastRunCrashDialog.cpp @@ -83,7 +83,7 @@ LastRunCrashDialog::LastRunCrashDialog() // }; // updateUpdateLabel(); - // this->managedConnect(updateManager.statusUpdated, + // this->signalHolder_.managedConnect(updateManager.statusUpdated, // [updateUpdateLabel](auto) mutable { // postToThread([updateUpdateLabel]() mutable { updateUpdateLabel(); // }); diff --git a/src/widgets/dialogs/LastRunCrashDialog.hpp b/src/widgets/dialogs/LastRunCrashDialog.hpp index 6c923561..22297484 100644 --- a/src/widgets/dialogs/LastRunCrashDialog.hpp +++ b/src/widgets/dialogs/LastRunCrashDialog.hpp @@ -5,10 +5,13 @@ namespace chatterino { -class LastRunCrashDialog : public QDialog, pajlada::Signals::SignalHolder +class LastRunCrashDialog : public QDialog { public: LastRunCrashDialog(); + +private: + pajlada::Signals::SignalHolder signalHolder_; }; } // namespace chatterino diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index 6315e201..2ccd4f78 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -430,12 +430,6 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent) this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Policy::Ignored); } -// remove once https://github.com/pajlada/signals/pull/10 gets merged -UserInfoPopup::~UserInfoPopup() -{ - this->refreshConnection_.disconnect(); -} - void UserInfoPopup::themeChangedEvent() { BaseWindow::themeChangedEvent(); @@ -601,26 +595,25 @@ void UserInfoPopup::updateLatestMessages() // shrink dialog in case ChannelView goes from visible to hidden this->adjustSize(); - this->refreshConnection_ - .disconnect(); // remove once https://github.com/pajlada/signals/pull/10 gets merged + this->refreshConnection_ = + std::make_unique( + this->channel_->messageAppended.connect([this, hasMessages]( + auto message, auto) { + if (!checkMessageUserName(this->userName_, message)) + return; - this->refreshConnection_ = this->channel_->messageAppended.connect( - [this, hasMessages](auto message, auto) { - if (!checkMessageUserName(this->userName_, message)) - return; - - if (hasMessages) - { - // display message in ChannelView - this->ui_.latestMessages->channel()->addMessage(message); - } - else - { - // The ChannelView is currently hidden, so manually refresh - // and display the latest messages - this->updateLatestMessages(); - } - }); + if (hasMessages) + { + // display message in ChannelView + this->ui_.latestMessages->channel()->addMessage(message); + } + else + { + // The ChannelView is currently hidden, so manually refresh + // and display the latest messages + this->updateLatestMessages(); + } + })); } void UserInfoPopup::updateUserData() diff --git a/src/widgets/dialogs/UserInfoPopup.hpp b/src/widgets/dialogs/UserInfoPopup.hpp index 89f06a36..dc45586d 100644 --- a/src/widgets/dialogs/UserInfoPopup.hpp +++ b/src/widgets/dialogs/UserInfoPopup.hpp @@ -3,6 +3,7 @@ #include "widgets/BaseWindow.hpp" #include "widgets/helper/ChannelView.hpp" +#include #include class QCheckBox; @@ -19,7 +20,6 @@ class UserInfoPopup final : public BaseWindow public: UserInfoPopup(bool closeAutomatically, QWidget *parent); - ~UserInfoPopup(); void setData(const QString &name, const ChannelPtr &channel); @@ -43,8 +43,7 @@ private: pajlada::Signals::NoArgSignal userStateChanged_; - // replace with ScopedConnection once https://github.com/pajlada/signals/pull/10 gets merged - pajlada::Signals::Connection refreshConnection_; + std::unique_ptr refreshConnection_; std::shared_ptr hack_; diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index fd5fcb7e..1a51f118 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -184,34 +184,35 @@ void ChannelView::initializeScrollbar() void ChannelView::initializeSignals() { - this->connections_.push_back( - getApp()->windows->wordFlagsChanged.connect([this] { - this->queueLayout(); - this->update(); - })); + this->signalHolder_.managedConnect(getApp()->windows->wordFlagsChanged, + [this] { + this->queueLayout(); + this->update(); + }); getSettings()->showLastMessageIndicator.connect( [this](auto, auto) { this->update(); }, - this->connections_); + this); - connections_.push_back(getApp()->windows->gifRepaintRequested.connect([&] { - this->queueUpdate(); - })); + this->signalHolder_.managedConnect(getApp()->windows->gifRepaintRequested, + [&] { + this->queueUpdate(); + }); - connections_.push_back( - getApp()->windows->layoutRequested.connect([&](Channel *channel) { + this->signalHolder_.managedConnect( + getApp()->windows->layoutRequested, [&](Channel *channel) { if (this->isVisible() && (channel == nullptr || this->channel_.get() == channel)) { this->queueLayout(); } - })); + }); - connections_.push_back(getApp()->fonts->fontChanged.connect([this] { + this->signalHolder_.managedConnect(getApp()->fonts->fontChanged, [this] { this->queueLayout(); - })); + }); } bool ChannelView::pausable() const @@ -597,87 +598,87 @@ void ChannelView::setChannel(ChannelPtr underlyingChannel) // Use a proxy channel to keep filtered messages past the time they are removed from their origin channel // - this->channelConnections_.push_back( - underlyingChannel->messageAppended.connect( - [this](MessagePtr &message, - boost::optional overridingFlags) { - if (this->shouldIncludeMessage(message)) + this->channelConnections_.managedConnect( + underlyingChannel->messageAppended, + [this](MessagePtr &message, + boost::optional overridingFlags) { + if (this->shouldIncludeMessage(message)) + { + if (this->channel_->lastDate_ != QDate::currentDate()) { - if (this->channel_->lastDate_ != QDate::currentDate()) - { - this->channel_->lastDate_ = QDate::currentDate(); - auto msg = makeSystemMessage( - QLocale().toString(QDate::currentDate(), - QLocale::LongFormat), - QTime(0, 0)); - this->channel_->addMessage(msg); - } - // When the message was received in the underlyingChannel, - // logging will be handled. Prevent duplications. - if (overridingFlags) - { - overridingFlags.get().set(MessageFlag::DoNotLog); - } - else - { - overridingFlags = MessageFlags(message->flags); - overridingFlags.get().set(MessageFlag::DoNotLog); - } - - this->channel_->addMessage(message, overridingFlags); + this->channel_->lastDate_ = QDate::currentDate(); + auto msg = makeSystemMessage( + QLocale().toString(QDate::currentDate(), + QLocale::LongFormat), + QTime(0, 0)); + this->channel_->addMessage(msg); + } + // When the message was received in the underlyingChannel, + // logging will be handled. Prevent duplications. + if (overridingFlags) + { + overridingFlags.get().set(MessageFlag::DoNotLog); + } + else + { + overridingFlags = MessageFlags(message->flags); + overridingFlags.get().set(MessageFlag::DoNotLog); } - })); - this->channelConnections_.push_back( - underlyingChannel->messagesAddedAtStart.connect( - [this](std::vector &messages) { - std::vector filtered; - std::copy_if(messages.begin(), messages.end(), - std::back_inserter(filtered), - [this](MessagePtr msg) { - return this->shouldIncludeMessage(msg); - }); + this->channel_->addMessage(message, overridingFlags); + } + }); - if (!filtered.empty()) - this->channel_->addMessagesAtStart(filtered); - })); + this->channelConnections_.managedConnect( + underlyingChannel->messagesAddedAtStart, + [this](std::vector &messages) { + std::vector filtered; + std::copy_if(messages.begin(), messages.end(), + std::back_inserter(filtered), [this](MessagePtr msg) { + return this->shouldIncludeMessage(msg); + }); - this->channelConnections_.push_back( - underlyingChannel->messageReplaced.connect( - [this](size_t index, MessagePtr replacement) { - if (this->shouldIncludeMessage(replacement)) - this->channel_->replaceMessage(index, replacement); - })); + if (!filtered.empty()) + this->channel_->addMessagesAtStart(filtered); + }); + + this->channelConnections_.managedConnect( + underlyingChannel->messageReplaced, + [this](size_t index, MessagePtr replacement) { + if (this->shouldIncludeMessage(replacement)) + this->channel_->replaceMessage(index, replacement); + }); // // Standard channel connections // // on new message - this->channelConnections_.push_back(this->channel_->messageAppended.connect( + this->channelConnections_.managedConnect( + this->channel_->messageAppended, [this](MessagePtr &message, boost::optional overridingFlags) { this->messageAppended(message, std::move(overridingFlags)); - })); + }); - this->channelConnections_.push_back( - this->channel_->messagesAddedAtStart.connect( - [this](std::vector &messages) { - this->messageAddedAtStart(messages); - })); + this->channelConnections_.managedConnect( + this->channel_->messagesAddedAtStart, + [this](std::vector &messages) { + this->messageAddedAtStart(messages); + }); // on message removed - this->channelConnections_.push_back( - this->channel_->messageRemovedFromStart.connect( - [this](MessagePtr &message) { - this->messageRemoveFromStart(message); - })); + this->channelConnections_.managedConnect( + this->channel_->messageRemovedFromStart, [this](MessagePtr &message) { + this->messageRemoveFromStart(message); + }); // on message replaced - this->channelConnections_.push_back(this->channel_->messageReplaced.connect( + this->channelConnections_.managedConnect( + this->channel_->messageReplaced, [this](size_t index, MessagePtr replacement) { this->messageReplaced(index, replacement); - })); + }); auto snapshot = underlyingChannel->getMessageSnapshot(); @@ -715,9 +716,10 @@ void ChannelView::setChannel(ChannelPtr underlyingChannel) // Notifications if (auto tc = dynamic_cast(underlyingChannel.get())) { - this->connections_.push_back(tc->liveStatusChanged.connect([this]() { - this->liveStatusChanged.invoke(); - })); + this->channelConnections_.managedConnect( + tc->liveStatusChanged, [this]() { + this->liveStatusChanged.invoke(); + }); } } diff --git a/src/widgets/helper/ChannelView.hpp b/src/widgets/helper/ChannelView.hpp index 13f67215..43534981 100644 --- a/src/widgets/helper/ChannelView.hpp +++ b/src/widgets/helper/ChannelView.hpp @@ -238,8 +238,10 @@ private: LimitedQueue messages_; - std::vector connections_; - std::vector channelConnections_; + pajlada::Signals::SignalHolder signalHolder_; + + // channelConnections_ will be cleared when the underlying channel of the channelview changes + pajlada::Signals::SignalHolder channelConnections_; std::unordered_set> messagesOnScreen_; diff --git a/src/widgets/helper/NotebookTab.hpp b/src/widgets/helper/NotebookTab.hpp index 45d0022f..1bd893ef 100644 --- a/src/widgets/helper/NotebookTab.hpp +++ b/src/widgets/helper/NotebookTab.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace chatterino { @@ -105,7 +105,7 @@ private: QMenu menu_; - std::vector managedConnections_; + pajlada::Signals::SignalHolder managedConnections_; }; } // namespace chatterino diff --git a/src/widgets/settingspages/GeneralPageView.hpp b/src/widgets/settingspages/GeneralPageView.hpp index 3b21f066..0a4ff57b 100644 --- a/src/widgets/settingspages/GeneralPageView.hpp +++ b/src/widgets/settingspages/GeneralPageView.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "Application.hpp" #include "common/ChatterinoSetting.hpp" #include "singletons/WindowManager.hpp" @@ -218,7 +219,7 @@ private: QVBoxLayout *navigationLayout_; std::vector groups_; - std::vector managedConnections_; + pajlada::Signals::SignalHolder managedConnections_; }; } // namespace chatterino diff --git a/src/widgets/settingspages/NotificationPage.cpp b/src/widgets/settingspages/NotificationPage.cpp index fb52c88e..69c23c68 100644 --- a/src/widgets/settingspages/NotificationPage.cpp +++ b/src/widgets/settingspages/NotificationPage.cpp @@ -55,9 +55,7 @@ NotificationPage::NotificationPage() // implementation of custom combobox done // because addComboBox only can handle strings-settings // int setting for the ToastReaction is desired - openIn - .append(this->createToastReactionComboBox( - this->managedConnections_)) + openIn.append(this->createToastReactionComboBox()) ->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); } @@ -118,8 +116,7 @@ NotificationPage::NotificationPage() } } } -QComboBox *NotificationPage::createToastReactionComboBox( - std::vector managedConnections) +QComboBox *NotificationPage::createToastReactionComboBox() { QComboBox *toastReactionOptions = new QComboBox(); @@ -135,7 +132,7 @@ QComboBox *NotificationPage::createToastReactionComboBox( [toastReactionOptions](const int &index, auto) { toastReactionOptions->setCurrentIndex(index); }, - managedConnections); + this->managedConnections_); QObject::connect(toastReactionOptions, QOverload::of(&QComboBox::currentIndexChanged), diff --git a/src/widgets/settingspages/NotificationPage.hpp b/src/widgets/settingspages/NotificationPage.hpp index e70f58ad..7b175902 100644 --- a/src/widgets/settingspages/NotificationPage.hpp +++ b/src/widgets/settingspages/NotificationPage.hpp @@ -15,8 +15,7 @@ public: NotificationPage(); private: - QComboBox *createToastReactionComboBox( - std::vector managedConnections); + QComboBox *createToastReactionComboBox(); }; } // namespace chatterino diff --git a/src/widgets/settingspages/SettingsPage.cpp b/src/widgets/settingspages/SettingsPage.cpp index 82cf8f89..02b7157d 100644 --- a/src/widgets/settingspages/SettingsPage.cpp +++ b/src/widgets/settingspages/SettingsPage.cpp @@ -157,9 +157,11 @@ QSpinBox *SettingsPage::createSpinBox(pajlada::Settings::Setting &setting, w->setMinimum(min); w->setMaximum(max); - setting.connect([w](const int &value, auto) { - w->setValue(value); - }); + setting.connect( + [w](const int &value, auto) { + w->setValue(value); + }, + this->managedConnections_); QObject::connect(w, QOverload::of(&QSpinBox::valueChanged), [&setting](int value) { setting.setValue(value); diff --git a/src/widgets/settingspages/SettingsPage.hpp b/src/widgets/settingspages/SettingsPage.hpp index 3b364d1e..47b125e0 100644 --- a/src/widgets/settingspages/SettingsPage.hpp +++ b/src/widgets/settingspages/SettingsPage.hpp @@ -75,7 +75,7 @@ public: protected: SettingsDialogTab *tab_; pajlada::Signals::NoArgSignal onCancel_; - std::vector managedConnections_; + pajlada::Signals::SignalHolder managedConnections_; }; } // namespace chatterino diff --git a/src/widgets/splits/Split.cpp b/src/widgets/splits/Split.cpp index a0417272..937bfc11 100644 --- a/src/widgets/splits/Split.cpp +++ b/src/widgets/splits/Split.cpp @@ -175,7 +175,7 @@ Split::Split(QWidget *parent) this->input_->show(); } }, - this->managedConnections_); + this->signalHolder_); this->header_->updateModerationModeIcon(); this->overlay_->hide(); @@ -183,29 +183,29 @@ Split::Split(QWidget *parent) this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - this->managedConnect(modifierStatusChanged, [this](Qt::KeyboardModifiers - status) { - if ((status == - showSplitOverlayModifiers /*|| status == showAddSplitRegions*/) && - this->isMouseOver_) - { - this->overlay_->show(); - } - else - { - this->overlay_->hide(); - } + this->signalHolder_.managedConnect( + modifierStatusChanged, [this](Qt::KeyboardModifiers status) { + if ((status == + showSplitOverlayModifiers /*|| status == showAddSplitRegions*/) && + this->isMouseOver_) + { + this->overlay_->show(); + } + else + { + this->overlay_->hide(); + } - if (getSettings()->pauseChatModifier.getEnum() != Qt::NoModifier && - status == getSettings()->pauseChatModifier.getEnum()) - { - this->view_->pause(PauseReason::KeyboardModifier); - } - else - { - this->view_->unpause(PauseReason::KeyboardModifier); - } - }); + if (getSettings()->pauseChatModifier.getEnum() != Qt::NoModifier && + status == getSettings()->pauseChatModifier.getEnum()) + { + this->view_->pause(PauseReason::KeyboardModifier); + } + else + { + this->view_->unpause(PauseReason::KeyboardModifier); + } + }); this->input_->ui_.textEdit->focused.connect([this] { this->focused.invoke(); @@ -250,12 +250,13 @@ Split::Split(QWidget *parent) [this](const bool &val) { this->setAcceptDrops(val); }, - this->managedConnections_); + this->signalHolder_); this->addShortcuts(); - this->managedConnect(getApp()->hotkeys->onItemsUpdated, [this]() { - this->clearShortcuts(); - this->addShortcuts(); - }); + this->signalHolder_.managedConnect(getApp()->hotkeys->onItemsUpdated, + [this]() { + this->clearShortcuts(); + this->addShortcuts(); + }); } void Split::addShortcuts() diff --git a/src/widgets/splits/Split.hpp b/src/widgets/splits/Split.hpp index 35113ba3..d0c0b6ba 100644 --- a/src/widgets/splits/Split.hpp +++ b/src/widgets/splits/Split.hpp @@ -31,7 +31,7 @@ class SelectChannelDialog; // - Responsible for rendering and handling user text input // // Each sub-element has a reference to the parent Chat Widget -class Split : public BaseWidget, pajlada::Signals::SignalHolder +class Split : public BaseWidget { friend class SplitInput; @@ -152,8 +152,6 @@ private: pajlada::Signals::Connection indirectChannelChangedConnection_; pajlada::Signals::SignalHolder signalHolder_; - std::vector managedConnections_; - public slots: void addSibling(); void deleteFromContainer(); diff --git a/src/widgets/splits/SplitContainer.cpp b/src/widgets/splits/SplitContainer.cpp index 74ecf277..4bb4ca74 100644 --- a/src/widgets/splits/SplitContainer.cpp +++ b/src/widgets/splits/SplitContainer.cpp @@ -41,39 +41,40 @@ SplitContainer::SplitContainer(Notebook *parent) { this->refreshTabTitle(); - this->managedConnect(Split::modifierStatusChanged, [this](auto modifiers) { - this->layout(); + this->signalHolder_.managedConnect( + Split::modifierStatusChanged, [this](auto modifiers) { + this->layout(); - if (modifiers == showResizeHandlesModifiers) - { - for (auto &handle : this->resizeHandles_) + if (modifiers == showResizeHandlesModifiers) { - handle->show(); - handle->raise(); + for (auto &handle : this->resizeHandles_) + { + handle->show(); + handle->raise(); + } } - } - else - { - for (auto &handle : this->resizeHandles_) + else { - handle->hide(); + for (auto &handle : this->resizeHandles_) + { + handle->hide(); + } } - } - if (modifiers == showSplitOverlayModifiers) - { - this->setCursor(Qt::PointingHandCursor); - } - else - { - this->unsetCursor(); - } - }); + if (modifiers == showSplitOverlayModifiers) + { + this->setCursor(Qt::PointingHandCursor); + } + else + { + this->unsetCursor(); + } + }); this->setCursor(Qt::PointingHandCursor); this->setAcceptDrops(true); - this->managedConnect(this->overlay_.dragEnded, [this]() { + this->signalHolder_.managedConnect(this->overlay_.dragEnded, [this]() { this->isDragging_ = false; this->layout(); }); diff --git a/src/widgets/splits/SplitContainer.hpp b/src/widgets/splits/SplitContainer.hpp index 1662f0b6..077ac7c1 100644 --- a/src/widgets/splits/SplitContainer.hpp +++ b/src/widgets/splits/SplitContainer.hpp @@ -29,7 +29,7 @@ class Notebook; // inside but it doesn't expose any of it publicly. // -class SplitContainer final : public BaseWidget, pajlada::Signals::SignalHolder +class SplitContainer final : public BaseWidget { Q_OBJECT @@ -260,6 +260,8 @@ private: std::unordered_map connectionsPerSplit_; + pajlada::Signals::SignalHolder signalHolder_; + bool isDragging_ = false; }; diff --git a/src/widgets/splits/SplitHeader.cpp b/src/widgets/splits/SplitHeader.cpp index 230128ae..54b895f8 100644 --- a/src/widgets/splits/SplitHeader.cpp +++ b/src/widgets/splits/SplitHeader.cpp @@ -204,9 +204,10 @@ SplitHeader::SplitHeader(Split *_split) this->handleChannelChanged(); }); - this->managedConnect(getApp()->accounts->twitch.currentUserChanged, [this] { - this->updateModerationModeIcon(); - }); + this->managedConnections_.managedConnect( + getApp()->accounts->twitch.currentUserChanged, [this] { + this->updateModerationModeIcon(); + }); auto _ = [this](const auto &, const auto &) { this->updateChannelText(); @@ -302,19 +303,19 @@ void SplitHeader::initializeLayout() }); // update moderation button when items changed - this->managedConnect(getSettings()->moderationActions.delayedItemsChanged, - [this] { - if (getSettings()->moderationActions.empty()) - { - if (this->split_->getModerationMode()) - this->split_->setModerationMode(true); - } - else - { - if (this->split_->getModerationMode()) - this->split_->setModerationMode(true); - } - }); + this->managedConnections_.managedConnect( + getSettings()->moderationActions.delayedItemsChanged, [this] { + if (getSettings()->moderationActions.empty()) + { + if (this->split_->getModerationMode()) + this->split_->setModerationMode(true); + } + else + { + if (this->split_->getModerationMode()) + this->split_->setModerationMode(true); + } + }); getSettings()->customURIScheme.connect( [this] { @@ -519,7 +520,8 @@ std::unique_ptr SplitHeader::createChatModeMenu() menu->addAction(setR9k); menu->addAction(setFollowers); - this->managedConnections_.push_back(this->modeUpdateRequested_.connect( + this->managedConnections_.managedConnect( + this->modeUpdateRequested_, [this, setSub, setEmote, setSlow, setR9k, setFollowers]() { auto twitchChannel = dynamic_cast(this->split_->getChannel().get()); @@ -536,7 +538,7 @@ std::unique_ptr SplitHeader::createChatModeMenu() setEmote->setChecked(roomModes->emoteOnly); setSub->setChecked(roomModes->submode); setFollowers->setChecked(roomModes->followerOnly != -1); - })); + }); auto toggle = [this](const QString &command, QAction *action) mutable { this->split_->getChannel().get()->sendMessage( @@ -652,10 +654,10 @@ void SplitHeader::handleChannelChanged() auto channel = this->split_->getChannel(); if (auto twitchChannel = dynamic_cast(channel.get())) { - this->channelConnections_.emplace_back( - twitchChannel->liveStatusChanged.connect([this]() { + this->channelConnections_.managedConnect( + twitchChannel->liveStatusChanged, [this]() { this->updateChannelText(); - })); + }); } } diff --git a/src/widgets/splits/SplitHeader.hpp b/src/widgets/splits/SplitHeader.hpp index dea611ac..f4723611 100644 --- a/src/widgets/splits/SplitHeader.hpp +++ b/src/widgets/splits/SplitHeader.hpp @@ -19,7 +19,7 @@ class EffectLabel; class Label; class Split; -class SplitHeader final : public BaseWidget, pajlada::Signals::SignalHolder +class SplitHeader final : public BaseWidget { Q_OBJECT @@ -81,8 +81,8 @@ private: // signals pajlada::Signals::NoArgSignal modeUpdateRequested_; - std::vector managedConnections_; - std::vector channelConnections_; + pajlada::Signals::SignalHolder managedConnections_; + pajlada::Signals::SignalHolder channelConnections_; public slots: void reloadChannelEmotes(); diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index b97a9133..ef1c1f80 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -99,10 +99,10 @@ void SplitInput::initLayout() QObject::connect(this->ui_.textEdit, &QTextEdit::textChanged, this, &SplitInput::onTextChanged); - this->managedConnections_.push_back(app->fonts->fontChanged.connect([=]() { + this->managedConnections_.managedConnect(app->fonts->fontChanged, [=]() { this->ui_.textEdit->setFont( app->fonts->getFont(FontStyle::ChatMedium, this->scale())); - })); + }); // open emote popup QObject::connect(this->ui_.emoteButton, &EffectLabel::leftClicked, [=] { diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index 5a9688fe..0518cc9c 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -69,7 +69,7 @@ private: QHBoxLayout *hbox; } ui_; - std::vector managedConnections_; + pajlada::Signals::SignalHolder managedConnections_; QStringList prevMsg_; QString currMsg_; int prevIndex_ = 0; diff --git a/src/widgets/splits/SplitOverlay.cpp b/src/widgets/splits/SplitOverlay.cpp index 06538398..30cd743d 100644 --- a/src/widgets/splits/SplitOverlay.cpp +++ b/src/widgets/splits/SplitOverlay.cpp @@ -75,7 +75,7 @@ SplitOverlay::SplitOverlay(Split *parent) up->setCursor(Qt::PointingHandCursor); down->setCursor(Qt::PointingHandCursor); - this->managedConnect(this->scaleChanged, [=](float _scale) { + this->signalHolder_.managedConnect(this->scaleChanged, [=](float _scale) { int a = int(_scale * 30); QSize size(a, a); diff --git a/src/widgets/splits/SplitOverlay.hpp b/src/widgets/splits/SplitOverlay.hpp index 23f489d5..929e4112 100644 --- a/src/widgets/splits/SplitOverlay.hpp +++ b/src/widgets/splits/SplitOverlay.hpp @@ -10,7 +10,7 @@ namespace chatterino { class Split; -class SplitOverlay : public BaseWidget, pajlada::Signals::SignalHolder +class SplitOverlay : public BaseWidget { public: explicit SplitOverlay(Split *parent = nullptr); @@ -52,6 +52,8 @@ private: QPushButton *right_; QPushButton *down_; + pajlada::Signals::SignalHolder signalHolder_; + friend class ButtonEventFilter; };