refactor: Make Args less of a singleton (#5041)

This means it's no longer a singleton, and its lifetime is bound to our application.
This felt like a good small experiment to see how its changes would look
if we did this.
As a shortcut, `getApp` that is already a mega singleton keeps a
reference to Args, this means places that are a bit more difficult to
inject into call `getApp()->getArgs()` just like other things are
accessed.
This commit is contained in:
pajlada 2023-12-29 15:40:31 +01:00 committed by GitHub
parent c65ebd26bd
commit d085ab578f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 78 additions and 69 deletions

View file

@ -100,6 +100,7 @@
- Dev: BREAKING: Replace custom `import()` with normal Lua `require()`. (#5014) - Dev: BREAKING: Replace custom `import()` with normal Lua `require()`. (#5014)
- Dev: Fixed most compiler warnings. (#5028) - Dev: Fixed most compiler warnings. (#5028)
- Dev: Added the ability to show `ChannelView`s without a `Split`. (#4747) - Dev: Added the ability to show `ChannelView`s without a `Split`. (#4747)
- Dev: Refactor Args to be less of a singleton. (#5041)
- Dev: Channels without any animated elements on screen will skip updates from the GIF timer. (#5042, #5043, #5045) - Dev: Channels without any animated elements on screen will skip updates from the GIF timer. (#5042, #5043, #5045)
## 2.4.6 ## 2.4.6

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Application.hpp" #include "Application.hpp"
#include "common/Args.hpp"
namespace chatterino::mock { namespace chatterino::mock {
@ -9,6 +10,11 @@ class EmptyApplication : public IApplication
public: public:
virtual ~EmptyApplication() = default; virtual ~EmptyApplication() = default;
const Args &getArgs() override
{
return this->args_;
}
Theme *getThemes() override Theme *getThemes() override
{ {
return nullptr; return nullptr;
@ -110,6 +116,9 @@ public:
{ {
return nullptr; return nullptr;
} }
private:
Args args_;
}; };
} // namespace chatterino::mock } // namespace chatterino::mock

View file

@ -104,8 +104,9 @@ IApplication::IApplication()
// It will create the instances of the major classes, and connect their signals // It will create the instances of the major classes, and connect their signals
// to each other // to each other
Application::Application(Settings &_settings, Paths &_paths) Application::Application(Settings &_settings, Paths &_paths, const Args &_args)
: themes(&this->emplace<Theme>()) : args_(_args)
, themes(&this->emplace<Theme>())
, fonts(&this->emplace<Fonts>()) , fonts(&this->emplace<Fonts>())
, emotes(&this->emplace<Emotes>()) , emotes(&this->emplace<Emotes>())
, accounts(&this->emplace<AccountController>()) , accounts(&this->emplace<AccountController>())
@ -146,7 +147,7 @@ void Application::initialize(Settings &settings, Paths &paths)
isAppInitialized = true; isAppInitialized = true;
// Show changelog // Show changelog
if (!getArgs().isFramelessEmbed && if (!this->args_.isFramelessEmbed &&
getSettings()->currentVersion.getValue() != "" && getSettings()->currentVersion.getValue() != "" &&
getSettings()->currentVersion.getValue() != CHATTERINO_VERSION) getSettings()->currentVersion.getValue() != CHATTERINO_VERSION)
{ {
@ -161,7 +162,7 @@ void Application::initialize(Settings &settings, Paths &paths)
} }
} }
if (!getArgs().isFramelessEmbed) if (!this->args_.isFramelessEmbed)
{ {
getSettings()->currentVersion.setValue(CHATTERINO_VERSION); getSettings()->currentVersion.setValue(CHATTERINO_VERSION);
@ -179,7 +180,7 @@ void Application::initialize(Settings &settings, Paths &paths)
// Show crash message. // Show crash message.
// On Windows, the crash message was already shown. // On Windows, the crash message was already shown.
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
if (!getArgs().isFramelessEmbed && getArgs().crashRecovery) if (!this->args_.isFramelessEmbed && this->args_.crashRecovery)
{ {
if (auto selected = if (auto selected =
this->windows->getMainWindow().getNotebook().getSelectedPage()) this->windows->getMainWindow().getNotebook().getSelectedPage())
@ -203,7 +204,7 @@ void Application::initialize(Settings &settings, Paths &paths)
this->windows->updateWordTypeMask(); this->windows->updateWordTypeMask();
if (!getArgs().isFramelessEmbed) if (!this->args_.isFramelessEmbed)
{ {
this->initNm(paths); this->initNm(paths);
} }
@ -219,7 +220,7 @@ int Application::run(QApplication &qtApp)
this->twitch->connect(); this->twitch->connect();
if (!getArgs().isFramelessEmbed) if (!this->args_.isFramelessEmbed)
{ {
this->windows->getMainWindow().show(); this->windows->getMainWindow().show();
} }

View file

@ -11,6 +11,7 @@
namespace chatterino { namespace chatterino {
class Args;
class TwitchIrcServer; class TwitchIrcServer;
class ITwitchIrcServer; class ITwitchIrcServer;
class PubSub; class PubSub;
@ -54,6 +55,7 @@ public:
static IApplication *instance; static IApplication *instance;
virtual const Args &getArgs() = 0;
virtual Theme *getThemes() = 0; virtual Theme *getThemes() = 0;
virtual Fonts *getFonts() = 0; virtual Fonts *getFonts() = 0;
virtual IEmotes *getEmotes() = 0; virtual IEmotes *getEmotes() = 0;
@ -78,6 +80,7 @@ public:
class Application : public IApplication class Application : public IApplication
{ {
const Args &args_;
std::vector<std::unique_ptr<Singleton>> singletons_; std::vector<std::unique_ptr<Singleton>> singletons_;
int argc_{}; int argc_{};
char **argv_{}; char **argv_{};
@ -85,7 +88,7 @@ class Application : public IApplication
public: public:
static Application *instance; static Application *instance;
Application(Settings &settings, Paths &paths); Application(Settings &_settings, Paths &_paths, const Args &_args);
void initialize(Settings &settings, Paths &paths); void initialize(Settings &settings, Paths &paths);
void load(); void load();
@ -126,6 +129,10 @@ public:
/*[[deprecated]]*/ Logging *const logging{}; /*[[deprecated]]*/ Logging *const logging{};
const Args &getArgs() override
{
return this->args_;
}
Theme *getThemes() override Theme *getThemes() override
{ {
return this->themes; return this->themes;

View file

@ -98,9 +98,9 @@ namespace {
installCustomPalette(); installCustomPalette();
} }
void showLastCrashDialog() void showLastCrashDialog(const Args &args)
{ {
auto *dialog = new LastRunCrashDialog; auto *dialog = new LastRunCrashDialog(args);
// Use exec() over open() to block the app from being loaded // Use exec() over open() to block the app from being loaded
// and to be able to set the safe mode. // and to be able to set the safe mode.
dialog->exec(); dialog->exec();
@ -223,16 +223,16 @@ namespace {
} }
} // namespace } // namespace
void runGui(QApplication &a, Paths &paths, Settings &settings) void runGui(QApplication &a, Paths &paths, Settings &settings, const Args &args)
{ {
initQt(); initQt();
initResources(); initResources();
initSignalHandler(); initSignalHandler();
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if (getArgs().crashRecovery) if (args.crashRecovery)
{ {
showLastCrashDialog(); showLastCrashDialog(args);
} }
#endif #endif
@ -271,12 +271,12 @@ void runGui(QApplication &a, Paths &paths, Settings &settings)
chatterino::NetworkManager::init(); chatterino::NetworkManager::init();
chatterino::Updates::instance().checkForUpdates(); chatterino::Updates::instance().checkForUpdates();
Application app(settings, paths); Application app(settings, paths, args);
app.initialize(settings, paths); app.initialize(settings, paths);
app.run(a); app.run(a);
app.save(); app.save();
if (!getArgs().dontSaveSettings) if (!args.dontSaveSettings)
{ {
pajlada::Settings::SettingManager::gSave(); pajlada::Settings::SettingManager::gSave();
} }

View file

@ -3,8 +3,12 @@
class QApplication; class QApplication;
namespace chatterino { namespace chatterino {
class Args;
class Paths; class Paths;
class Settings; class Settings;
void runGui(QApplication &a, Paths &paths, Settings &settings); void runGui(QApplication &a, Paths &paths, Settings &settings,
const Args &args);
} // namespace chatterino } // namespace chatterino

View file

@ -1,4 +1,4 @@
#include "Args.hpp" #include "common/Args.hpp"
#include "common/QLogging.hpp" #include "common/QLogging.hpp"
#include "debug/AssertInGuiThread.hpp" #include "debug/AssertInGuiThread.hpp"
@ -248,18 +248,4 @@ void Args::applyCustomChannelLayout(const QString &argValue)
} }
} }
static Args *instance = nullptr;
void initArgs(const QApplication &app)
{
instance = new Args(app);
}
const Args &getArgs()
{
assert(instance);
return *instance;
}
} // namespace chatterino } // namespace chatterino

View file

@ -30,6 +30,7 @@ namespace chatterino {
class Args class Args
{ {
public: public:
Args() = default;
Args(const QApplication &app); Args(const QApplication &app);
bool printVersion{}; bool printVersion{};
@ -60,7 +61,4 @@ private:
QStringList currentArguments_; QStringList currentArguments_;
}; };
void initArgs(const QApplication &app);
const Args &getArgs();
} // namespace chatterino } // namespace chatterino

View file

@ -233,7 +233,7 @@ void PluginController::load(const QFileInfo &index, const QDir &pluginDir,
auto *temp = plugin.get(); auto *temp = plugin.get();
this->plugins_.insert({pluginName, std::move(plugin)}); this->plugins_.insert({pluginName, std::move(plugin)});
if (getArgs().safeMode) if (getApp()->getArgs().safeMode)
{ {
// This isn't done earlier to ensure the user can disable a misbehaving plugin // This isn't done earlier to ensure the user can disable a misbehaving plugin
qCWarning(chatterinoLua) << "Skipping loading plugin " << meta.name qCWarning(chatterinoLua) << "Skipping loading plugin " << meta.name

View file

@ -62,18 +62,18 @@ int main(int argc, char **argv)
return 1; return 1;
} }
initArgs(a); const Args args(a);
#ifdef CHATTERINO_WITH_CRASHPAD #ifdef CHATTERINO_WITH_CRASHPAD
const auto crashpadHandler = installCrashHandler(); const auto crashpadHandler = installCrashHandler(args);
#endif #endif
// run in gui mode or browser extension host mode // run in gui mode or browser extension host mode
if (getArgs().shouldRunBrowserExtensionHost) if (args.shouldRunBrowserExtensionHost)
{ {
runBrowserExtensionHost(); runBrowserExtensionHost();
} }
else if (getArgs().printVersion) else if (args.printVersion)
{ {
attachToConsole(); attachToConsole();
@ -87,7 +87,7 @@ int main(int argc, char **argv)
} }
else else
{ {
if (getArgs().verbose) if (args.verbose)
{ {
attachToConsole(); attachToConsole();
} }
@ -99,7 +99,7 @@ int main(int argc, char **argv)
Settings settings(paths->settingsDirectory); Settings settings(paths->settingsDirectory);
runGui(a, *paths, settings); runGui(a, *paths, settings, args);
} }
return 0; return 0;
} }

View file

@ -82,10 +82,9 @@ std::optional<bool> readRecoverySettings(const Paths &paths)
return shouldRecover.toBool(); return shouldRecover.toBool();
} }
bool canRestart(const Paths &paths) bool canRestart(const Paths &paths, const Args &args)
{ {
#ifdef NDEBUG #ifdef NDEBUG
const auto &args = chatterino::getArgs();
if (args.isFramelessEmbed || args.shouldRunBrowserExtensionHost) if (args.isFramelessEmbed || args.shouldRunBrowserExtensionHost)
{ {
return false; return false;
@ -109,10 +108,10 @@ bool canRestart(const Paths &paths)
/// additional plus ('++' -> '+'). /// additional plus ('++' -> '+').
/// ///
/// The decoding happens in crash-handler/src/CommandLine.cpp /// The decoding happens in crash-handler/src/CommandLine.cpp
std::string encodeArguments() std::string encodeArguments(const Args &appArgs)
{ {
std::string args; std::string args;
for (auto arg : getArgs().currentArguments()) for (auto arg : appArgs.currentArguments())
{ {
if (!args.empty()) if (!args.empty())
{ {
@ -161,7 +160,7 @@ void CrashHandler::saveShouldRecover(bool value)
} }
#ifdef CHATTERINO_WITH_CRASHPAD #ifdef CHATTERINO_WITH_CRASHPAD
std::unique_ptr<crashpad::CrashpadClient> installCrashHandler() std::unique_ptr<crashpad::CrashpadClient> installCrashHandler(const Args &args)
{ {
// Currently, the following directory layout is assumed: // Currently, the following directory layout is assumed:
// [applicationDirPath] // [applicationDirPath]
@ -197,7 +196,7 @@ std::unique_ptr<crashpad::CrashpadClient> installCrashHandler()
std::map<std::string, std::string> annotations{ std::map<std::string, std::string> annotations{
{ {
"canRestart"s, "canRestart"s,
canRestart(*getPaths()) ? "true"s : "false"s, canRestart(*getPaths(), args) ? "true"s : "false"s,
}, },
{ {
"exePath"s, "exePath"s,
@ -209,7 +208,7 @@ std::unique_ptr<crashpad::CrashpadClient> installCrashHandler()
}, },
{ {
"exeArguments"s, "exeArguments"s,
encodeArguments(), encodeArguments(args),
}, },
}; };

View file

@ -12,6 +12,8 @@
namespace chatterino { namespace chatterino {
class Args;
class CrashHandler : public Singleton class CrashHandler : public Singleton
{ {
public: public:
@ -30,7 +32,7 @@ private:
}; };
#ifdef CHATTERINO_WITH_CRASHPAD #ifdef CHATTERINO_WITH_CRASHPAD
std::unique_ptr<crashpad::CrashpadClient> installCrashHandler(); std::unique_ptr<crashpad::CrashpadClient> installCrashHandler(const Args &args);
#endif #endif
} // namespace chatterino } // namespace chatterino

View file

@ -55,7 +55,7 @@ using SplitDirection = SplitContainer::Direction;
void WindowManager::showSettingsDialog(QWidget *parent, void WindowManager::showSettingsDialog(QWidget *parent,
SettingsDialogPreference preference) SettingsDialogPreference preference)
{ {
if (getArgs().dontSaveSettings) if (getApp()->getArgs().dontSaveSettings)
{ {
QMessageBox::critical(parent, "Chatterino - Editing Settings Forbidden", QMessageBox::critical(parent, "Chatterino - Editing Settings Forbidden",
"Settings cannot be edited when running with\n" "Settings cannot be edited when running with\n"
@ -356,9 +356,9 @@ void WindowManager::initialize(Settings &settings, Paths &paths)
{ {
WindowLayout windowLayout; WindowLayout windowLayout;
if (getArgs().customChannelLayout) if (getApp()->getArgs().customChannelLayout)
{ {
windowLayout = getArgs().customChannelLayout.value(); windowLayout = getApp()->getArgs().customChannelLayout.value();
} }
else else
{ {
@ -370,7 +370,7 @@ void WindowManager::initialize(Settings &settings, Paths &paths)
this->applyWindowLayout(windowLayout); this->applyWindowLayout(windowLayout);
} }
if (getArgs().isFramelessEmbed) if (getApp()->getArgs().isFramelessEmbed)
{ {
this->framelessEmbedWindow_.reset(new FramelessEmbedWindow); this->framelessEmbedWindow_.reset(new FramelessEmbedWindow);
this->framelessEmbedWindow_->show(); this->framelessEmbedWindow_->show();
@ -383,7 +383,7 @@ void WindowManager::initialize(Settings &settings, Paths &paths)
this->mainWindow_->getNotebook().addPage(true); this->mainWindow_->getNotebook().addPage(true);
// TODO: don't create main window if it's a frameless embed // TODO: don't create main window if it's a frameless embed
if (getArgs().isFramelessEmbed) if (getApp()->getArgs().isFramelessEmbed)
{ {
this->mainWindow_->hide(); this->mainWindow_->hide();
} }
@ -418,7 +418,7 @@ void WindowManager::initialize(Settings &settings, Paths &paths)
void WindowManager::save() void WindowManager::save()
{ {
if (getArgs().dontSaveSettings) if (getApp()->getArgs().dontSaveSettings)
{ {
return; return;
} }
@ -724,7 +724,7 @@ WindowLayout WindowManager::loadWindowLayoutFromFile() const
void WindowManager::applyWindowLayout(const WindowLayout &layout) void WindowManager::applyWindowLayout(const WindowLayout &layout)
{ {
if (getArgs().dontLoadMainWindow) if (getApp()->getArgs().dontLoadMainWindow)
{ {
return; return;
} }

View file

@ -64,13 +64,13 @@ bool FramelessEmbedWindow::nativeEvent(const QByteArray &eventType,
void FramelessEmbedWindow::showEvent(QShowEvent *) void FramelessEmbedWindow::showEvent(QShowEvent *)
{ {
if (!getArgs().parentWindowId) if (!getApp()->getArgs().parentWindowId)
{ {
return; return;
} }
if (auto parentHwnd = if (auto parentHwnd =
reinterpret_cast<HWND>(getArgs().parentWindowId.value())) reinterpret_cast<HWND>(getApp()->getArgs().parentWindowId.value()))
{ {
auto handle = reinterpret_cast<HWND>(this->winId()); auto handle = reinterpret_cast<HWND>(this->winId());
if (!::SetParent(handle, parentHwnd)) if (!::SetParent(handle, parentHwnd))

View file

@ -1347,7 +1347,7 @@ void SplitNotebook::addCustomButtons()
auto settingsBtn = this->addCustomButton(); auto settingsBtn = this->addCustomButton();
// This is to ensure you can't lock yourself out of the settings // This is to ensure you can't lock yourself out of the settings
if (getArgs().safeMode) if (getApp()->getArgs().safeMode)
{ {
settingsBtn->setVisible(true); settingsBtn->setVisible(true);
} }

View file

@ -737,7 +737,7 @@ void Window::onAccountSelected()
} }
#endif #endif
if (getArgs().safeMode) if (getApp()->getArgs().safeMode)
{ {
windowTitle += " (safe mode)"; windowTitle += " (safe mode)";
} }

View file

@ -43,7 +43,7 @@ namespace chatterino {
using namespace literals; using namespace literals;
LastRunCrashDialog::LastRunCrashDialog() LastRunCrashDialog::LastRunCrashDialog(const Args &args)
{ {
this->setWindowFlag(Qt::WindowContextHelpButtonHint, false); this->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
this->setWindowTitle(u"Chatterino - " % randomMessage()); this->setWindowTitle(u"Chatterino - " % randomMessage());
@ -62,14 +62,14 @@ LastRunCrashDialog::LastRunCrashDialog()
"<a href=\"file:///" % "<a href=\"file:///" %
reportsDir % u"\">" % reportsDir % u"</a>.<br>"; reportsDir % u"\">" % reportsDir % u"</a>.<br>";
if (getArgs().exceptionCode) if (args.exceptionCode)
{ {
text += u"The last run crashed with code <code>0x" % text += u"The last run crashed with code <code>0x" %
QString::number(*getArgs().exceptionCode, 16) % u"</code>"; QString::number(*args.exceptionCode, 16) % u"</code>";
if (getArgs().exceptionMessage) if (args.exceptionMessage)
{ {
text += u" (" % *getArgs().exceptionMessage % u")"; text += u" (" % *args.exceptionMessage % u")";
} }
text += u".<br>"_s; text += u".<br>"_s;

View file

@ -4,10 +4,12 @@
namespace chatterino { namespace chatterino {
class Args;
class LastRunCrashDialog : public QDialog class LastRunCrashDialog : public QDialog
{ {
public: public:
LastRunCrashDialog(); explicit LastRunCrashDialog(const Args &args);
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -411,7 +411,7 @@ void SettingsDialog::showEvent(QShowEvent *e)
///// Widget creation helpers ///// Widget creation helpers
void SettingsDialog::onOkClicked() void SettingsDialog::onOkClicked()
{ {
if (!getArgs().dontSaveSettings) if (!getApp()->getArgs().dontSaveSettings)
{ {
getApp()->commands->save(); getApp()->commands->save();
pajlada::Settings::SettingManager::gSave(); pajlada::Settings::SettingManager::gSave();

View file

@ -53,7 +53,7 @@ PluginsPage::PluginsPage()
this->rebuildContent(); this->rebuildContent();
}); });
groupLayout->addRow(box); groupLayout->addRow(box);
if (getArgs().safeMode) if (getApp()->getArgs().safeMode)
{ {
box->setEnabled(false); box->setEnabled(false);
auto *disabledLabel = new QLabel(this); auto *disabledLabel = new QLabel(this);
@ -197,7 +197,7 @@ void PluginsPage::rebuildContent()
this->rebuildContent(); this->rebuildContent();
}); });
pluginEntry->addRow(reloadButton); pluginEntry->addRow(reloadButton);
if (getArgs().safeMode) if (getApp()->getArgs().safeMode)
{ {
reloadButton->setEnabled(false); reloadButton->setEnabled(false);
} }