Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9dc8a7b
refactor: move Dash-specific font management to `qt/guiutil_font.{cpp…
kwvg Aug 29, 2025
306e703
refactor: consolidate font settings to struct `FontSettings`
kwvg Aug 29, 2025
f194b8f
refactor: consolidate available fonts with `AVAILABLE_FONTS`
kwvg Aug 29, 2025
5940f9f
refactor: consolidate Montserrat weight and name maps
kwvg Aug 28, 2025
2ea87cc
qt: recognize "Roboto Mono" as non-selectable font
kwvg Aug 28, 2025
daae3c1
qt: recognize system monospace font as non-selectable font
kwvg Aug 28, 2025
dcf919e
qt: apply monospace font to overview page balances
kwvg Aug 28, 2025
a1c5b68
qt: add monospaced font settings
kwvg Aug 29, 2025
467e57c
qt: adjust padding and font size of monospace font selector
kwvg Aug 28, 2025
3abaeee
merge bitcoin-core/gui#79: Embed monospaced font
kwvg Aug 28, 2025
fd6ec64
merge bitcoin-core/gui#600: Add OptionsModel getOption/setOption methods
kwvg Aug 18, 2025
ab0b32d
merge bitcoin-core/gui#601: Pass interfaces::Node references to Optio…
kwvg Apr 29, 2019
ad250c1
merge bitcoin#15936: Expose settings.json methods to GUI
kwvg Apr 29, 2019
489d853
qt: remove PrivateSend -> CoinJoin migration logic, remove old values
kwvg Aug 30, 2025
5ddec6d
qt: move Prune{,Size} handling outside `ENABLE_WALLET` gate
kwvg Aug 30, 2025
89e17f7
merge bitcoin-core/gui#602: Unify bitcoin-qt and bitcoind persistent …
kwvg Aug 30, 2025
eacc4cf
refactor: spin-off list of option IDs that require string workaround
kwvg Aug 25, 2025
a2eed11
qt: migrate `-coinjoinsessions` setting from QSettings to settings.json
kwvg Aug 26, 2025
856aadc
qt: migrate `-coinjoinrounds` setting from QSettings to settings.json
kwvg Aug 26, 2025
3be117b
qt: migrate `-coinjoinamount` setting from QSettings to settings.json
kwvg Aug 26, 2025
1b59fb3
qt: migrate `-coinjoinmultisession` setting from QSettings to setting…
kwvg Aug 25, 2025
cc00490
qt: migrate `-coinjoindenomsgoal` setting from QSettings to settings.…
kwvg Aug 26, 2025
ee02422
qt: migrate `-coinjoindenomshardcap` setting from QSettings to settin…
kwvg Aug 26, 2025
1401cc0
qt: migrate `-enablecoinjoin` setting from QSettings to settings.json
kwvg Aug 29, 2025
350d20c
qt: migrate `-font-family` setting from QSettings to settings.json
kwvg Aug 26, 2025
fd18417
qt: migrate `-font-scale` setting from QSettings to settings.json
kwvg Aug 26, 2025
74d8f54
qt: migrate `-font-weight-normal` from QSettings to settings.json
kwvg Aug 30, 2025
34d1d16
qt: migrate `-font-weight-bold` from QSettings to settings.json
kwvg Aug 30, 2025
41ee54e
qt: use fallback weight if weightFromArg fails
kwvg Aug 30, 2025
171c6a9
merge bitcoin-core/gui#701: Persist Mask Values option
kwvg Jan 24, 2023
3f3d71b
merge bitcoin-core/gui#603: Add settings.json prune-prev, proxy-prev,…
kwvg Apr 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/release-notes-6833.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
GUI changes
-----------

Configuration changes made in the Dash GUI (such as the pruning setting,
proxy settings, UPNP preferences) are now saved to `<datadir>/settings.json`
file rather than to the Qt settings backend (windows registry or unix desktop
config files), so these settings will now apply to dashd, instead of being
ignored.

Also, the interaction between GUI settings and `dash.conf` settings is
simplified. Settings from `dash.conf` are now displayed normally in the GUI
settings dialog, instead of in a separate warning message ("Options set in this
dialog are overridden by the configuration file: -setting=value"). And these
settings can now be edited because `settings.json` values take precedence over
`dash.conf` values.
2 changes: 2 additions & 0 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ BITCOIN_QT_H = \
qt/proposalwizard.h \
qt/guiconstants.h \
qt/guiutil.h \
qt/guiutil_font.h \
qt/initexecutor.h \
qt/intro.h \
qt/macdockiconhandler.h \
Expand Down Expand Up @@ -227,6 +228,7 @@ BITCOIN_QT_BASE_CPP = \
qt/clientmodel.cpp \
qt/csvmodelwriter.cpp \
qt/guiutil.cpp \
qt/guiutil_font.cpp \
qt/initexecutor.cpp \
qt/intro.cpp \
qt/modaloverlay.cpp \
Expand Down
1 change: 0 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,6 @@ void Shutdown(NodeContext& node)
LogPrintf("%s: Unable to remove PID file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
}

node.args = nullptr;
LogPrintf("%s: done\n", __func__);
}

Expand Down
29 changes: 24 additions & 5 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
#ifndef BITCOIN_INTERFACES_NODE_H
#define BITCOIN_INTERFACES_NODE_H

#include <consensus/amount.h> // For CAmount
#include <net.h> // For NodeId
#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
#include <netbase.h> // For ConnectionDirection
#include <consensus/amount.h> // For CAmount
#include <net.h> // For NodeId
#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
#include <netbase.h> // For ConnectionDirection
#include <support/allocators/secure.h> // For SecureString
#include <uint256.h>
#include <util/settings.h> // For util::SettingsValue
#include <util/translation.h>

#include <functional>
Expand Down Expand Up @@ -193,6 +194,24 @@ class Node
//! Return whether shutdown was requested.
virtual bool shutdownRequested() = 0;

//! Return whether a particular setting in <datadir>/settings.json is or
//! would be ignored because it is also specified in the command line.
virtual bool isSettingIgnored(const std::string& name) = 0;

//! Return setting value from <datadir>/settings.json or bitcoin.conf.
virtual util::SettingsValue getPersistentSetting(const std::string& name) = 0;

//! Update a setting in <datadir>/settings.json.
virtual void updateRwSetting(const std::string& name, const util::SettingsValue& value) = 0;

//! Force a setting value to be applied, overriding any other configuration
//! source, but not being persisted.
virtual void forceSetting(const std::string& name, const util::SettingsValue& value) = 0;

//! Clear all settings in <datadir>/settings.json and store a backup of
//! previous settings in <datadir>/settings.json.bak.
virtual void resetSettings() = 0;

//! Map port.
virtual void mapPort(bool use_upnp, bool use_natpmp) = 0;

Expand Down
40 changes: 40 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,46 @@ class NodeImpl : public Node
}
}
bool shutdownRequested() override { return ShutdownRequested(); }
bool isSettingIgnored(const std::string& name) override
{
bool ignored = false;
gArgs.LockSettings([&](util::Settings& settings) {
if (auto* options = util::FindKey(settings.command_line_options, name)) {
ignored = !options->empty();
}
});
return ignored;
}
Comment on lines +447 to +456
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Also treat forced settings as “ignored” overrides

isSettingIgnored only checks command_line_options. If a setting is overridden via forced_settings, the GUI will not flag it as ignored. Either update the docstring in node.h or include forced settings here for consistency with ignore_nonpersistent.

Apply:

 bool isSettingIgnored(const std::string& name) override
 {
-    bool ignored = false;
-    gArgs.LockSettings([&](util::Settings& settings) {
-        if (auto* options = util::FindKey(settings.command_line_options, name)) {
-            ignored = !options->empty();
-        }
-    });
-    return ignored;
+    bool ignored = false;
+    gArgs.LockSettings([&](const util::Settings& settings) {
+        if (const auto* v = util::FindKey(settings.command_line_options, name)) {
+            ignored = !v->empty();
+        }
+        if (!ignored) {
+            if (const auto* f = util::FindKey(settings.forced_settings, name)) {
+                ignored = !f->empty();
+            }
+        }
+    });
+    return ignored;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool isSettingIgnored(const std::string& name) override
{
bool ignored = false;
gArgs.LockSettings([&](util::Settings& settings) {
if (auto* options = util::FindKey(settings.command_line_options, name)) {
ignored = !options->empty();
}
});
return ignored;
}
bool isSettingIgnored(const std::string& name) override
{
bool ignored = false;
gArgs.LockSettings([&](const util::Settings& settings) {
if (const auto* v = util::FindKey(settings.command_line_options, name)) {
ignored = !v->empty();
}
if (!ignored) {
if (const auto* f = util::FindKey(settings.forced_settings, name)) {
ignored = !f->empty();
}
}
});
return ignored;
}
🤖 Prompt for AI Agents
In src/node/interfaces.cpp around lines 447 to 456, isSettingIgnored currently
only checks command_line_options and therefore misses settings present in
forced_settings; update the function to also check settings.forced_settings
(using util::FindKey or equivalent) and mark the setting as ignored if a
forced_settings entry exists or is non-empty, mirroring ignore_nonpersistent
behavior; keep the gArgs.LockSettings scope and combine the checks so that
ignored becomes true if either command_line_options or forced_settings indicates
an override.

util::SettingsValue getPersistentSetting(const std::string& name) override { return gArgs.GetPersistentSetting(name); }
void updateRwSetting(const std::string& name, const util::SettingsValue& value) override
{
gArgs.LockSettings([&](util::Settings& settings) {
if (value.isNull()) {
settings.rw_settings.erase(name);
} else {
settings.rw_settings[name] = value;
}
});
gArgs.WriteSettingsFile();
}
Comment on lines +458 to +468
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Unify update path and handle write failures

This void updateRwSetting duplicates the logic of the existing bool updateRwSetting(name, value, write) and ignores the write result. Delegate to the boolean overload to centralize behavior and optionally log failures.

Apply:

 void updateRwSetting(const std::string& name, const util::SettingsValue& value) override
 {
-    gArgs.LockSettings([&](util::Settings& settings) {
-        if (value.isNull()) {
-            settings.rw_settings.erase(name);
-        } else {
-            settings.rw_settings[name] = value;
-        }
-    });
-    gArgs.WriteSettingsFile();
+    (void)updateRwSetting(name, value, /*write=*/true);
 }
🤖 Prompt for AI Agents
In src/node/interfaces.cpp around lines 458 to 468, this void updateRwSetting
duplicates logic of the existing bool updateRwSetting(name, value, write) and
ignores whether the write succeeded; replace the implementation to call the
boolean overload (e.g. updateRwSetting(name, value, /*write*/ true)) and if it
returns false, emit a failure log (use the existing logging facility in this
file) so write failures are not silently ignored, thereby centralizing behavior
and preserving the original semantics.

void forceSetting(const std::string& name, const util::SettingsValue& value) override
{
gArgs.LockSettings([&](util::Settings& settings) {
if (value.isNull()) {
settings.forced_settings.erase(name);
} else {
settings.forced_settings[name] = value;
}
});
}
void resetSettings() override
{
gArgs.WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
gArgs.LockSettings([&](util::Settings& settings) {
settings.rw_settings.clear();
});
gArgs.WriteSettingsFile();
}
void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(ConnectionDirection flags) override
Expand Down
1 change: 1 addition & 0 deletions src/qt/addressbookpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/optionsmodel.h>
#include <qt/qrdialog.h>

Expand Down
1 change: 1 addition & 0 deletions src/qt/addresstablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <qt/addresstablemodel.h>

#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/walletmodel.h>

#include <key_io.h>
Expand Down
8 changes: 3 additions & 5 deletions src/qt/appearancewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ AppearanceWidget::AppearanceWidget(QWidget* parent) :
ui->theme->addItem(entry, QVariant(entry));
}

GUIUtil::FontFamily fontSystem = GUIUtil::FontFamily::SystemDefault;
GUIUtil::FontFamily fontMontserrat = GUIUtil::FontFamily::Montserrat;

ui->fontFamily->addItem(GUIUtil::fontFamilyToString(fontSystem), QVariant(static_cast<int>(fontSystem)));
ui->fontFamily->addItem(GUIUtil::fontFamilyToString(fontMontserrat), QVariant(static_cast<int>(fontMontserrat)));
for (const auto& [family, family_str, selectable] : GUIUtil::AVAILABLE_FONTS) {
if (selectable) ui->fontFamily->addItem(family_str, QVariant(static_cast<int>(family)));
}

updateWeightSlider();

Expand Down
1 change: 1 addition & 0 deletions src/qt/appearancewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <QWidget>

#include <qt/guiutil.h>
#include <qt/guiutil_font.h>

namespace Ui {
class AppearanceWidget;
Expand Down
1 change: 1 addition & 0 deletions src/qt/askpassphrasedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/walletmodel.h>

#include <support/allocators/secure.h>
Expand Down
51 changes: 36 additions & 15 deletions src/qt/bitcoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/initexecutor.h>
#include <qt/intro.h>
#include <qt/networkstyle.h>
Expand Down Expand Up @@ -267,9 +268,26 @@ void BitcoinApplication::createPaymentServer()
}
#endif

void BitcoinApplication::createOptionsModel(bool resetSettings)
bool BitcoinApplication::createOptionsModel(bool resetSettings)
{
optionsModel = new OptionsModel(this, resetSettings);
optionsModel = new OptionsModel(node(), this);
if (resetSettings) {
optionsModel->Reset();
}
bilingual_str error;
if (!optionsModel->Init(error)) {
fs::path settings_path;
if (gArgs.GetSettingsPath(&settings_path)) {
error += Untranslated("\n");
std::string quoted_path = strprintf("%s", fs::quoted(fs::PathToString(settings_path)));
error.original += strprintf("Settings file %s might be corrupt or invalid.", quoted_path);
error.translated += tr("Settings file %1 might be corrupt or invalid.").arg(QString::fromStdString(quoted_path)).toStdString();
}
InitError(error);
QMessageBox::critical(nullptr, PACKAGE_NAME, QString::fromStdString(error.translated));
return false;
}
return true;
}
Comment on lines +271 to 291
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Compile error: use std::quoted (not fs::quoted) and include .

fs has no quoted; std::quoted is in . Fix as below.

@@
-#include <memory>
+#include <memory>
+#include <iomanip> // for std::quoted
@@
-        if (gArgs.GetSettingsPath(&settings_path)) {
+        if (gArgs.GetSettingsPath(&settings_path)) {
             error += Untranslated("\n");
-            std::string quoted_path = strprintf("%s", fs::quoted(fs::PathToString(settings_path)));
+            std::string quoted_path = strprintf("%s", std::quoted(fs::PathToString(settings_path)));
             error.original += strprintf("Settings file %s might be corrupt or invalid.", quoted_path);
             error.translated += tr("Settings file %1 might be corrupt or invalid.").arg(QString::fromStdString(quoted_path)).toStdString();
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool BitcoinApplication::createOptionsModel(bool resetSettings)
{
optionsModel = new OptionsModel(this, resetSettings);
optionsModel = new OptionsModel(node(), this);
if (resetSettings) {
optionsModel->Reset();
}
bilingual_str error;
if (!optionsModel->Init(error)) {
fs::path settings_path;
if (gArgs.GetSettingsPath(&settings_path)) {
error += Untranslated("\n");
std::string quoted_path = strprintf("%s", fs::quoted(fs::PathToString(settings_path)));
error.original += strprintf("Settings file %s might be corrupt or invalid.", quoted_path);
error.translated += tr("Settings file %1 might be corrupt or invalid.").arg(QString::fromStdString(quoted_path)).toStdString();
}
InitError(error);
QMessageBox::critical(nullptr, PACKAGE_NAME, QString::fromStdString(error.translated));
return false;
}
return true;
}
#include <memory>
#include <iomanip> // for std::quoted
bool BitcoinApplication::createOptionsModel(bool resetSettings)
{
optionsModel = new OptionsModel(node(), this);
if (resetSettings) {
optionsModel->Reset();
}
bilingual_str error;
if (!optionsModel->Init(error)) {
fs::path settings_path;
if (gArgs.GetSettingsPath(&settings_path)) {
error += Untranslated("\n");
std::string quoted_path = strprintf("%s", std::quoted(fs::PathToString(settings_path)));
error.original += strprintf("Settings file %s might be corrupt or invalid.", quoted_path);
error.translated += tr("Settings file %1 might be corrupt or invalid.").arg(QString::fromStdString(quoted_path)).toStdString();
}
InitError(error);
QMessageBox::critical(nullptr, PACKAGE_NAME, QString::fromStdString(error.translated));
return false;
}
return true;
}
🤖 Prompt for AI Agents
In src/qt/bitcoin.cpp around lines 271 to 291, the code incorrectly calls
fs::quoted (which doesn't exist) and doesn't include the header for std::quoted;
change fs::quoted to std::quoted and add #include <iomanip> to the file (or a
common header included by this translation unit) so std::quoted is available;
ensure the call uses std::quoted(std::string) (i.e., keep the strprintf
wrapping) and fully-qualify as std::quoted to avoid relying on using directives.


void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
Expand All @@ -295,7 +313,6 @@ void BitcoinApplication::createNode(interfaces::Init& init)
{
assert(!m_node);
m_node = init.makeNode();
if (optionsModel) optionsModel->setNode(*m_node);
if (m_splash) m_splash->setNode(*m_node);
}

Expand Down Expand Up @@ -332,7 +349,7 @@ void BitcoinApplication::parameterSetup()

void BitcoinApplication::InitPruneSetting(int64_t prune_MiB)
{
optionsModel->SetPruneTargetGB(PruneMiBtoGB(prune_MiB), true);
optionsModel->SetPruneTargetGB(PruneMiBtoGB(prune_MiB));
}

void BitcoinApplication::requestInitialize()
Expand Down Expand Up @@ -488,10 +505,10 @@ static void SetupUIArgs(ArgsManager& argsman)
{
argsman.AddArg("-choosedatadir", strprintf(QObject::tr("Choose data directory on startup (default: %u)").toStdString(), DEFAULT_CHOOSE_DATADIR), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-custom-css-dir", "Set a directory which contains custom css files. Those will be used as stylesheets for the UI.", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-family", QObject::tr("Set the font family. Possible values: %1. (default: %2)").arg("SystemDefault, Montserrat").arg(GUIUtil::fontFamilyToString(GUIUtil::getFontFamilyDefault())).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-scale", QObject::tr("Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3)").arg(-100).arg(100).arg(GUIUtil::getFontScaleDefault()).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-weight-bold", QObject::tr("Set the font weight for bold texts. Possible range %1 to %2 (default: %3)").arg(0).arg(8).arg(GUIUtil::weightToArg(GUIUtil::getFontWeightBoldDefault())).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-weight-normal", QObject::tr("Set the font weight for normal texts. Possible range %1 to %2 (default: %3)").arg(0).arg(8).arg(GUIUtil::weightToArg(GUIUtil::getFontWeightNormalDefault())).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-family", QObject::tr("Set the font family. Possible values: %1. (default: %2)").arg("SystemDefault, Montserrat").arg(GUIUtil::fontFamilyToString(GUIUtil::g_font_defaults.family)).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-scale", QObject::tr("Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3)").arg(-100).arg(100).arg(GUIUtil::g_font_defaults.scale).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-weight-bold", QObject::tr("Set the font weight for bold texts. Possible range %1 to %2 (default: %3)").arg(0).arg(8).arg(GUIUtil::weightToArg(GUIUtil::g_font_defaults.weight_bold)).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-font-weight-normal", QObject::tr("Set the font weight for normal texts. Possible range %1 to %2 (default: %3)").arg(0).arg(8).arg(GUIUtil::weightToArg(GUIUtil::g_font_defaults.weight_normal)).toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-lang=<lang>", QObject::tr("Set language, for example \"de_DE\" (default: system locale)").toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-min", QObject::tr("Start minimized").toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
argsman.AddArg("-resetguisettings", QObject::tr("Reset all settings changed in the GUI").toStdString(), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
Expand Down Expand Up @@ -670,12 +687,21 @@ int GuiMain(int argc, char* argv[])
QObject::tr("Error: Failed to load application fonts."));
return EXIT_FAILURE;
}

if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
app.createSplashScreen(networkStyle.data());

app.createNode(*init);

// Load GUI settings from QSettings
app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false));
if (!app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false))) {
return EXIT_FAILURE;
}

// Validate/set font family
if (gArgs.IsArgSet("-font-family")) {
GUIUtil::FontFamily family;
QString strFamily = gArgs.GetArg("-font-family", GUIUtil::fontFamilyToString(GUIUtil::getFontFamilyDefault()).toStdString()).c_str();
QString strFamily = gArgs.GetArg("-font-family", GUIUtil::fontFamilyToString(GUIUtil::g_font_defaults.family).toStdString()).c_str();
try {
family = GUIUtil::fontFamilyFromString(strFamily);
} catch (const std::exception& e) {
Expand Down Expand Up @@ -762,11 +788,6 @@ int GuiMain(int argc, char* argv[])
app.InitPruneSetting(prune_MiB);
}

if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
app.createSplashScreen(networkStyle.data());

app.createNode(*init);

int rv = EXIT_SUCCESS;
try
{
Expand Down
2 changes: 1 addition & 1 deletion src/qt/bitcoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class BitcoinApplication: public QApplication
/// parameter interaction/setup based on rules
void parameterSetup();
/// Create options model
void createOptionsModel(bool resetSettings);
[[nodiscard]] bool createOptionsModel(bool resetSettings);
/// Initialize prune setting
void InitPruneSetting(int64_t prune_MiB);
/// Create main window
Expand Down
3 changes: 3 additions & 0 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <qt/createwalletdialog.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/modaloverlay.h>
#include <qt/networkstyle.h>
#include <qt/notificator.h>
Expand Down Expand Up @@ -888,6 +889,8 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH

connect(optionsModel, &OptionsModel::coinJoinEnabledChanged, this, &BitcoinGUI::updateCoinJoinVisibility);
}

m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool());
} else {
Comment on lines +893 to 894
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Null-deref risk if OptionsModel is null.

_setClientModel() unconditionally dereferences _clientModel->getOptionsModel() to set m_mask_values_action. This can crash when options model is not yet available. Guard it.

-        m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool());
+        if (OptionsModel* opt = _clientModel->getOptionsModel()) {
+            m_mask_values_action->setChecked(opt->getOption(OptionsModel::OptionID::MaskValues).toBool());
+        } else {
+            m_mask_values_action->setChecked(false);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
m_mask_values_action->setChecked(_clientModel->getOptionsModel()->getOption(OptionsModel::OptionID::MaskValues).toBool());
} else {
if (OptionsModel* opt = _clientModel->getOptionsModel()) {
m_mask_values_action->setChecked(opt->getOption(OptionsModel::OptionID::MaskValues).toBool());
} else {
m_mask_values_action->setChecked(false);
}
} else {
🤖 Prompt for AI Agents
In src/qt/bitcoingui.cpp around lines 893-894, the code unconditionally calls
_clientModel->getOptionsModel()->getOption(...), risking a null-deref if
getOptionsModel() returns nullptr; change the logic to first check that
_clientModel and _clientModel->getOptionsModel() are non-null before calling
getOption, and only call m_mask_values_action->setChecked(...) when the options
model exists (otherwise set a safe default or leave the action unchecked);
ensure any subsequent logic that assumes the options model exists is similarly
guarded or deferred until the model is available.

if(trayIconMenu)
{
Expand Down
1 change: 1 addition & 0 deletions src/qt/coincontroldialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <qt/addresstablemodel.h>
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/optionsmodel.h>
#include <qt/walletmodel.h>

Expand Down
Loading
Loading