This commit is contained in:
Mm2PL 2024-01-14 12:45:27 +00:00 committed by GitHub
commit f93fcd676b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 82 additions and 31 deletions

View file

@ -106,6 +106,7 @@
- Dev: Refactored the Image Uploader feature. (#4971)
- Dev: Refactored the SplitOverlay code. (#5082)
- Dev: Fixed deadlock and use-after-free in tests. (#4981)
- Dev: Cleanly exit Chatterino instead of force exiting. (#4993)
- Dev: Moved all `.clang-format` files to the root directory. (#5037)
- Dev: Load less message history upon reconnects. (#5001, #5018)
- Dev: Load less message history upon reconnects. (#5001)

View file

@ -114,6 +114,7 @@ Application::Application(Settings &_settings, Paths &_paths, const Args &_args)
, emotes(&this->emplace<Emotes>())
, accounts(&this->emplace<AccountController>())
, hotkeys(&this->emplace<HotkeyController>())
, twitch(&this->emplace<TwitchIrcServer>())
, windows(&this->emplace<WindowManager>())
, toasts(&this->emplace<Toasts>())
, imageUploader(&this->emplace<ImageUploader>())
@ -123,7 +124,6 @@ Application::Application(Settings &_settings, Paths &_paths, const Args &_args)
, commands(&this->emplace<CommandController>())
, notifications(&this->emplace<NotificationController>())
, highlights(&this->emplace<HighlightController>())
, twitch(&this->emplace<TwitchIrcServer>())
, chatterinoBadges(&this->emplace<ChatterinoBadges>())
, ffzBadges(&this->emplace<FfzBadges>())
, seventvBadges(&this->emplace<SeventvBadges>())
@ -147,11 +147,6 @@ Application::Application(Settings &_settings, Paths &_paths, const Args &_args)
Application::~Application() = default;
void Application::fakeDtor()
{
this->twitchPubSub.reset();
}
void Application::initialize(Settings &settings, Paths &paths)
{
assert(isAppInitialized == false);

View file

@ -98,12 +98,6 @@ public:
Application &operator=(const Application &) = delete;
Application &operator=(Application &&) = delete;
/**
* In the interim, before we remove _exit(0); from RunGui.cpp,
* this will destroy things we know can be destroyed
*/
void fakeDtor();
void initialize(Settings &settings, Paths &paths);
void load();
void save();
@ -117,6 +111,7 @@ public:
Emotes *const emotes{};
AccountController *const accounts{};
HotkeyController *const hotkeys{};
TwitchIrcServer *const twitch{};
WindowManager *const windows{};
Toasts *const toasts{};
ImageUploader *const imageUploader{};
@ -126,7 +121,6 @@ public:
CommandController *const commands{};
NotificationController *const notifications{};
HighlightController *const highlights{};
TwitchIrcServer *const twitch{};
ChatterinoBadges *const chatterinoBadges{};
FfzBadges *const ffzBadges{};
SeventvBadges *const seventvBadges{};

View file

@ -492,6 +492,7 @@ set(SOURCE_FILES
util/RapidjsonHelpers.hpp
util/RatelimitBucket.cpp
util/RatelimitBucket.hpp
util/RenameThread.hpp
util/SampleData.cpp
util/SampleData.hpp
util/SharedPtrElementLess.hpp

View file

@ -21,6 +21,7 @@
#include <QtConcurrent>
#include <csignal>
#include <thread>
#include <tuple>
#ifdef USEWINSDK
@ -237,6 +238,7 @@ void runGui(QApplication &a, Paths &paths, Settings &settings, const Args &args)
#endif
auto thread = std::thread([dir = paths.miscDirectory] {
#ifdef Q_OS_WIN32
{
auto path = combinePath(dir, "Update.exe");
if (QFile::exists(path))
@ -251,6 +253,7 @@ void runGui(QApplication &a, Paths &paths, Settings &settings, const Args &args)
QFile::remove(path);
}
}
#endif
});
// Clear the cache 1 minute after start.
@ -281,15 +284,16 @@ void runGui(QApplication &a, Paths &paths, Settings &settings, const Args &args)
pajlada::Settings::SettingManager::gSave();
}
if (thread.joinable())
{
thread.join();
}
chatterino::NetworkManager::deinit();
#ifdef USEWINSDK
// flushing windows clipboard to keep copied messages
flushClipboard();
#endif
app.fakeDtor();
_exit(0);
}
} // namespace chatterino

View file

@ -150,6 +150,15 @@ protected:
return this->started_.load(std::memory_order_acquire);
}
/**
* @brief Will be called when the clients has been requested to stop
*
* Derived classes can override this to do their own shutdown behaviour
*/
virtual void stopImpl()
{
}
liveupdates::WebsocketClient &websocketClient_;
private:
@ -164,6 +173,8 @@ private:
{
assert(this->isStarted());
this->started_.store(false, std::memory_order_release);
this->stopImpl();
}
liveupdates::WebsocketHandle handle_;

View file

@ -8,6 +8,7 @@
#include "providers/twitch/PubSubHelpers.hpp"
#include "util/DebugCount.hpp"
#include "util/ExponentialBackoff.hpp"
#include "util/RenameThread.hpp"
#include <pajlada/signals/signal.hpp>
#include <QJsonObject>
@ -94,7 +95,10 @@ public:
.toStdString());
}
virtual ~BasicPubSubManager() = default;
virtual ~BasicPubSubManager()
{
this->stop();
};
BasicPubSubManager(const BasicPubSubManager &) = delete;
BasicPubSubManager(const BasicPubSubManager &&) = delete;
@ -115,6 +119,8 @@ public:
this->mainThread_.reset(new std::thread([this] {
runThread();
}));
renameThread(*this->mainThread_.get(), "BPSM");
}
void stop()

View file

@ -13,6 +13,8 @@ Client::Client(liveupdates::WebsocketClient &websocketClient,
: BasicPubSubClient<Subscription>(websocketClient, std::move(handle))
, lastHeartbeat_(std::chrono::steady_clock::now())
, heartbeatInterval_(heartbeatInterval)
, heartbeatTimer_(std::make_shared<boost::asio::steady_timer>(
this->websocketClient_.get_io_service()))
{
}
@ -23,6 +25,11 @@ void Client::onConnectionEstablished()
this->checkHeartbeat();
}
void Client::stopImpl()
{
this->heartbeatTimer_->cancel();
}
void Client::setHeartbeatInterval(int intervalMs)
{
qCDebug(chatterinoSeventvEventAPI)
@ -54,14 +61,13 @@ void Client::checkHeartbeat()
auto self = std::dynamic_pointer_cast<Client>(this->shared_from_this());
runAfter(this->websocketClient_.get_io_service(), this->heartbeatInterval_,
[self](auto) {
if (!self->isStarted())
{
return;
}
self->checkHeartbeat();
});
runAfter(this->heartbeatTimer_, this->heartbeatInterval_, [self](auto) {
if (!self->isStarted())
{
return;
}
self->checkHeartbeat();
});
}
} // namespace chatterino::seventv::eventapi

View file

@ -24,6 +24,7 @@ public:
protected:
void onConnectionEstablished() override;
void stopImpl() override;
private:
void checkHeartbeat();
@ -32,6 +33,7 @@ private:
lastHeartbeat_;
// This will be set once on the welcome message.
std::chrono::milliseconds heartbeatInterval_;
std::shared_ptr<boost::asio::steady_timer> heartbeatTimer_;
friend SeventvEventAPI;
};

View file

@ -125,7 +125,16 @@ WindowManager::WindowManager()
});
}
WindowManager::~WindowManager() = default;
WindowManager::~WindowManager()
{
for (const auto &window : this->windows_)
{
// We would prefer to use window->deleteLater() here, but the timings are too tight
// Channel's completion model gets destroyed before the deleteLater call actually deletes the
// UI objects that rely on the completion model
delete window;
}
}
MessageElementFlags WindowManager::getWordFlags()
{

19
src/util/RenameThread.hpp Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include <QtGlobal>
#ifdef Q_OS_LINUX
# include <pthread.h>
#endif
namespace chatterino {
template <typename T>
void renameThread(T &&thread, const char *threadName)
{
#ifdef Q_OS_LINUX
pthread_setname_np(thread.native_handle(), threadName);
#endif
}
} // namespace chatterino

View file

@ -50,13 +50,13 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget,
this->installEventFilter(this);
this->initLayout();
auto completer =
new QCompleter(&this->split_->getChannel()->completionModel);
auto *completer =
new QCompleter(&this->split_->getChannel()->completionModel, this);
this->ui_.textEdit->setCompleter(completer);
this->signalHolder_.managedConnect(this->split_->channelChanged, [this] {
auto channel = this->split_->getChannel();
auto completer = new QCompleter(&channel->completionModel);
auto *completer = new QCompleter(&channel->completionModel, this);
this->ui_.textEdit->setCompleter(completer);
});
@ -76,6 +76,8 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget,
});
}
SplitInput::~SplitInput() = default;
void SplitInput::initLayout()
{
auto app = getApp();

View file

@ -24,7 +24,7 @@ class ResizingTextEdit;
class ChannelView;
enum class CompletionKind;
class SplitInput : public BaseWidget
class SplitInput final : public BaseWidget
{
Q_OBJECT
@ -32,6 +32,7 @@ public:
SplitInput(Split *_chatWidget, bool enableInlineReplying = true);
SplitInput(QWidget *parent, Split *_chatWidget, ChannelView *_channelView,
bool enableInlineReplying = true);
~SplitInput() override;
bool hasSelection() const;
void clearSelection() const;