diff --git a/misc/dconfig/org.deepin.dde.treeland.user.json b/misc/dconfig/org.deepin.dde.treeland.user.json index 2dc0a7254..deb844093 100644 --- a/misc/dconfig/org.deepin.dde.treeland.user.json +++ b/misc/dconfig/org.deepin.dde.treeland.user.json @@ -178,6 +178,83 @@ "permissions": "readwrite", "visibility": "public" }, + "enableMinimizeAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable minimize animation", + "name[zh_CN]": "启用最小化动效", + "description": "Enable/disable minimize animation", + "description[zh_CN]": "启用或禁用最小化动效", + "permissions": "readwrite", + "visibility": "public" + }, + "enableMaximizeAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable maximize animation", + "name[zh_CN]": "启用最大化动效", + "description": "Enable/disable maximize animation", + "description[zh_CN]": "启用或禁用最大化动效", + "permissions": "readwrite", + "visibility": "public" + }, + "enableWindowOpenCloseAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable window open/close animation", + "name[zh_CN]": "启用窗口打开/关闭动效", + "description": "Enable/disable window appearance and closing animation", + "description[zh_CN]": "启用或禁用窗口打开和关闭时的动效", + "permissions": "readwrite", + "visibility": "public" + }, + "enableLayerShellAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable layer shell animation", + "name[zh_CN]": "启用面板动效", + "description": "Enable/disable layer shell surface animation (taskbar, panel, dock)", + "description[zh_CN]": "启用或禁用面板类表面的动效(任务栏、停靠栏等)", + "permissions": "readwrite", + "visibility": "public" + }, + "enableLaunchpadAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable launchpad animation", + "name[zh_CN]": "启用启动器动效", + "description": "Enable/disable launchpad show/hide animation", + "description[zh_CN]": "启用或禁用启动器显示和隐藏动效", + "permissions": "readwrite", + "visibility": "public" + }, + "enableShowDesktopAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable show desktop animation", + "name[zh_CN]": "启用显示桌面动效", + "description": "Enable/disable window fade animation when showing desktop", + "description[zh_CN]": "启用或禁用进入显示桌面时的窗口淡出动效", + "permissions": "readwrite", + "visibility": "public" + }, + "enableWorkspaceAnimation": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "Enable workspace switching animation", + "name[zh_CN]": "启用工作区切换动效", + "description": "Enable/disable workspace slide animation when switching", + "description[zh_CN]": "启用或禁用切换工作区时的滑动动效", + "permissions": "readwrite", + "visibility": "public" + }, "maxWorkspace": { "value": 6, "serial": 0, diff --git a/src/greeter/greeterproxy.cpp b/src/greeter/greeterproxy.cpp index 44915c9d2..4aca2cc9f 100644 --- a/src/greeter/greeterproxy.cpp +++ b/src/greeter/greeterproxy.cpp @@ -4,37 +4,30 @@ #include "greeterproxy.h" // Treeland +#include "common/treelandlogging.h" +#include "core/lockscreen.h" #include "greeter/sessionmodel.h" #include "greeter/usermodel.h" +#include "modules/ddm/ddminterfacev2.h" #include "seat/helper.h" #include "session/session.h" -#include "common/treelandlogging.h" -#include "core/lockscreen.h" // DDM #include #include #include -#include // Qt -#include -#include #include #include #include #include -#include #include #include -// Waylib -#include - // System #include #include -#include using namespace DDM; @@ -90,14 +83,6 @@ static inline SessionModel *sessionModel() GreeterProxy::GreeterProxy(QObject *parent) : QObject(parent) { - m_socket = new QLocalSocket(this); - - // connect signals - connect(m_socket, &QLocalSocket::connected, this, &GreeterProxy::connected); - connect(m_socket, &QLocalSocket::disconnected, this, &GreeterProxy::disconnected); - connect(m_socket, &QLocalSocket::readyRead, this, &GreeterProxy::readyRead); - connect(m_socket, &QLocalSocket::errorOccurred, this, &GreeterProxy::error); - auto conn = QDBusConnection::systemBus(); conn.connect(Logind::serviceName(), Logind::managerPath(), @@ -111,23 +96,27 @@ GreeterProxy::GreeterProxy(QObject *parent) "SessionRemoved", this, SLOT(onSessionRemoved(QString, QDBusObjectPath))); - conn.connect("org.deepin.DisplayManager", - "/org/deepin/DisplayManager", - "org.deepin.DisplayManager", - "AuthInfoChanged", - this, - SLOT(updateAuthSocket())); - - updateAuthSocket(); } GreeterProxy::~GreeterProxy() { } +void GreeterProxy::connectDDM(DDMInterfaceV2 *interface) +{ + m_ddmInterface = interface; + connect(interface, &DDMInterfaceV2::capabilities, this, &GreeterProxy::capabilities); + connect(interface, &DDMInterfaceV2::userLoggedIn, this, &GreeterProxy::userLoggedIn); + connect(interface, + &DDMInterfaceV2::authenticationFailed, + this, + &GreeterProxy::authenticationFailed); +} + //////////////////////// // Properties setters // //////////////////////// -void GreeterProxy::setShowShutdownView(bool show) { +void GreeterProxy::setShowShutdownView(bool show) +{ if (m_showShutdownView != show) { m_showShutdownView = show; Q_EMIT showShutdownViewChanged(show); @@ -159,89 +148,183 @@ void GreeterProxy::setLock(bool isLocked) void GreeterProxy::powerOff() { - SocketWriter(m_socket) << quint32(GreeterMessages::PowerOff); + if (m_ddmInterface && m_ddmInterface->isValid()) + m_ddmInterface->powerOff(); } void GreeterProxy::reboot() { - SocketWriter(m_socket) << quint32(GreeterMessages::Reboot); + if (m_ddmInterface && m_ddmInterface->isValid()) + m_ddmInterface->reboot(); } void GreeterProxy::suspend() { - SocketWriter(m_socket) << quint32(GreeterMessages::Suspend); + if (m_ddmInterface && m_ddmInterface->isValid()) + m_ddmInterface->suspend(); } void GreeterProxy::hibernate() { - SocketWriter(m_socket) << quint32(GreeterMessages::Hibernate); + if (m_ddmInterface && m_ddmInterface->isValid()) + m_ddmInterface->hibernate(); } void GreeterProxy::hybridSleep() { - SocketWriter(m_socket) << quint32(GreeterMessages::HybridSleep); + if (m_ddmInterface && m_ddmInterface->isValid()) + m_ddmInterface->hybridSleep(); } void GreeterProxy::login(const QString &user, const QString &password, const int sessionIndex) { - if (!m_socket->isValid()) { - qCDebug(treelandGreeter) << "Socket is not valid. Local password check."; + if (m_ddmInterface && m_ddmInterface->isValid()) { + // get model index + QModelIndex index = sessionModel()->index(sessionIndex, 0); + // send command to the daemon + DDM::Session::Type sessionType = static_cast( + sessionModel()->data(index, SessionModel::TypeRole).toInt()); + QString sessionFile = sessionModel()->data(index, SessionModel::FileRole).toString(); + qCInfo(treelandGreeter) << "Logging user" << user << "in with" << sessionType << "session" + << sessionFile; + m_ddmInterface->login(user, password, sessionType, sessionFile); + } else { + qCInfo(treelandGreeter) << "DDM is not valid. Local password check."; if (localValidation(user, password)) { setLock(false); } else { Q_EMIT failedAttemptsChanged(++m_failedAttempts); } - return; } - - // get model index - QModelIndex index = sessionModel()->index(sessionIndex, 0); - - // send command to the daemon - DDM::Session::Type type = - static_cast(sessionModel()->data(index, SessionModel::TypeRole).toInt()); - QString name = sessionModel()->data(index, SessionModel::FileRole).toString(); - qCInfo(treelandGreeter) << "Logging user" << user << "in with" << type << "session" << name; - DDM::Session session(type, name); - SocketWriter(m_socket) << quint32(GreeterMessages::Login) << user << password << session; } void GreeterProxy::unlock(const QString &user, const QString &password) { - if (!m_socket->isValid()) { - qCDebug(treelandGreeter) << "Socket is not valid. Local password check."; + if (m_ddmInterface && m_ddmInterface->isValid()) { + auto session = Helper::instance()->sessionManager()->sessionForUser(user); + if (session) { + qCInfo(treelandGreeter) << "Unlocking session" << session->id() << "for user" << user; + m_ddmInterface->unlock(session->id(), password); + } else { + qCWarning(treelandGreeter) << "Trying to unlock session for user" << user + << "but no session found."; + // [TODO] Further actions + } + } else { + qCInfo(treelandGreeter) << "DDM is not valid. Local password check."; if (localValidation(user, password)) { setLock(false); } else { Q_EMIT failedAttemptsChanged(++m_failedAttempts); } - return; - } - - auto userInfo = userModel()->get(user); - if (userInfo.isValid()) { - qCInfo(treelandGreeter) << "Unlocking user" << user; - SocketWriter(m_socket) << quint32(GreeterMessages::Unlock) << user << password; } } void GreeterProxy::logout() { - auto session = Helper::instance()->sessionManager()->activeSession().lock(); - qCInfo(treelandGreeter) << "Logging user" << session->username() << "out with session id" << session->id(); - SocketWriter(m_socket) << quint32(GreeterMessages::Logout) << session->id(); + if (m_ddmInterface && m_ddmInterface->isValid()) { + auto session = Helper::instance()->sessionManager()->activeSession().lock(); + if (session) { + qCInfo(treelandGreeter) << "Logging user" << session->username() << "out with session id" + << session->id(); + m_ddmInterface->logout(session->id()); + } else { + qCWarning(treelandGreeter) + << "Trying to logout when no active session, show lockscreen directly."; + setLock(true); + } + } else { + qCInfo(treelandGreeter) + << "Trying to logout when DDM is not available, show lockscreen directly."; + setLock(true); + } } void GreeterProxy::lock() { auto session = Helper::instance()->sessionManager()->activeSession().lock(); if (!session || session->username() == "dde") { - qCInfo(treelandGreeter) << "Trying to lock when no user session active, show lockscreen directly."; + qCInfo(treelandGreeter) + << "Trying to lock when no user session active, show lockscreen directly."; setLock(true); - return; + } else if (!m_ddmInterface || !m_ddmInterface->isValid()) { + qCInfo(treelandGreeter) + << "Trying to lock when DDM is not available, show lockscreen directly."; + setLock(true); + } else { + qCInfo(treelandGreeter) << "Locking user" << session->username() << "with session id" + << session->id(); + m_ddmInterface->lock(session->id()); + } +} + +////////////////////// +// Signals from DDM // +////////////////////// + +void GreeterProxy::capabilities(uint32_t capabilities) +{ + // parse capabilities + m_canPowerOff = capabilities & Capability::PowerOff; + m_canReboot = capabilities & Capability::Reboot; + m_canSuspend = capabilities & Capability::Suspend; + m_canHibernate = capabilities & Capability::Hibernate; + m_canHybridSleep = capabilities & Capability::HybridSleep; + + // Q_EMIT signals + Q_EMIT canPowerOffChanged(m_canPowerOff); + Q_EMIT canRebootChanged(m_canReboot); + Q_EMIT canSuspendChanged(m_canSuspend); + Q_EMIT canHibernateChanged(m_canHibernate); + Q_EMIT canHybridSleepChanged(m_canHybridSleep); +} + +void GreeterProxy::userLoggedIn(const QString &username, const QString &session) +{ + // This will happen after a crash recovery of treeland + qCInfo(treelandGreeter) << "User " << username << " is already logged in with session" + << session; + auto userPtr = userModel()->getUser(username); + if (userPtr) { + userModel()->updateUserLoginState(username, true); + Q_EMIT userModel()->userLoggedIn(username, session); + QThreadPool::globalInstance()->start([this, session] { + // Connect to Lock/Unlock signals + auto conn = QDBusConnection::systemBus(); + OrgFreedesktopLogin1ManagerInterface manager(Logind::serviceName(), + Logind::managerPath(), + conn); + auto reply = manager.GetSession(session); + reply.waitForFinished(); + if (!reply.isValid()) { + qCWarning(treelandGreeter) << "Failed to get session path for session" << session + << ", error:" << reply.error().message(); + return; + } + auto path = reply.value(); + conn.connect(Logind::serviceName(), + path.path(), + Logind::sessionIfaceName(), + "Lock", + this, + SLOT(onSessionLock())); + conn.connect(Logind::serviceName(), + path.path(), + Logind::sessionIfaceName(), + "Unlock", + this, + SLOT(onSessionUnlock())); + }); + } else { + qCWarning(treelandGreeter) << "User " << username << " logged in but not found"; } - qCInfo(treelandGreeter) << "Locking user" << session->username() << "with session id" << session->id(); - SocketWriter(m_socket) << quint32(GreeterMessages::Lock) << session->id(); +} + +void GreeterProxy::authenticationFailed(uint32_t error) +{ + qCDebug(treelandGreeter) << "Message received from DDM: Authentication Failed:" + << DDMInterfaceV2::authErrorToString(error); + Q_EMIT failedAttemptsChanged(++m_failedAttempts); } ////////////////////////////// @@ -274,7 +357,7 @@ void GreeterProxy::onSessionNew(const QString &id, [[maybe_unused]] const QDBusO qCInfo(treelandGreeter) << "New session added: id=" << id << ", user=" << user; userModel()->updateUserLoginState(user, true); // userLoggedIn signal is connected with Helper::updateActiveUserSession - Q_EMIT userModel()->userLoggedIn(user, id.toInt()); + Q_EMIT userModel()->userLoggedIn(user, id); // Connect to Lock/Unlock signals auto conn = QDBusConnection::systemBus(); @@ -317,7 +400,7 @@ void GreeterProxy::onSessionRemoved(const QString &id, [[maybe_unused]] const QD this, SLOT(onSessionUnlock())); - auto session = Helper::instance()->sessionManager()->sessionForId(id.toInt()); + auto session = Helper::instance()->sessionManager()->sessionForId(id); if (session) { QString username = session->username(); qCInfo(treelandGreeter) << "Session removed: id=" << id << ", user=" << username; @@ -340,7 +423,7 @@ void GreeterProxy::onSessionLock() OrgFreedesktopLogin1SessionInterface session("org.freedesktop.login1", path, QDBusConnection::systemBus()); - int id = session.id().toInt(); + QString id = session.id(); qCInfo(treelandGreeter) << "Lock signal received for session id:" << id; auto activeSession = Helper::instance()->sessionManager()->activeSession().lock(); if (!activeSession) @@ -363,7 +446,7 @@ void GreeterProxy::onSessionUnlock() OrgFreedesktopLogin1SessionInterface session("org.freedesktop.login1", path, QDBusConnection::systemBus()); - int id = session.id().toInt(); + QString id = session.id(); const QString username = session.name(); qCInfo(treelandGreeter) << "Unlock signal received for session id:" << id; auto activeSession = Helper::instance()->sessionManager()->activeSession().lock(); @@ -374,7 +457,12 @@ void GreeterProxy::onSessionUnlock() qCWarning(treelandGreeter) << "Unlock signal received for non-active session id:" << id << ", lock it back."; QMetaObject::invokeMethod(this, [this, id] { - SocketWriter(m_socket) << quint32(GreeterMessages::Lock) << QString::number(id); + if (m_ddmInterface && m_ddmInterface->isValid()) { + m_ddmInterface->lock(id); + } else { + qCInfo(treelandGreeter) << "Trying to lock when DDM is not available, show lockscreen directly." << id; + setLock(true); + } }); } else { QMetaObject::invokeMethod(this, [this] { @@ -383,180 +471,3 @@ void GreeterProxy::onSessionUnlock() } }); } - -/////////////////////// -// DDM Communication // -/////////////////////// - -bool GreeterProxy::isConnected() const -{ - return m_socket->state() == QLocalSocket::ConnectedState; -} - -void GreeterProxy::connected() -{ - qCInfo(treelandGreeter) << "Connected to the ddm"; - - SocketWriter(m_socket) - << quint32(GreeterMessages::Connect) - << Helper::instance()->sessionManager()->globalSession()->socket()->fullServerName(); -} - -void GreeterProxy::disconnected() -{ - qCWarning(treelandGreeter) << "Disconnected from the ddm"; - - Q_EMIT socketDisconnected(); -} - -void GreeterProxy::error() -{ - qCCritical(treelandGreeter) << "Socket error: " << m_socket->errorString(); -} - -void GreeterProxy::readyRead() -{ - // input stream - QDataStream input(m_socket); - - while (input.device()->bytesAvailable()) { - // read message - quint32 message; - input >> message; - - switch (DaemonMessages(message)) { - case DaemonMessages::Capabilities: { - // log message - qCDebug(treelandGreeter) << "Message received from daemon: Capabilities"; - - // read capabilities - quint32 capabilities; - input >> capabilities; - - // parse capabilities - m_canPowerOff = capabilities & Capability::PowerOff; - m_canReboot = capabilities & Capability::Reboot; - m_canSuspend = capabilities & Capability::Suspend; - m_canHibernate = capabilities & Capability::Hibernate; - m_canHybridSleep = capabilities & Capability::HybridSleep; - - // Q_EMIT signals - Q_EMIT canPowerOffChanged(m_canPowerOff); - Q_EMIT canRebootChanged(m_canReboot); - Q_EMIT canSuspendChanged(m_canSuspend); - Q_EMIT canHibernateChanged(m_canHibernate); - Q_EMIT canHybridSleepChanged(m_canHybridSleep); - } break; - case DaemonMessages::HostName: { - qCDebug(treelandGreeter) << "Message received from daemon: HostName"; - - // read host name - input >> m_hostName; - - // Q_EMIT signal - Q_EMIT hostNameChanged(m_hostName); - } break; - case DaemonMessages::LoginFailed: { - QString user; - input >> user; - - qCDebug(treelandGreeter) << "Message received from daemon: LoginFailed" << user; - - Q_EMIT failedAttemptsChanged(++m_failedAttempts); - } break; - case DaemonMessages::InformationMessage: { - QString message; - input >> message; - - qCDebug(treelandGreeter) << "Information Message received from daemon: " << message; - Q_EMIT informationMessage(message); - } break; - case DaemonMessages::SwitchToGreeter: { - qCInfo(treelandGreeter) << "switch to greeter"; - lock(); - } break; - case DaemonMessages::UserActivateMessage: { - QString user; - int sessionId; - input >> user >> sessionId; - - // NOTE: maybe DDM will active dde user. - if (!userModel()->getUser(user)) { - qCInfo(treelandGreeter) << "activate user, but switch to greeter"; - lock(); - break; - } - - userModel()->setCurrentUserName(user); - - qCInfo(treelandGreeter) << "activate successfully: " << user << ", XDG_SESSION_ID: " << sessionId; - } break; - case DaemonMessages::UserLoggedIn: { - QString user; - int sessionId; - input >> user >> sessionId; - - // This will happen after a crash recovery of treeland - qCInfo(treelandGreeter) << "User " << user << " is already logged in"; - auto userPtr = userModel()->getUser(user); - if (userPtr) { - userModel()->updateUserLoginState(user, true); - Q_EMIT userModel()->userLoggedIn(user, sessionId); - QThreadPool::globalInstance()->start([this, sessionId] { - // Connect to Lock/Unlock signals - auto conn = QDBusConnection::systemBus(); - OrgFreedesktopLogin1ManagerInterface manager("org.freedesktop.login1", - Logind::managerPath(), - conn); - auto reply = manager.GetSession(QString::number(sessionId)); - reply.waitForFinished(); - if (!reply.isValid()) { - qCWarning(treelandGreeter) << "Failed to get session path for session id:" << sessionId << ", error:" << reply.error().message(); - return; - } - auto path = reply.value(); - conn.connect(Logind::serviceName(), - path.path(), - Logind::sessionIfaceName(), - "Lock", - this, - SLOT(onSessionLock())); - conn.connect(Logind::serviceName(), - path.path(), - Logind::sessionIfaceName(), - "Unlock", - this, - SLOT(onSessionUnlock())); - }); - } else { - qCWarning(treelandGreeter) << "User " << user << " logged in but not found"; - } - } break; - default: { - qCWarning(treelandGreeter) << "Unknown message received from daemon." << message; - } - } - } -} - -void GreeterProxy::updateAuthSocket() -{ - QThreadPool::globalInstance()->start([this]() { - QDBusInterface manager("org.deepin.DisplayManager", - "/org/deepin/DisplayManager", - "org.deepin.DisplayManager", - QDBusConnection::systemBus()); - QDBusReply reply = manager.call("AuthInfo"); - if (!reply.isValid()) { - qCWarning(treelandGreeter) << "Failed to get auth info from display manager:" << reply.error().message(); - return; - } - const QString &socket = reply.value(); - QMetaObject::invokeMethod(this, [this, socket] { - if (m_socket->state() == QLocalSocket::ConnectedState) - m_socket->disconnectFromServer(); - - m_socket->connectToServer(socket); - }); - }); -} diff --git a/src/greeter/greeterproxy.h b/src/greeter/greeterproxy.h index e628e0a51..95762abc1 100644 --- a/src/greeter/greeterproxy.h +++ b/src/greeter/greeterproxy.h @@ -10,6 +10,7 @@ class QLocalSocket; +class DDMInterfaceV2; class LockScreen; class GreeterProxy @@ -43,6 +44,8 @@ class GreeterProxy explicit GreeterProxy(QObject *parent = nullptr); ~GreeterProxy(); + void connectDDM(DDMInterfaceV2 *interface); + ////////////////////// // Property getters // ////////////////////// @@ -93,7 +96,9 @@ class GreeterProxy /** * @brief Get the number of failed login attempts (password incorrect) + * * The value is reset to 0 when unlocked successfully + * * QML elements should listen to this property to detect failed login/unlock attempts * * @return Number of failed attempts @@ -102,6 +107,7 @@ class GreeterProxy /** * @brief Get whether the shutdown view is shown + * * QML elements should listen to this property to show/hide the shutdown view * * @return true if shutdown view is shown @@ -110,6 +116,7 @@ class GreeterProxy /** * @brief Get whether to show animation on lock/unlock + * * QML elements should listen to this property to enable/disable animation * * @return true if show animation @@ -118,6 +125,7 @@ class GreeterProxy /** * @brief Get whether there is an active user session + * * QML elements should listen to this property to show/hide session related UI * * @return true if has active session @@ -130,6 +138,7 @@ class GreeterProxy /** * @brief Set whether to show the shutdown view + * * QML elements should set this property to show/hide the shutdown view * * @param show true to show shutdown view, false to hide @@ -140,14 +149,9 @@ class GreeterProxy // Public methods // //////////////////// - /** - * @brief Check if the DDM socket is connected - * @return true if connected - */ - bool isConnected() const; - /** * @brief Set the LockScreen instance + * * This is necessary for the GreeterProxy to control the lock screen visibility * * @param lockScreen LockScreen instance @@ -176,6 +180,7 @@ public Q_SLOTS: void hybridSleep(); /** @brief Login given user with given password for given desktop session. + * * This function will call DDM to perform the login. * * Listen to org.freedesktop.login1.Manager.SessionNew signal to @@ -189,6 +194,7 @@ public Q_SLOTS: void login(const QString &user, const QString &password, int sessionIndex); /** @brief Lock the current active session. + * * This function will call DDM to perform the lock. * * Listen to org.freedesktop.login1.Session.Lock signal to detect @@ -197,6 +203,7 @@ public Q_SLOTS: void lock(); /** @brief Unlock given user with given password. + * * This function will call DDM to perform the unlock. * * Listen to org.freedesktop.login1.Session.Unlock signal to @@ -209,6 +216,7 @@ public Q_SLOTS: void unlock(const QString &user, const QString &password); /** @brief Logout the current active session. + * * This function will call DDM to perform the logout. * * Listen to org.freedesktop.login1.Manager.SessionRemoved signal to @@ -218,14 +226,13 @@ public Q_SLOTS: private Q_SLOTS: - /////////////////////// - // DDM Communication // - /////////////////////// + ////////////////////// + // Signals from DDM // + ////////////////////// - void connected(); - void disconnected(); - void readyRead(); - void error(); + void capabilities(uint32_t capabilities); + void userLoggedIn(const QString &username, const QString &session); + void authenticationFailed(uint32_t error); ////////////////////////////// // Logind session listeners // @@ -244,8 +251,6 @@ private Q_SLOTS: void onSessionUnlock(); Q_SIGNALS: - void informationMessage(const QString &message); - void switchUser(); void socketDisconnected(); @@ -295,6 +300,7 @@ private Q_SLOTS: /** * @brief Set the lock state + * * This is the internal method to set the lock state (lockscreen * visibility, etc.) directly without calling DDM and * communicating with systemd-logind. @@ -303,16 +309,11 @@ private Q_SLOTS: */ void setLock(bool isLocked); - /** - * @brief Update the DDM communication socket - */ - void updateAuthSocket(); - ///////////////////// // Property values // ///////////////////// - QLocalSocket *m_socket{ nullptr }; + DDMInterfaceV2 *m_ddmInterface{ nullptr }; LockScreen *m_lockScreen{ nullptr }; QString m_hostName{}; diff --git a/src/greeter/usermodel.h b/src/greeter/usermodel.h index 3ab250bed..ec682f329 100644 --- a/src/greeter/usermodel.h +++ b/src/greeter/usermodel.h @@ -85,7 +85,7 @@ class UserModel : public QAbstractListModel void currentUserNameChanged(); void updateTranslations(const QLocale &locale); void countChanged(); - void userLoggedIn(const QString &username, int sessionId); + void userLoggedIn(const QString &username, const QString &session); private Q_SLOTS: void onUserAdded(quint64 uid); diff --git a/src/modules/ddm/CMakeLists.txt b/src/modules/ddm/CMakeLists.txt index d1f10ae16..38c3fa6bd 100644 --- a/src/modules/ddm/CMakeLists.txt +++ b/src/modules/ddm/CMakeLists.txt @@ -1,14 +1,14 @@ find_package(TreelandProtocols REQUIRED) -ws_generate_local(server ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-ddm-v1.xml treeland-ddm-v1-protocol) +ws_generate_local(server ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-ddm-v2.xml treeland-ddm-v2-protocol) impl_treeland( NAME module_ddm SOURCE - ${CMAKE_SOURCE_DIR}/src/modules/ddm/ddminterfacev1.h - ${CMAKE_SOURCE_DIR}/src/modules/ddm/ddminterfacev1.cpp - ${WAYLAND_PROTOCOLS_OUTPUTDIR}/treeland-ddm-v1-protocol.c + ${CMAKE_SOURCE_DIR}/src/modules/ddm/ddminterfacev2.h + ${CMAKE_SOURCE_DIR}/src/modules/ddm/ddminterfacev2.cpp + ${WAYLAND_PROTOCOLS_OUTPUTDIR}/treeland-ddm-v2-protocol.c INCLUDE $ ) diff --git a/src/modules/ddm/ddminterfacev1.cpp b/src/modules/ddm/ddminterfacev1.cpp deleted file mode 100644 index 327fdf05b..000000000 --- a/src/modules/ddm/ddminterfacev1.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) 2025 April Lu . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "ddminterfacev1.h" -#include "treeland-ddm-v1-protocol.h" -#include "common/treelandlogging.h" -#include "helper.h" -#include "usermodel.h" - -#include -#include -#include -#include - -struct treeland_ddm { - wl_resource *resource; -}; - -// request implementation - -static void switchToGreeter([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) { - Helper::instance()->showLockScreen(false); -} - -static void switchToUser([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource, const char *username) { - auto user = QString::fromLocal8Bit(username); - auto helper = Helper::instance(); - if (user == "ddm") { - helper->showLockScreen(false); - } else if (user != helper->userModel()->currentUserName()) { - helper->userModel()->setCurrentUserName(QString(username)); - helper->showLockScreen(false); - } -} - -static void activateSession([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) { - Helper::instance()->activateSession(); -} - -static void deactivateSession([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) { - Helper::instance()->deactivateSession(); -} - -static void enableRender([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) { - Helper::instance()->enableRender(); -} - -static void disableRender(struct wl_client *client, [[maybe_unused]] struct wl_resource *resource, uint32_t id) { - Helper::instance()->disableRender(); - auto callback = wl_resource_create(client, &wl_callback_interface, 1, id); - auto serial = wl_display_get_serial(wl_client_get_display(client)); - wl_callback_send_done(callback, serial); - wl_resource_destroy(callback); -} - -static const struct treeland_ddm_v1_interface treeland_ddm_impl { - .switch_to_greeter = switchToGreeter, - .switch_to_user = switchToUser, - .activate_session = activateSession, - .deactivate_session = deactivateSession, - .enable_render = enableRender, - .disable_render = disableRender, -}; - -// wayland object binding - -static void handleResourceDestroy(struct wl_resource *resource) { - qCWarning(treelandCore) << "DDM connection lost"; - auto ddm = static_cast(wl_resource_get_user_data(resource)); - ddm->resource = nullptr; -} - -void handleBindingGlobal(struct wl_client *client, void *data, uint32_t version, uint32_t id) { - auto ddm = static_cast(data); - auto *resource = wl_resource_create(client, &treeland_ddm_v1_interface, version, id); - wl_resource_set_implementation(resource, &treeland_ddm_impl, ddm, handleResourceDestroy); - ddm->resource = resource; - qCDebug(treelandCore) << "DDM connection established"; - - treeland_ddm_v1_send_acquire_vt(resource, 0); -} - -// DDMInterfaceV1 - -DDMInterfaceV1::DDMInterfaceV1() { - -} - -DDMInterfaceV1::~DDMInterfaceV1() { -} - -QByteArrayView DDMInterfaceV1::interfaceName() const { - static const QByteArray arr(treeland_ddm_v1_interface.name); - return QByteArrayView(arr); -} - -bool DDMInterfaceV1::isConnected() const { - auto ddm = static_cast(m_handle); - return ddm && ddm->resource; -} - -void DDMInterfaceV1::create(WServer *server) { - auto ddm = new treeland_ddm { .resource = nullptr }; - m_handle = ddm; - m_global = wl_global_create(server->handle()->handle(), &treeland_ddm_v1_interface, - treeland_ddm_v1_interface.version, ddm, handleBindingGlobal); -} - -void DDMInterfaceV1::destroy([[maybe_unused]] WServer *server) { - wl_global_destroy(m_global); - auto ddm = static_cast(m_handle); - delete ddm; - m_handle = nullptr; -} - -wl_global *DDMInterfaceV1::global() const { - return m_global; -} - -// Event wrapper - -void DDMInterfaceV1::switchToVt(const int vtnr) { - auto ddm = static_cast(m_handle); - if (isConnected()) - treeland_ddm_v1_send_switch_to_vt(ddm->resource, vtnr); - else - qCWarning(treelandCore) << "DDM is not connected when trying to call switchToVt"; -} - -void DDMInterfaceV1::acquireVt(const int vtnr) { - auto ddm = static_cast(m_handle); - if (isConnected()) - treeland_ddm_v1_send_acquire_vt(ddm->resource, vtnr); - else - qCWarning(treelandCore) << "DDM is not connected when trying to call acquireVt"; -} diff --git a/src/modules/ddm/ddminterfacev1.h b/src/modules/ddm/ddminterfacev1.h deleted file mode 100644 index 5bd796911..000000000 --- a/src/modules/ddm/ddminterfacev1.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2025 April Lu . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "wserver.h" - -/** - * The server-side wrapper for treeland private protocol. - */ -class DDMInterfaceV1 : public Waylib::Server::WServerInterface { -public: - DDMInterfaceV1(); - ~DDMInterfaceV1() override; - QByteArrayView interfaceName() const override; - bool isConnected() const; - void switchToVt(const int vtnr); - void acquireVt(const int vtnr); -protected: - void create(Waylib::Server::WServer *server) override; - void destroy(Waylib::Server::WServer *server) override; - wl_global *global() const override; -private: - struct wl_global *m_global { nullptr }; -}; diff --git a/src/modules/ddm/ddminterfacev2.cpp b/src/modules/ddm/ddminterfacev2.cpp new file mode 100644 index 000000000..95ef2cf97 --- /dev/null +++ b/src/modules/ddm/ddminterfacev2.cpp @@ -0,0 +1,314 @@ +// 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 "ddminterfacev2.h" + +#include "common/treelandlogging.h" +#include "helper.h" +#include "treeland-ddm-v2-protocol.h" +#include "usermodel.h" + +#include +#include +#include + +#include + +///////////////////////////// +// Request Implementations // +///////////////////////////// + +// Sync + +static void capabilities([[maybe_unused]] struct wl_client *client, + struct wl_resource *resource, + uint32_t capabilities) +{ + auto interface = static_cast(wl_resource_get_user_data(resource)); + Q_EMIT interface->capabilities(capabilities); +} + +static void userLoggedIn([[maybe_unused]] struct wl_client *client, + struct wl_resource *resource, + const char *username, + const char *session) +{ + auto interface = static_cast(wl_resource_get_user_data(resource)); + Q_EMIT interface->userLoggedIn(QString::fromLocal8Bit(username), QString::fromLocal8Bit(session)); +} + +// Authentication + +static void authenticationFailed([[maybe_unused]] struct wl_client *client, + struct wl_resource *resource, + uint32_t error) +{ + auto interface = static_cast(wl_resource_get_user_data(resource)); + Q_EMIT interface->authenticationFailed(error); +} + +// Greeter + +static void switchToGreeter([[maybe_unused]] struct wl_client *client, + [[maybe_unused]] struct wl_resource *resource) +{ + Helper::instance()->showLockScreen(false); +} + +static void switchToUser([[maybe_unused]] struct wl_client *client, + [[maybe_unused]] struct wl_resource *resource, + const char *username) +{ + auto user = QString::fromLocal8Bit(username); + auto helper = Helper::instance(); + if (user == "dde") { + helper->showLockScreen(false); + } else if (user != helper->userModel()->currentUserName()) { + helper->userModel()->setCurrentUserName(user); + helper->showLockScreen(false); + } +} + +// DRM Control + +static void activateSession([[maybe_unused]] struct wl_client *client, + [[maybe_unused]] struct wl_resource *resource) +{ + Helper::instance()->activateSession(); +} + +static void deactivateSession([[maybe_unused]] struct wl_client *client, + [[maybe_unused]] struct wl_resource *resource) +{ + Helper::instance()->deactivateSession(); +} + +static void enableRender([[maybe_unused]] struct wl_client *client, + [[maybe_unused]] struct wl_resource *resource) +{ + Helper::instance()->enableRender(); +} + +static void disableRender(struct wl_client *client, + [[maybe_unused]] struct wl_resource *resource, + uint32_t id) +{ + Helper::instance()->disableRender(); + auto callback = wl_resource_create(client, &wl_callback_interface, 1, id); + auto serial = wl_display_get_serial(wl_client_get_display(client)); + wl_callback_send_done(callback, serial); + wl_resource_destroy(callback); +} + +//////////////////////////// +// Wayland Object Binding // +//////////////////////////// + +static const struct treeland_ddm_v2_interface treeland_ddm_v2_impl{ + .capabilities = capabilities, + .user_logged_in = userLoggedIn, + .authentication_failed = authenticationFailed, + .switch_to_greeter = switchToGreeter, + .switch_to_user = switchToUser, + .activate_session = activateSession, + .deactivate_session = deactivateSession, + .enable_render = enableRender, + .disable_render = disableRender, +}; + +static void handleResourceDestroy(struct wl_resource *resource) +{ + qCWarning(treelandCore) << "DDM connection lost"; + auto interface = static_cast(wl_resource_get_user_data(resource)); + interface->setHandle(nullptr); + Q_EMIT interface->disconnected(); +} + +static void handleBindingGlobal(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + auto interface = static_cast(data); + auto *resource = wl_resource_create(client, &treeland_ddm_v2_interface, version, id); + wl_resource_set_user_data(resource, interface); + wl_resource_set_implementation(resource, &treeland_ddm_v2_impl, interface, handleResourceDestroy); + interface->setHandle(resource); + qCDebug(treelandCore) << "DDM connection established"; + Q_EMIT interface->connected(); +} + +///////////// +// Methods // +///////////// + +QByteArrayView DDMInterfaceV2::interfaceName() const +{ + return treeland_ddm_v2_interface.name; +} + +void DDMInterfaceV2::setHandle(struct wl_resource *handle) +{ + m_handle = handle; +} + +QString DDMInterfaceV2::authErrorToString(uint32_t error) +{ + switch (error) { + case TREELAND_DDM_V2_AUTH_ERROR_AUTHENTICATION_FAILED: + return "Authentication failed"; + case TREELAND_DDM_V2_AUTH_ERROR_INVALID_USER: + return "Invalid user"; + case TREELAND_DDM_V2_AUTH_ERROR_INVALID_SESSION: + return "Invalid session"; + case TREELAND_DDM_V2_AUTH_ERROR_EXISTING_AUTHENTICATION_ONGOING: + return "Existing authentication ongoing"; + case TREELAND_DDM_V2_AUTH_ERROR_INTERNAL_ERROR: + return "Internal error"; + default: + return QString("Unknown error: %1").arg(error); + } +} + +void DDMInterfaceV2::create(WServer *server) +{ + m_global = wl_global_create(server->handle()->handle(), + &treeland_ddm_v2_interface, + treeland_ddm_v2_interface.version, + this, + handleBindingGlobal); +} + +void DDMInterfaceV2::destroy([[maybe_unused]] WServer *server) +{ + if (m_handle) { + wl_resource_destroy(static_cast(m_handle)); + m_handle = nullptr; + } + if (m_global) { + wl_global_destroy(m_global); + m_global = nullptr; + } +} + +wl_global *DDMInterfaceV2::global() const +{ + return m_global; +} + +//////////////////// +// Event Wrappers // +//////////////////// + +// Session Management + +void DDMInterfaceV2::login(const QString &username, + const QString &password, + DDM::Session::Type sessionType, + const QString &sessionFile) const +{ + if (isValid()) { + treeland_ddm_v2_send_login(static_cast(m_handle), + qPrintable(username), + qPrintable(password), + sessionType, + qPrintable(sessionFile)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call login"; + } +} + +void DDMInterfaceV2::logout(const QString &session) const +{ + if (isValid()) { + treeland_ddm_v2_send_logout(static_cast(m_handle), + qPrintable(session)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call logout"; + } +} + +void DDMInterfaceV2::lock(const QString &session) const +{ + if (isValid()) { + treeland_ddm_v2_send_lock(static_cast(m_handle), qPrintable(session)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call lock"; + } +} + +void DDMInterfaceV2::unlock(const QString &session, const QString &password) const +{ + if (isValid()) { + treeland_ddm_v2_send_unlock(static_cast(m_handle), + qPrintable(session), + qPrintable(password)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call unlock"; + } +} + +// Power Management + +void DDMInterfaceV2::powerOff() const +{ + if (isValid()) { + treeland_ddm_v2_send_poweroff(static_cast(m_handle)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call powerOff"; + } +} + +void DDMInterfaceV2::reboot() const +{ + if (isValid()) { + treeland_ddm_v2_send_reboot(static_cast(m_handle)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call reboot"; + } +} + +void DDMInterfaceV2::suspend() const +{ + if (isValid()) { + treeland_ddm_v2_send_suspend(static_cast(m_handle)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call suspend"; + } +} + +void DDMInterfaceV2::hibernate() const +{ + if (isValid()) { + treeland_ddm_v2_send_hibernate(static_cast(m_handle)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call hibernate"; + } +} + +void DDMInterfaceV2::hybridSleep() const +{ + if (isValid()) { + treeland_ddm_v2_send_hybrid_sleep(static_cast(m_handle)); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call hybridSleep"; + } +} + +// DRM Control + +void DDMInterfaceV2::switchToVt(int vtnr) const +{ + if (isValid()) { + treeland_ddm_v2_send_switch_to_vt(static_cast(m_handle), vtnr); + wl_display_flush_clients(wl_global_get_display(m_global)); + } else { + qCWarning(treelandCore) << "DDM is not connected when trying to call switchToVt"; + } +} diff --git a/src/modules/ddm/ddminterfacev2.h b/src/modules/ddm/ddminterfacev2.h new file mode 100644 index 000000000..ca6d06269 --- /dev/null +++ b/src/modules/ddm/ddminterfacev2.h @@ -0,0 +1,59 @@ +// 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 "wserver.h" + +#include + +/** + * Server-side wrapper for treeland-ddm protocol. + */ +class DDMInterfaceV2 : public QObject, public Waylib::Server::WServerInterface +{ + Q_OBJECT +public: + QByteArrayView interfaceName() const override; + void setHandle(struct wl_resource *handle); + static QString authErrorToString(uint32_t error); + + //////////////////// + // Event Wrappers // + //////////////////// + +public Q_SLOTS: + void login(const QString &username, + const QString &password, + DDM::Session::Type sessionType, + const QString &sessionFile) const; + void logout(const QString &session) const; + void lock(const QString &session) const; + void unlock(const QString &session, const QString &password) const; + void powerOff() const; + void reboot() const; + void suspend() const; + void hibernate() const; + void hybridSleep() const; + void switchToVt(int vtnr) const; + +Q_SIGNALS: + void connected(); + void disconnected(); + + /////////////////////////// + // Signals from Requests // + /////////////////////////// + + void capabilities(uint32_t capabilities); + void userLoggedIn(const QString &username, const QString &session); + void authenticationFailed(uint32_t error); + +protected: + void create(Waylib::Server::WServer *server) override; + void destroy(Waylib::Server::WServer *server) override; + wl_global *global() const override; + +private: + struct wl_global *m_global{ nullptr }; +}; diff --git a/src/seat/helper.cpp b/src/seat/helper.cpp index 8e5cc8a3c..30d5f7429 100644 --- a/src/seat/helper.cpp +++ b/src/seat/helper.cpp @@ -32,7 +32,7 @@ #include "modules/capture/capture.h" #include "modules/dde-shell/ddeshellattached.h" #include "modules/dde-shell/ddeshellmanagerinterfacev1.h" -#include "modules/ddm/ddminterfacev1.h" +#include "modules/ddm/ddminterfacev2.h" #include "modules/keystate/keystate.h" #include "modules/output-manager/outputmanagement.h" #include "modules/personalization/personalizationmanager.h" @@ -1237,6 +1237,9 @@ void Helper::init(Treeland::Treeland *treeland) m_userModel = engine->singletonInstance("Treeland", "UserModel"); m_sessionModel = engine->singletonInstance("Treeland", "SessionModel"); + m_ddmInterfaceV2 = m_server->attach(); + m_greeterProxy->connectDDM(m_ddmInterfaceV2); + engine->setContextForObject(m_renderWindow, engine->rootContext()); engine->setContextForObject(m_renderWindow->contentItem(), engine->rootContext()); m_rootSurfaceContainer->setQmlEngine(engine); @@ -1245,8 +1248,6 @@ void Helper::init(Treeland::Treeland *treeland) m_backend = m_server->attach(); m_seatManager = new SeatsManager(m_server, this); - m_ddmInterfaceV1 = m_server->attach(); - m_outputManager = m_server->attach(); connect(m_backend, &WBackend::outputAdded, this, &Helper::onOutputAdded); connect(m_backend, &WBackend::outputRemoved, this, &Helper::onOutputRemoved); @@ -1504,7 +1505,7 @@ void Helper::init(Treeland::Treeland *treeland) xdgOutputManager->setFilter([](WClient *client) { return !isXWaylandClient(client); }); xwaylandOutputManager->setFilter([](WClient *client) { return isXWaylandClient(client); }); // User dde does not has a real Logind session, so just pass 0 as id - m_sessionManager->updateActiveUserSession(QStringLiteral("dde"), 0); + m_sessionManager->updateActiveUserSession(QStringLiteral("dde"), {}); connect(m_userModel, &UserModel::userLoggedIn, m_sessionManager, &SessionManager::updateActiveUserSession); m_xdgDecorationManager = m_server->attach(); connect(m_xdgDecorationManager, @@ -1784,8 +1785,8 @@ bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *targetWindow, QInputEvent // Check if the backend is active to avoid this. if (key >= Qt::Key_F1 && key <= Qt::Key_F12 && m_backend->isSessionActive()) { const int vtnr = key - Qt::Key_F1 + 1; - if (m_ddmInterfaceV1 && m_ddmInterfaceV1->isConnected()) { - m_ddmInterfaceV1->switchToVt(vtnr); + if (m_ddmInterfaceV2 && m_ddmInterfaceV2->isValid()) { + m_ddmInterfaceV2->switchToVt(vtnr); } else { qCDebug(treelandCore) << "DDM is not connected"; showLockScreen(false); @@ -2660,8 +2661,8 @@ void Helper::onPrepareForSleep(bool sleep) } } -DDMInterfaceV1 *Helper::ddmInterfaceV1() const { - return m_ddmInterfaceV1; +DDMInterfaceV2 *Helper::ddmInterfaceV2() const { + return m_ddmInterfaceV2; } void Helper::activateSession() { diff --git a/src/seat/helper.h b/src/seat/helper.h index ec93b865f..f82b317ea 100644 --- a/src/seat/helper.h +++ b/src/seat/helper.h @@ -96,7 +96,7 @@ QW_USE_NAMESPACE class CaptureSourceSelector; class DDEShellManagerInterfaceV1; -class DDMInterfaceV1; +class DDMInterfaceV2; class ForeignToplevelV1; class FpsDisplayManager; class GreeterProxy; @@ -236,7 +236,7 @@ class Helper : public WSeatEventFilter inline UserModel *userModel() const { return m_userModel; }; inline SessionModel *sessionModel() const { return m_sessionModel; }; - DDMInterfaceV1 *ddmInterfaceV1() const; + DDMInterfaceV2 *ddmInterfaceV2() const; void activateSession(); void deactivateSession(); @@ -399,7 +399,7 @@ private Q_SLOTS: PrelaunchSplash *m_prelaunchSplash = nullptr; // treeland prelaunch splash protocol VirtualOutputV1 *m_virtualOutput = nullptr; OutputManagerV1 *m_outputManagerV1 = nullptr; - DDMInterfaceV1 *m_ddmInterfaceV1 = nullptr; + DDMInterfaceV2 *m_ddmInterfaceV2 = nullptr; ScreensaverInterfaceV1 *m_screensaverInterfaceV1 = nullptr; TreelandWallpaperManagerInterfaceV1 *m_wallpaperManagerInterfaceV1 = nullptr; TreelandWallpaperNotifierInterfaceV1 *m_wallpaperNotifierInterfaceV1 = nullptr; diff --git a/src/session/session.cpp b/src/session/session.cpp index 2553760c1..01142fbf4 100644 --- a/src/session/session.cpp +++ b/src/session/session.cpp @@ -62,7 +62,7 @@ Session::~Session() } } -int Session::id() const +QString Session::id() const { return m_id; } @@ -192,7 +192,7 @@ void SessionManager::removeSession(std::shared_ptr session) * @param username Username to ensure session for * @returns Session for the given username, or nullptr on failure */ -std::shared_ptr SessionManager::ensureSession(int id, QString username) +std::shared_ptr SessionManager::ensureSession(QString id, QString username) { // Helper lambda to create WSocket and WXWayland auto createWSocket = [this]() { @@ -324,7 +324,7 @@ std::shared_ptr SessionManager::ensureSession(int id, QString username) * @param id Session ID to find session for * @returns Session for the given id, or nullptr if not found */ -std::shared_ptr SessionManager::sessionForId(int id) const +std::shared_ptr SessionManager::sessionForId(const QString &id) const { for (auto session : m_sessions) { if (session && session->m_id == id) @@ -404,8 +404,9 @@ bool SessionManager::isDDEUserClient(WClient *client) * active session changed. * * @param username Username to set as active session + * @param session Logind session ID to set as active session */ -void SessionManager::updateActiveUserSession(const QString &username, int id) +void SessionManager::updateActiveUserSession(const QString &username, const QString &id) { // Get previous active session auto previous = m_activeSession.lock(); diff --git a/src/session/session.h b/src/session/session.h index 25331aae2..797bf86e9 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -22,7 +22,7 @@ class Session : public QObject { public: ~Session(); - int id() const; + QString id() const; uid_t uid() const; const QString &username() const; WSocket *socket() const; @@ -35,7 +35,7 @@ class Session : public QObject { private: friend class SessionManager; - int m_id = 0; + QString m_id = {}; uid_t m_uid = 0; QString m_username = {}; WSocket *m_socket = nullptr; @@ -62,9 +62,9 @@ class SessionManager : public QObject { bool activeSocketEnabled() const; void setActiveSocketEnabled(bool newEnabled); - void updateActiveUserSession(const QString &username, int id); + void updateActiveUserSession(const QString &username, const QString &id); void removeSession(std::shared_ptr session); - std::shared_ptr sessionForId(int id) const; + std::shared_ptr sessionForId(const QString &id) const; std::shared_ptr sessionForUid(uid_t uid) const; std::shared_ptr sessionForUser(const QString &username) const; std::shared_ptr sessionForXWayland(WXWayland *xwayland) const; @@ -76,7 +76,7 @@ class SessionManager : public QObject { void sessionChanged(); private: - std::shared_ptr ensureSession(int id, QString username); + std::shared_ptr ensureSession(QString id, QString username); std::weak_ptr m_activeSession; QList> m_sessions; diff --git a/src/surface/surfacewrapper.cpp b/src/surface/surfacewrapper.cpp index 8110fe289..025c490a9 100644 --- a/src/surface/surfacewrapper.cpp +++ b/src/surface/surfacewrapper.cpp @@ -60,6 +60,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, , m_hideByshowDesk(true) , m_hideByLockScreen(false) , m_confirmHideByLockScreen(false) + , m_ignoreNormalGeometryUpdate(false) , m_blur(false) , m_isActivated(false) , m_appId(appId) @@ -92,6 +93,7 @@ SurfaceWrapper::SurfaceWrapper(SurfaceWrapper *original, QQuickItem *parent) , m_hideByshowDesk(true) , m_hideByLockScreen(false) , m_confirmHideByLockScreen(false) + , m_ignoreNormalGeometryUpdate(false) , m_blur(false) , m_isActivated(false) , m_appId(original->m_appId) @@ -157,6 +159,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, , m_hideByshowDesk(true) , m_hideByLockScreen(false) , m_confirmHideByLockScreen(false) + , m_ignoreNormalGeometryUpdate(false) , m_blur(false) , m_isActivated(false) , m_appId(appId) @@ -265,12 +268,12 @@ void SurfaceWrapper::setup() m_shellSurface->safeConnect(&WToplevelSurface::requestCancelMinimize, this, [this]() { requestCancelMinimize(); }); - m_shellSurface->safeConnect(&WToplevelSurface::requestMaximize, - this, - &SurfaceWrapper::requestMaximize); - m_shellSurface->safeConnect(&WToplevelSurface::requestCancelMaximize, - this, - &SurfaceWrapper::requestCancelMaximize); + m_shellSurface->safeConnect(&WToplevelSurface::requestMaximize, this, [this]() { + requestMaximize(); + }); + m_shellSurface->safeConnect(&WToplevelSurface::requestCancelMaximize, this, [this]() { + requestCancelMaximize(); + }); m_shellSurface->safeConnect(&WToplevelSurface::requestMove, this, &SurfaceWrapper::requestMove); @@ -831,7 +834,7 @@ SurfaceWrapper::State SurfaceWrapper::surfaceState() const return m_surfaceState; } -void SurfaceWrapper::setSurfaceState(State newSurfaceState) +void SurfaceWrapper::setSurfaceState(State newSurfaceState, bool performAnimation) { if (m_wrapperAboutToRemove) return; @@ -858,7 +861,18 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) } if (targetGeometry.isValid()) { - startStateChangeAnimation(newSurfaceState, targetGeometry); + bool shouldAnimate = performAnimation; + if (shouldAnimate + && (newSurfaceState == State::Maximized || m_surfaceState == State::Maximized) + && !Helper::instance()->config()->enableMaximizeAnimation()) { + shouldAnimate = false; + } + if (shouldAnimate) { + startStateChangeAnimation(newSurfaceState, targetGeometry); + } else { + applyStateGeometry(targetGeometry); + doSetSurfaceState(newSurfaceState); + } } else { if (m_geometryAnimation) { m_geometryAnimation->disconnect(this); @@ -1091,7 +1105,7 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeo, const QRectF &oldGeome if (m_container && m_container->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) return; - if (isNormal() && !m_geometryAnimation) { + if (isNormal() && !m_geometryAnimation && !m_ignoreNormalGeometryUpdate) { setNormalGeometry(newGeometry); } @@ -1106,6 +1120,19 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeo, const QRectF &oldGeome updateClipRect(); } +void SurfaceWrapper::applyStateGeometry(const QRectF &targetGeometry) +{ + if (!targetGeometry.isValid()) + return; + + m_ignoreNormalGeometryUpdate = true; + if (!resize(targetGeometry.size())) + goto done; + setPosition(alignToPixelGrid(targetGeometry.topLeft())); +done: + m_ignoreNormalGeometryUpdate = false; +} + void SurfaceWrapper::createNewOrClose(uint direction) { if (!m_windowAnimationEnabled) @@ -1123,6 +1150,8 @@ void SurfaceWrapper::createNewOrClose(uint direction) case Type::XdgToplevel: [[fallthrough]]; case Type::XWayland: { + if (!Helper::instance()->config()->enableWindowOpenCloseAnimation()) + return; m_windowAnimation = m_engine->createNewAnimation(this, container(), direction); m_windowAnimation->setProperty("enableBlur", m_blur); } break; @@ -1135,11 +1164,15 @@ void SurfaceWrapper::createNewOrClose(uint direction) auto *surface = qobject_cast(m_shellSurface); auto anchor = surface->getExclusiveZoneEdge(); if (scope == "dde-shell/launchpad") { - m_windowAnimation = m_engine->createLaunchpadAnimation(this, direction, m_container); + if (Helper::instance()->config()->enableLaunchpadAnimation()) { + m_windowAnimation = m_engine->createLaunchpadAnimation(this, direction, m_container); + } } else if (anchor != WLayerSurface::AnchorType::None) { - m_windowAnimation = m_engine->createLayerShellAnimation(this, container(), direction); - m_windowAnimation->setProperty("position", QVariant::fromValue(anchor)); - m_windowAnimation->setProperty("enableBlur", m_blur); + if (Helper::instance()->config()->enableLayerShellAnimation()) { + m_windowAnimation = m_engine->createLayerShellAnimation(this, container(), direction); + m_windowAnimation->setProperty("position", QVariant::fromValue(anchor)); + m_windowAnimation->setProperty("enableBlur", m_blur); + } } else { // NOTE: missing fullscreen window animation, so hide window now. if (m_hideByLockScreen) { @@ -1446,6 +1479,12 @@ void SurfaceWrapper::startShowDesktopAnimation(bool show) } setHideByShowDesk(show); + + if (!Helper::instance()->config()->enableShowDesktopAnimation()) { + updateVisible(); + return; + } + m_showDesktopAnimation = m_engine->createShowDesktopAnimation(this, container(), show); bool ok = connect(m_showDesktopAnimation, SIGNAL(finished()), @@ -1486,7 +1525,7 @@ void SurfaceWrapper::setRadius(qreal newRadius) void SurfaceWrapper::requestMinimize(bool onAnimation) { setSurfaceState(State::Minimized); - if (onAnimation) + if (onAnimation && Helper::instance()->config()->enableMinimizeAnimation()) startMinimizeAnimation(iconGeometry(), CLOSE_ANIMATION); } @@ -1498,32 +1537,32 @@ void SurfaceWrapper::requestCancelMinimize(bool onAnimation) setHideByShowDesk(true); doSetSurfaceState(m_previousSurfaceState); - if (onAnimation) + if (onAnimation && Helper::instance()->config()->enableMinimizeAnimation()) startMinimizeAnimation(iconGeometry(), OPEN_ANIMATION); } -void SurfaceWrapper::requestMaximize() +void SurfaceWrapper::requestMaximize(bool onAnimation) { if (m_surfaceState == State::Minimized || m_surfaceState == State::Fullscreen) return; - setSurfaceState(State::Maximized); + setSurfaceState(State::Maximized, onAnimation); } -void SurfaceWrapper::requestCancelMaximize() +void SurfaceWrapper::requestCancelMaximize(bool onAnimation) { if (m_surfaceState != State::Maximized) return; - setSurfaceState(State::Normal); + setSurfaceState(State::Normal, onAnimation); } -void SurfaceWrapper::requestToggleMaximize() +void SurfaceWrapper::requestToggleMaximize(bool onAnimation) { if (m_surfaceState == State::Maximized) - requestCancelMaximize(); + requestCancelMaximize(onAnimation); else - requestMaximize(); + requestMaximize(onAnimation); } void SurfaceWrapper::requestFullscreen() diff --git a/src/surface/surfacewrapper.h b/src/surface/surfacewrapper.h index c85486c59..a00324ae6 100644 --- a/src/surface/surfacewrapper.h +++ b/src/surface/surfacewrapper.h @@ -186,7 +186,7 @@ class SurfaceWrapper : public QQuickItem State previousSurfaceState() const; State surfaceState() const; - void setSurfaceState(State newSurfaceState); + void setSurfaceState(State newSurfaceState, bool performAnimation = true); QBindable bindableSurfaceState(); bool isNormal() const; bool isMaximized() const; @@ -283,9 +283,9 @@ public Q_SLOTS: // for titlebar void requestMinimize(bool onAnimation = true); void requestCancelMinimize(bool onAnimation = true); - void requestMaximize(); - void requestCancelMaximize(); - void requestToggleMaximize(); + void requestMaximize(bool onAnimation = true); + void requestCancelMaximize(bool onAnimation = true); + void requestToggleMaximize(bool onAnimation = true); void requestFullscreen(); void requestCancelFullscreen(); void requestClose(); @@ -382,9 +382,11 @@ public Q_SLOTS: Q_SLOT void onHideAnimationFinished(); void updateExplicitAlwaysOnTop(); void startMinimizeAnimation(const QRectF &iconGeometry, uint direction); + void startMaximizeAnimation(const QRectF &geometry, uint direction); Q_SLOT void onMinimizeAnimationFinished(); void startShowDesktopAnimation(bool show); Q_SLOT void onShowDesktopAnimationFinished(); + void applyStateGeometry(const QRectF &targetGeometry); void updateHasActiveCapability(ActiveControlState state, bool value); // wayland set by treeland-dde-shell, x11 set by bypassManager/windowTypes @@ -459,6 +461,7 @@ public Q_SLOTS: uint m_hideByshowDesk : 1; uint m_hideByLockScreen : 1; uint m_confirmHideByLockScreen : 1; + uint m_ignoreNormalGeometryUpdate : 1; uint m_blur : 1; uint m_isActivated : 1; SurfaceRole m_surfaceRole = SurfaceRole::Normal; diff --git a/src/workspace/workspace.cpp b/src/workspace/workspace.cpp index bf6c821f0..351ec65d4 100644 --- a/src/workspace/workspace.cpp +++ b/src/workspace/workspace.cpp @@ -300,6 +300,9 @@ void Workspace::updateSurfacesOwnsOutput() void Workspace::createSwitcher() { + if (!Helper::instance()->config()->enableWorkspaceAnimation()) + return; + if (m_switcherEnabled && !m_switcher) { auto engine = Helper::instance()->qmlEngine(); m_switcher = engine->createWorkspaceSwitcher(this); diff --git a/src/workspace/workspaceanimationcontroller.cpp b/src/workspace/workspaceanimationcontroller.cpp index 50997a046..beb4cc1e3 100644 --- a/src/workspace/workspaceanimationcontroller.cpp +++ b/src/workspace/workspaceanimationcontroller.cpp @@ -146,11 +146,19 @@ void WorkspaceAnimationController::slide(uint fromWorkspaceIndex, uint toWorkspa m_needBounce = false; slideRunning(toWorkspaceIndex); slideNormal(fromWorkspaceIndex, toWorkspaceIndex); - startSlideAnimation(); + + if (Helper::instance()->config()->enableWorkspaceAnimation()) { + startSlideAnimation(); + } else { + setViewportPos(m_animationDestination); + } } void WorkspaceAnimationController::bounce(uint currentWorkspaceIndex, Direction direction) { + if (!Helper::instance()->config()->enableWorkspaceAnimation()) + return; + if (m_bounceAnimation->state() == QAbstractAnimation::Running) return; if (m_slideAnimation->state() != QAbstractAnimation::Running) {