-
Notifications
You must be signed in to change notification settings - Fork 48
fix(dconfig): cache configuration objects for the compositor lifetime #1252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| // Copyright (C) 2026 UnionTech Software Technology Co., Ltd. | ||
| // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | ||
|
|
||
| #include "systemdconfigmanager.h" | ||
|
|
||
| #include "appconfig.hpp" | ||
| #include "outputconfig.hpp" | ||
| #include "seatuserconfig.hpp" | ||
| #include "treelandconfig.hpp" | ||
| #include "treelanduserconfig.hpp" | ||
|
|
||
| #include <DConfig> | ||
|
|
||
| namespace { | ||
|
|
||
| QString configSubpath(const QString &name) | ||
| { | ||
| return QStringLiteral("/") + name; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| SystemDConfigManager *SystemDConfigManager::s_instance = nullptr; | ||
|
|
||
| SystemDConfigManager::SystemDConfigManager(QObject *parent) | ||
| : QObject(parent) | ||
| { | ||
| Q_ASSERT(!s_instance); | ||
| s_instance = this; | ||
|
|
||
| m_globalConfig = TreelandConfig::create(QStringLiteral("org.deepin.dde.treeland"), | ||
| QString(), | ||
| this); | ||
| Q_ASSERT(m_globalConfig); | ||
|
|
||
| connect(m_globalConfig, | ||
| &TreelandConfig::configInitializeSucceed, | ||
| this, | ||
| [this](DTK_CORE_NAMESPACE::DConfig *) { Q_EMIT InitializeSucceed(); }, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 可以直接连接,为啥要用lambda |
||
| Qt::SingleShotConnection); | ||
| connect(m_globalConfig, | ||
| &TreelandConfig::configInitializeFailed, | ||
| this, | ||
| [this] { Q_EMIT InitializeFailed(); }, | ||
| Qt::SingleShotConnection); | ||
| } | ||
|
|
||
| SystemDConfigManager::~SystemDConfigManager() | ||
| { | ||
| if (s_instance == this) { | ||
| s_instance = nullptr; | ||
| } | ||
| } | ||
|
|
||
| SystemDConfigManager *SystemDConfigManager::instance() | ||
| { | ||
| return s_instance; | ||
| } | ||
|
|
||
| bool SystemDConfigManager::isInitializeSucceeded() const | ||
| { | ||
| return m_globalConfig && m_globalConfig->isInitializeSucceeded(); | ||
| } | ||
|
|
||
| bool SystemDConfigManager::isInitializeFailed() const | ||
| { | ||
| return !m_globalConfig || m_globalConfig->isInitializeFailed(); | ||
| } | ||
|
|
||
| TreelandConfig *SystemDConfigManager::globalConfig() const | ||
| { | ||
| return m_globalConfig; | ||
| } | ||
|
|
||
| TreelandUserConfig *SystemDConfigManager::userConfig(const QString &userName) | ||
| { | ||
| if (userName.isEmpty()) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| if (auto *config = m_userConfigs.value(userName)) { | ||
| return config; | ||
| } | ||
|
|
||
| auto *config = TreelandUserConfig::createByName(QStringLiteral("org.deepin.dde.treeland.user"), | ||
| QStringLiteral("org.deepin.dde.treeland"), | ||
| configSubpath(userName), | ||
| this); | ||
| m_userConfigs.insert(userName, config); | ||
| return config; | ||
| } | ||
|
|
||
| SeatUserDConfig *SystemDConfigManager::seatUserConfig(const QString &userName) | ||
| { | ||
| if (userName.isEmpty()) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| if (auto *config = m_seatUserConfigs.value(userName)) { | ||
| return config; | ||
| } | ||
|
|
||
| auto *config = SeatUserDConfig::createByName( | ||
| QStringLiteral("org.deepin.dde.treeland.user.seat"), | ||
| QStringLiteral("org.deepin.dde.treeland"), | ||
| configSubpath(userName), | ||
| this); | ||
| m_seatUserConfigs.insert(userName, config); | ||
| return config; | ||
| } | ||
|
|
||
| OutputConfig *SystemDConfigManager::outputConfig(const QString &outputName) | ||
| { | ||
| if (outputName.isEmpty()) { | ||
| return nullptr; | ||
| } | ||
|
Comment on lines
+114
to
+116
|
||
|
|
||
| if (auto *config = m_outputConfigs.value(outputName)) { | ||
| return config; | ||
| } | ||
|
|
||
| auto *config = OutputConfig::createByName(QStringLiteral("org.deepin.dde.treeland.output"), | ||
| QStringLiteral("org.deepin.dde.treeland"), | ||
| configSubpath(outputName), | ||
| this); | ||
| m_outputConfigs.insert(outputName, config); | ||
| return config; | ||
| } | ||
|
|
||
| AppConfig *SystemDConfigManager::appConfig(const QString &appId) | ||
| { | ||
| if (appId.isEmpty()) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| if (auto *config = m_appConfigs.value(appId)) { | ||
| return config; | ||
| } | ||
|
|
||
| auto *config = AppConfig::create(QStringLiteral("org.deepin.dde.treeland"), | ||
| configSubpath(appId), | ||
| this); | ||
| m_appConfigs.insert(appId, config); | ||
| return config; | ||
| } | ||
|
|
||
| bool SystemDConfigManager::initializeUserConfigs(const QString &userName) | ||
| { | ||
| m_initialUserConfig = userConfig(userName); | ||
| const auto *seatConfig = seatUserConfig(userName); | ||
| return m_initialUserConfig && seatConfig | ||
| && m_initialUserConfig->isInitializeSucceeded() | ||
| && seatConfig->isInitializeSucceeded(); | ||
| } | ||
|
|
||
| TreelandUserConfig *SystemDConfigManager::initialUserConfig() const | ||
| { | ||
| return m_initialUserConfig; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // Copyright (C) 2026 UnionTech Software Technology Co., Ltd. | ||
| // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <QHash> | ||
| #include <QObject> | ||
| #include <QString> | ||
|
|
||
| class AppConfig; | ||
| class OutputConfig; | ||
| class SeatUserDConfig; | ||
| class TreelandConfig; | ||
| class TreelandUserConfig; | ||
|
|
||
| class SystemDConfigManager : public QObject | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| explicit SystemDConfigManager(QObject *parent = nullptr); | ||
| ~SystemDConfigManager() override; | ||
|
|
||
| static SystemDConfigManager *instance(); | ||
|
|
||
| bool isInitializeSucceeded() const; | ||
| bool isInitializeFailed() const; | ||
|
|
||
| TreelandConfig *globalConfig() const; | ||
| TreelandUserConfig *userConfig(const QString &userName); | ||
| SeatUserDConfig *seatUserConfig(const QString &userName); | ||
| OutputConfig *outputConfig(const QString &outputName); | ||
| AppConfig *appConfig(const QString &appId); | ||
|
|
||
| // Creates and caches the initial user's configs. Returns true only when both | ||
| // configs have already finished successfully; callers should listen for | ||
| // their initialization signals when this returns false. | ||
| bool initializeUserConfigs(const QString &userName); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 应该叫 setCurrentUser? 不过为啥要在这里做这样的封装,treeland.cpp 里直接使用 userConfig 获取,自己做当前config对象存储。 |
||
| TreelandUserConfig *initialUserConfig() const; | ||
|
|
||
| Q_SIGNALS: | ||
| void InitializeSucceed(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 信号首字母不要用大写 |
||
| void InitializeFailed(); | ||
|
Comment on lines
+41
to
+43
|
||
|
|
||
| private: | ||
| static SystemDConfigManager *s_instance; | ||
|
|
||
| TreelandConfig *m_globalConfig = nullptr; | ||
| QHash<QString, TreelandUserConfig *> m_userConfigs; | ||
| QHash<QString, SeatUserDConfig *> m_seatUserConfigs; | ||
| QHash<QString, OutputConfig *> m_outputConfigs; | ||
| QHash<QString, AppConfig *> m_appConfigs; | ||
| TreelandUserConfig *m_initialUserConfig = nullptr; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 成员变量改名为 currentUserConfig |
||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,11 +4,14 @@ | |
| #include "treeland.h" | ||
|
|
||
| #include "core/qmlengine.h" | ||
| #include "core/systemdconfigmanager.h" | ||
| #include "greeter/usermodel.h" | ||
| #include "interfaces/multitaskviewinterface.h" | ||
| #include "interfaces/plugininterface.h" | ||
| #include "seat/helper.h" | ||
| #include "seatuserconfig.hpp" | ||
| #include "session/session.h" | ||
| #include "treelanduserconfig.hpp" | ||
| #include "utils/cmdline.h" | ||
| #include "common/treelandlogging.h" | ||
| #include "common/constants.h" | ||
|
|
@@ -33,6 +36,7 @@ | |
| #include <QMetaMethod> | ||
| #include <QTranslator> | ||
|
|
||
| #include <functional> | ||
| #include <memory> | ||
| #include <pwd.h> | ||
| #include <sys/socket.h> | ||
|
|
@@ -56,7 +60,7 @@ class TreelandPrivate : public QObject | |
| { | ||
| } | ||
|
|
||
| void init() | ||
| void init(std::function<void()> onInitialized) | ||
| { | ||
| qmlEngine = new QmlEngine(this); | ||
| qmlEngine->addImportPath(QString("%1/qt/qml").arg(QCoreApplication::applicationDirPath())); | ||
|
|
@@ -70,23 +74,97 @@ class TreelandPrivate : public QObject | |
| // assert(wlroots: assert(wl_list_empty(&cur->events.button.listener_list))) | ||
| // failed during quit(If the quit call is from the cursor's button press/release event) | ||
| connect(qmlEngine, &QQmlEngine::quit, q, &Treeland::quit, Qt::QueuedConnection); | ||
| helper = qmlEngine->singletonInstance<Helper *>("Treeland", "Helper"); | ||
| connect(helper, &Helper::requestQuit, q, &Treeland::quit, Qt::QueuedConnection); | ||
|
|
||
| qputenv("WLR_XWAYLAND", QByteArray(LIBEXEC_DIR) + "/treeland-xwayland"); | ||
| helper->init(q); | ||
|
|
||
| #ifndef DISABLE_DDM | ||
| auto userModel = qmlEngine->singletonInstance<UserModel *>("Treeland", "UserModel"); | ||
| const QString initialUserName = userModel ? userModel->currentUserName() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. userModel 里要加一个 pendingUserXXXX 的方法,当这个用户对应的dconfig未reday时,它还不是currentUser,对于想要切换到的user,应该先为pending状态,对应的dconfig reday后才变成currentUser,避免依赖 UserModel::currentUserNameChanged 的地方认为用户切换完成误用了dconfig。
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. user对应的dconfig未完成初始化时,所有的也有代码逻辑能获取到的信息都应该是旧的,相当于没有进行user的切换。 |
||
| : QStringLiteral("dde"); | ||
| #else | ||
| const QString initialUserName = QStringLiteral("dde"); | ||
| #endif | ||
| auto initializeTreeland = [this, q, onInitialized = std::move(onInitialized) | ||
| #ifndef DISABLE_DDM | ||
| , userModel | ||
| #endif | ||
| ] { | ||
| helper = qmlEngine->singletonInstance<Helper *>("Treeland", "Helper"); | ||
| connect(helper, &Helper::requestQuit, q, &Treeland::quit, Qt::QueuedConnection); | ||
|
|
||
| auto updateUser = [this, userModel] { | ||
| auto user = userModel->currentUser(); | ||
| onCurrentChanged(user ? user->UID() : getuid()); | ||
| }; | ||
| qputenv("WLR_XWAYLAND", QByteArray(LIBEXEC_DIR) + "/treeland-xwayland"); | ||
| helper->init(q); | ||
|
|
||
| #ifndef DISABLE_DDM | ||
| auto updateUser = [this, userModel] { | ||
| auto user = userModel->currentUser(); | ||
| onCurrentChanged(user ? user->UID() : getuid()); | ||
| }; | ||
|
|
||
| connect(userModel, &UserModel::currentUserNameChanged, this, updateUser); | ||
| updateUser(); | ||
| connect(userModel, &UserModel::currentUserNameChanged, this, updateUser); | ||
| updateUser(); | ||
| #endif | ||
| onInitialized(); | ||
| }; | ||
|
|
||
| auto *configManager = SystemDConfigManager::instance(); | ||
| if (!configManager || configManager->initializeUserConfigs(initialUserName)) { | ||
| initializeTreeland(); | ||
| return; | ||
| } | ||
|
|
||
| auto *userConfig = configManager->initialUserConfig(); | ||
| auto *seatConfig = configManager->seatUserConfig(initialUserName); | ||
| auto initialized = std::make_shared<bool>(false); | ||
| auto initializeWhenReady = [initializeTreeland, | ||
| userConfig, | ||
| seatConfig, | ||
| initialized] { | ||
| if (*initialized) { | ||
| return; | ||
| } | ||
|
|
||
| const bool userSucceeded = userConfig && userConfig->isInitializeSucceeded(); | ||
| const bool seatSucceeded = seatConfig && seatConfig->isInitializeSucceeded(); | ||
| const bool userFinished = !userConfig || userSucceeded | ||
| || userConfig->isInitializeFailed(); | ||
| const bool seatFinished = !seatConfig || seatSucceeded | ||
| || seatConfig->isInitializeFailed(); | ||
| if (!userFinished || !seatFinished) { | ||
| return; | ||
| } | ||
|
|
||
| *initialized = true; | ||
| if (!userSucceeded || !seatSucceeded) { | ||
| qCWarning(lcTlCore) | ||
| << "Initial user DConfig initialization failed; Treeland will continue with generated defaults."; | ||
| } | ||
| initializeTreeland(); | ||
| }; | ||
|
|
||
| if (userConfig) { | ||
| connect(userConfig, | ||
| &TreelandUserConfig::configInitializeSucceed, | ||
| this, | ||
| initializeWhenReady, | ||
| Qt::SingleShotConnection); | ||
| connect(userConfig, | ||
| &TreelandUserConfig::configInitializeFailed, | ||
| this, | ||
| initializeWhenReady, | ||
| Qt::SingleShotConnection); | ||
| } | ||
| if (seatConfig) { | ||
| connect(seatConfig, | ||
| &SeatUserDConfig::configInitializeSucceed, | ||
| this, | ||
| initializeWhenReady, | ||
| Qt::SingleShotConnection); | ||
| connect(seatConfig, | ||
| &SeatUserDConfig::configInitializeFailed, | ||
| this, | ||
| initializeWhenReady, | ||
| Qt::SingleShotConnection); | ||
| } | ||
| initializeWhenReady(); | ||
| } | ||
|
|
||
| ~TreelandPrivate() | ||
|
|
@@ -311,7 +389,12 @@ Treeland::Treeland() | |
|
|
||
| qmlRegisterModule("Treeland.Protocols", 1, 0); | ||
|
|
||
| d->init(); | ||
| d->init([this] { initialize(); }); | ||
| } | ||
|
|
||
| void Treeland::initialize() | ||
| { | ||
| Q_D(Treeland); | ||
|
|
||
| auto globalSession = d->helper->sessionManager()->globalSession(); | ||
| Q_ASSERT(globalSession); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
直接叫 dconfigmanager 就行