diff --git a/chatterino.pro b/chatterino.pro index 4510ad6d6..1d2cdc617 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -350,6 +350,7 @@ HEADERS += \ src/util/IsBigEndian.hpp \ src/util/JsonQuery.hpp \ src/util/LayoutCreator.hpp \ + src/util/QObjectRef.hpp \ src/util/QStringHash.hpp \ src/util/rangealgorithm.hpp \ src/util/RapidjsonHelpers.hpp \ diff --git a/src/util/QObjectRef.hpp b/src/util/QObjectRef.hpp new file mode 100644 index 000000000..183844d88 --- /dev/null +++ b/src/util/QObjectRef.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +namespace chatterino +{ + /// Holds a pointer to a QObject and resets it to nullptr if the QObject + /// gets destroyed. + template + class QObjectRef + { + public: + QObjectRef() + { + static_assert(std::is_base_of_v); + } + + explicit QObjectRef(T* t) + { + static_assert(std::is_base_of_v); + + this->swap(t); + } + + ~QObjectRef() + { + this->swap(nullptr); + } + + QObjectRef& operator=(T* t) + { + this->swap(t); + return *this; + } + + operator bool() + { + return t_; + } + + T* operator->() + { + return t_; + } + + T* get() + { + return t_; + } + + QObject* swap(T* other) + { + // old + if (this->conn_) + { + QObject::disconnect(this->conn_); + } + + // new + if (other) + { + QObject::connect(other, &QObject::destroyed, + [this]() { this->swap(nullptr); }); + } + + return std::exchange(this->t_, other); + } + + private: + T* t_{}; + QMetaObject::Connection conn_; + }; +} // namespace chatterino diff --git a/src/widgets/dialogs/EmotePopup.cpp b/src/widgets/dialogs/EmotePopup.cpp index bb984a9ef..f1ac2693c 100644 --- a/src/widgets/dialogs/EmotePopup.cpp +++ b/src/widgets/dialogs/EmotePopup.cpp @@ -100,8 +100,8 @@ namespace { } } // namespace -EmotePopup::EmotePopup() - : BaseWindow(nullptr, BaseWindow::EnableCustomFrame) +EmotePopup::EmotePopup(QWidget *parent) + : BaseWindow(parent, BaseWindow::EnableCustomFrame) { auto layout = new QVBoxLayout(this); this->getLayoutContainer()->setLayout(layout); diff --git a/src/widgets/dialogs/EmotePopup.hpp b/src/widgets/dialogs/EmotePopup.hpp index 4e4d5f74a..4997e578a 100644 --- a/src/widgets/dialogs/EmotePopup.hpp +++ b/src/widgets/dialogs/EmotePopup.hpp @@ -14,7 +14,7 @@ using ChannelPtr = std::shared_ptr; class EmotePopup : public BaseWindow { public: - EmotePopup(); + EmotePopup(QWidget *parent = nullptr); void loadChannel(ChannelPtr channel); void loadEmojis(); diff --git a/src/widgets/splits/SplitInput.cpp b/src/widgets/splits/SplitInput.cpp index be9dc88c4..1b31af989 100644 --- a/src/widgets/splits/SplitInput.cpp +++ b/src/widgets/splits/SplitInput.cpp @@ -153,7 +153,9 @@ void SplitInput::openEmotePopup() { if (!this->emotePopup_) { - this->emotePopup_ = std::make_unique(); + this->emotePopup_ = new EmotePopup(this); + this->emotePopup_->setAttribute(Qt::WA_DeleteOnClose); + this->emotePopup_->linkClicked.connect([this](const Link &link) { if (link.type == Link::InsertText) { diff --git a/src/widgets/splits/SplitInput.hpp b/src/widgets/splits/SplitInput.hpp index b26030b6b..784b2f50b 100644 --- a/src/widgets/splits/SplitInput.hpp +++ b/src/widgets/splits/SplitInput.hpp @@ -1,5 +1,6 @@ #pragma once +#include "util/QObjectRef.hpp" #include "widgets/BaseWidget.hpp" #include @@ -46,7 +47,7 @@ private: void openEmotePopup(); Split *const split_; - std::shared_ptr emotePopup_; + QObjectRef emotePopup_; struct { ResizingTextEdit *textEdit;