Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ qt_add_qml_module(libtreeland
core/imcandidatepanelmanager.h
core/shellhandler.cpp
core/shellhandler.h
core/systemdconfigmanager.cpp
core/systemdconfigmanager.h
core/treeland.cpp
core/treeland.h
core/windowpicker.cpp
Expand Down
159 changes: 159 additions & 0 deletions src/core/systemdconfigmanager.cpp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

直接叫 dconfigmanager 就行

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"

Check warning on line 6 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "appconfig.hpp" not found.
#include "outputconfig.hpp"

Check warning on line 7 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "outputconfig.hpp" not found.
#include "seatuserconfig.hpp"

Check warning on line 8 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "seatuserconfig.hpp" not found.
#include "treelandconfig.hpp"

Check warning on line 9 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "treelandconfig.hpp" not found.
#include "treelanduserconfig.hpp"

Check warning on line 10 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "treelanduserconfig.hpp" not found.

#include <DConfig>

Check warning on line 12 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <DConfig> not found. Please note: Cppcheck does not need standard library headers to get proper results.

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(); },

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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)

Check warning on line 112 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'outputConfig' is never used.
{
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)

Check warning on line 147 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'initializeUserConfigs' is never used.
{
m_initialUserConfig = userConfig(userName);
const auto *seatConfig = seatUserConfig(userName);
return m_initialUserConfig && seatConfig
&& m_initialUserConfig->isInitializeSucceeded()
&& seatConfig->isInitializeSucceeded();
}

TreelandUserConfig *SystemDConfigManager::initialUserConfig() const

Check warning on line 156 in src/core/systemdconfigmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'initialUserConfig' is never used.
{
return m_initialUserConfig;
}
54 changes: 54 additions & 0 deletions src/core/systemdconfigmanager.h
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>

Check warning on line 6 in src/core/systemdconfigmanager.h

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QHash> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

应该叫 setCurrentUser?

不过为啥要在这里做这样的封装,treeland.cpp 里直接使用 userConfig 获取,自己做当前config对象存储。

TreelandUserConfig *initialUserConfig() const;

Q_SIGNALS:
void InitializeSucceed();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

成员变量改名为 currentUserConfig

};
109 changes: 96 additions & 13 deletions src/core/treeland.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -33,6 +36,7 @@
#include <QMetaMethod>
#include <QTranslator>

#include <functional>
#include <memory>
#include <pwd.h>
#include <sys/socket.h>
Expand All @@ -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()));
Expand All @@ -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()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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()
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/core/treeland.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public Q_SLOTS:
void XWaylandName();

private:
void initialize();
void quit();

std::unique_ptr<TreelandPrivate> d_ptr;
Expand Down
Loading
Loading