feat: never destroy config singletons
There are lots of issues with it, so instead give ownership to C++ and don't destroy on reloads (this does mean it does not reload, but it doesn't need to anyways)
This commit is contained in:
parent
9cf3ad4094
commit
f65723ad71
4 changed files with 13 additions and 65 deletions
|
|
@ -9,8 +9,6 @@ namespace caelestia::config {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
GlobalConfig* s_instance = nullptr;
|
|
||||||
|
|
||||||
QString configDir() {
|
QString configDir() {
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/caelestia/");
|
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/caelestia/");
|
||||||
}
|
}
|
||||||
|
|
@ -36,14 +34,7 @@ GlobalConfig::GlobalConfig(QObject* parent)
|
||||||
, m_sidebar(new SidebarConfig(this))
|
, m_sidebar(new SidebarConfig(this))
|
||||||
, m_services(new ServiceConfig(this))
|
, m_services(new ServiceConfig(this))
|
||||||
, m_paths(new UserPaths(this)) {
|
, m_paths(new UserPaths(this)) {
|
||||||
// Set global instance
|
|
||||||
s_instance = this;
|
|
||||||
|
|
||||||
setupFileBackend(configDir() + QStringLiteral("shell.json"));
|
setupFileBackend(configDir() + QStringLiteral("shell.json"));
|
||||||
|
|
||||||
// If TokenConfig was created before us, bind now
|
|
||||||
if (TokenConfig::instance())
|
|
||||||
bindAppearanceTokens();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalConfig::GlobalConfig(GlobalConfig* fallback, const QString& filePath, QObject* parent)
|
GlobalConfig::GlobalConfig(GlobalConfig* fallback, const QString& filePath, QObject* parent)
|
||||||
|
|
@ -72,13 +63,10 @@ GlobalConfig::GlobalConfig(GlobalConfig* fallback, const QString& filePath, QObj
|
||||||
syncFromGlobal(fallback);
|
syncFromGlobal(fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalConfig::~GlobalConfig() {
|
|
||||||
if (s_instance == this)
|
|
||||||
s_instance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalConfig* GlobalConfig::instance() {
|
GlobalConfig* GlobalConfig::instance() {
|
||||||
return s_instance;
|
static GlobalConfig instance;
|
||||||
|
instance.bindAppearanceTokens();
|
||||||
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalConfig* GlobalConfig::defaults() {
|
GlobalConfig* GlobalConfig::defaults() {
|
||||||
|
|
@ -91,14 +79,8 @@ void GlobalConfig::bindAppearanceTokens() {
|
||||||
if (m_tokensBound)
|
if (m_tokensBound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto* tokens = TokenConfig::instance();
|
|
||||||
if (!tokens) {
|
|
||||||
qCDebug(lcConfig) << "GlobalConfig::bindAppearanceTokens: TokenConfig not yet available";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCDebug(lcConfig) << "GlobalConfig::bindAppearanceTokens: binding appearance to token values";
|
qCDebug(lcConfig) << "GlobalConfig::bindAppearanceTokens: binding appearance to token values";
|
||||||
auto* tokenAppearance = tokens->appearance();
|
auto* const tokenAppearance = TokenConfig::instance()->appearance();
|
||||||
m_appearance->rounding()->bindTokens(tokenAppearance->rounding());
|
m_appearance->rounding()->bindTokens(tokenAppearance->rounding());
|
||||||
m_appearance->spacing()->bindTokens(tokenAppearance->spacing());
|
m_appearance->spacing()->bindTokens(tokenAppearance->spacing());
|
||||||
m_appearance->padding()->bindTokens(tokenAppearance->padding());
|
m_appearance->padding()->bindTokens(tokenAppearance->padding());
|
||||||
|
|
@ -107,17 +89,9 @@ void GlobalConfig::bindAppearanceTokens() {
|
||||||
m_tokensBound = true;
|
m_tokensBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalConfig* GlobalConfig::create(QQmlEngine* engine, QJSEngine* jsEngine) {
|
GlobalConfig* GlobalConfig::create(QQmlEngine*, QJSEngine*) {
|
||||||
auto* config = new GlobalConfig(engine);
|
QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
|
||||||
|
return instance();
|
||||||
// Ensure TokenConfig is created — appearance computed properties depend on token binding.
|
|
||||||
if (!TokenConfig::instance())
|
|
||||||
TokenConfig::create(engine, jsEngine);
|
|
||||||
|
|
||||||
// Bind now that both singletons exist
|
|
||||||
config->bindAppearanceTokens();
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config (attached type)
|
// Config (attached type)
|
||||||
|
|
@ -140,8 +114,7 @@ void Config::connectScope() {
|
||||||
const Type* Config::name() const { \
|
const Type* Config::name() const { \
|
||||||
if (m_scope && m_scope->config()) \
|
if (m_scope && m_scope->config()) \
|
||||||
return m_scope->config()->name(); \
|
return m_scope->config()->name(); \
|
||||||
auto* global = GlobalConfig::instance(); \
|
return GlobalConfig::instance()->name(); \
|
||||||
return global ? global->name() : nullptr; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_ATTACHED_GETTER(AppearanceConfig, appearance)
|
CONFIG_ATTACHED_GETTER(AppearanceConfig, appearance)
|
||||||
|
|
@ -165,11 +138,6 @@ CONFIG_ATTACHED_GETTER(UserPaths, paths)
|
||||||
#undef CONFIG_ATTACHED_GETTER
|
#undef CONFIG_ATTACHED_GETTER
|
||||||
|
|
||||||
Config* Config::qmlAttachedProperties(QObject* object) {
|
Config* Config::qmlAttachedProperties(QObject* object) {
|
||||||
// Ensure GlobalConfig singleton is created before any attached property access
|
|
||||||
if (!GlobalConfig::instance()) {
|
|
||||||
if (auto* engine = qmlEngine(object))
|
|
||||||
engine->singletonInstance<GlobalConfig*>("Caelestia.Config", "GlobalConfig");
|
|
||||||
}
|
|
||||||
return new Config(ConfigScope::find(object), object);
|
return new Config(ConfigScope::find(object), object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,6 @@ public:
|
||||||
[[nodiscard]] Q_INVOKABLE GlobalConfig* defaults();
|
[[nodiscard]] Q_INVOKABLE GlobalConfig* defaults();
|
||||||
static GlobalConfig* create(QQmlEngine*, QJSEngine*);
|
static GlobalConfig* create(QQmlEngine*, QJSEngine*);
|
||||||
|
|
||||||
~GlobalConfig() override;
|
|
||||||
|
|
||||||
void bindAppearanceTokens();
|
void bindAppearanceTokens();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@ namespace caelestia::config {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
TokenConfig* s_instance = nullptr;
|
|
||||||
|
|
||||||
QString configDir() {
|
QString configDir() {
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/caelestia/");
|
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/caelestia/");
|
||||||
}
|
}
|
||||||
|
|
@ -21,13 +19,7 @@ TokenConfig::TokenConfig(QObject* parent)
|
||||||
: RootConfig(parent)
|
: RootConfig(parent)
|
||||||
, m_appearance(new AppearanceTokens(this))
|
, m_appearance(new AppearanceTokens(this))
|
||||||
, m_sizes(new SizeTokens(this)) {
|
, m_sizes(new SizeTokens(this)) {
|
||||||
s_instance = this;
|
|
||||||
|
|
||||||
setupFileBackend(configDir() + QStringLiteral("shell-tokens.json"));
|
setupFileBackend(configDir() + QStringLiteral("shell-tokens.json"));
|
||||||
|
|
||||||
// If GlobalConfig was created before us, trigger its binding
|
|
||||||
if (auto* global = GlobalConfig::instance())
|
|
||||||
global->bindAppearanceTokens();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenConfig::TokenConfig(TokenConfig* fallback, const QString& filePath, QObject* parent)
|
TokenConfig::TokenConfig(TokenConfig* fallback, const QString& filePath, QObject* parent)
|
||||||
|
|
@ -41,13 +33,9 @@ TokenConfig::TokenConfig(TokenConfig* fallback, const QString& filePath, QObject
|
||||||
syncFromGlobal(fallback);
|
syncFromGlobal(fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenConfig::~TokenConfig() {
|
|
||||||
if (s_instance == this)
|
|
||||||
s_instance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
TokenConfig* TokenConfig::instance() {
|
TokenConfig* TokenConfig::instance() {
|
||||||
return s_instance;
|
static TokenConfig instance;
|
||||||
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenConfig* TokenConfig::defaults() {
|
TokenConfig* TokenConfig::defaults() {
|
||||||
|
|
@ -56,8 +44,9 @@ TokenConfig* TokenConfig::defaults() {
|
||||||
return m_defaults;
|
return m_defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenConfig* TokenConfig::create(QQmlEngine* engine, QJSEngine*) {
|
TokenConfig* TokenConfig::create(QQmlEngine*, QJSEngine*) {
|
||||||
return new TokenConfig(engine);
|
QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
|
||||||
|
return instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tokens (attached type)
|
// Tokens (attached type)
|
||||||
|
|
@ -132,11 +121,6 @@ const SizeTokens* Tokens::sizes() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Tokens* Tokens::qmlAttachedProperties(QObject* object) {
|
Tokens* Tokens::qmlAttachedProperties(QObject* object) {
|
||||||
// Ensure GlobalConfig singleton is created before any attached property access
|
|
||||||
if (!GlobalConfig::instance()) {
|
|
||||||
if (auto* engine = qmlEngine(object))
|
|
||||||
engine->singletonInstance<GlobalConfig*>("Caelestia.Config", "GlobalConfig");
|
|
||||||
}
|
|
||||||
return new Tokens(ConfigScope::find(object), object);
|
return new Tokens(ConfigScope::find(object), object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -332,8 +332,6 @@ public:
|
||||||
[[nodiscard]] Q_INVOKABLE TokenConfig* defaults();
|
[[nodiscard]] Q_INVOKABLE TokenConfig* defaults();
|
||||||
static TokenConfig* create(QQmlEngine*, QJSEngine*);
|
static TokenConfig* create(QQmlEngine*, QJSEngine*);
|
||||||
|
|
||||||
~TokenConfig() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MonitorConfigManager;
|
friend class MonitorConfigManager;
|
||||||
explicit TokenConfig(QObject* parent = nullptr);
|
explicit TokenConfig(QObject* parent = nullptr);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue