Projects
Eulaceura:Mainline
kiran-session-manager
_service:obs_scm:kiran-session-manager-17059176...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:kiran-session-manager-1705917668.255d400.obscpio of Package kiran-session-manager
07070100000000000081A400000000000000000000000165AE3CE40000039E000000000000000000000000000000000000006900000000kiran-session-manager-1705917668.255d400/0001-Add-Type-Application-in-kiran-session-idlemonitor.de.patchFrom bb27c4d23c4a300e5da80ba4bf27fce332d8f409 Mon Sep 17 00:00:00 2001 From: huangjiawen <huangjiawen@kylinsec.com.cn> Date: Fri, 2 Jun 2023 17:17:27 +0800 Subject: [PATCH] Add Type=Application in kiran-session-idlemonitor.desktop.in file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在文件kiran-session-idlemonitor.desktop.in中添加Type=Application Signed-off-by: huangjiawen <huangjiawen@kylinsec.com.cn> --- data/kiran-session-idlemonitor.desktop.in | 1 + 1 file changed, 1 insertion(+) diff --git a/data/kiran-session-idlemonitor.desktop.in b/data/kiran-session-idlemonitor.desktop.in index ea3f34f..04889dc 100644 --- a/data/kiran-session-idlemonitor.desktop.in +++ b/data/kiran-session-idlemonitor.desktop.in @@ -1,4 +1,5 @@ [Desktop Entry] +Type=Application Name=Kiran Session Idle Monitor Exec=/usr/bin/kiran-session-idlemonitor NoDisplay=true -- 2.33.0 07070100000001000081A400000000000000000000000165AE3CE400000382000000000000000000000000000000000000006900000000kiran-session-manager-1705917668.255d400/0001-feature-blacklist_autostart_apps-Add-mate-volume-con.patchFrom dc2ee24bb97dd8334aa133c8f8b8d39e274b31b1 Mon Sep 17 00:00:00 2001 From: luoqing <luoqing@kylinsec.com.cn> Date: Sun, 8 Oct 2023 11:30:31 +0800 Subject: [PATCH] feature(blacklist_autostart_apps):Add mate-volume-control-status-icon.desktop to the autostart blacklist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将mate-volume-control-status-icon.desktop添加到自启动黑名单 --- data/blacklist_autostart_apps.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/data/blacklist_autostart_apps.txt b/data/blacklist_autostart_apps.txt index 04002c9..8459d14 100644 --- a/data/blacklist_autostart_apps.txt +++ b/data/blacklist_autostart_apps.txt @@ -2,3 +2,4 @@ mate-screensaver.desktop mate-power-manager.desktop orca-autostart.desktop nm-applet.desktop +mate-volume-control-status-icon.desktop \ No newline at end of file -- 2.33.0 07070100000002000081A400000000000000000000000165AE3CE400003E34000000000000000000000000000000000000006900000000kiran-session-manager-1705917668.255d400/0001-feature-lockscreen-Add-LockScreenWhenHibernate-and-L.patchFrom b6ac29d2838bedab513d6cdfb21084b95da0a70c Mon Sep 17 00:00:00 2001 From: tangjie02 <tangjie02@kylinsec.com.cn> Date: Tue, 9 May 2023 17:06:03 +0800 Subject: [PATCH] feature(lockscreen): Add LockScreenWhenHibernate and LockScreenWhenSuspend functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加当计算机休眠/待机时是否锁屏功能 Relates #68459 Signed-off-by: tangjie02 <tangjie02@kylinsec.com.cn> --- ...insec.kiran.session-manager.gschema.xml.in | 10 +++ data/org.gnome.SessionManager.xml | 40 +++++++++++ include/ksm-i.h | 12 ++-- lib/dbus/systemd-login1.cpp | 1 + src/core/power.cpp | 68 +++++++++++++++++-- src/core/power.h | 7 ++ src/core/presence.cpp | 3 - src/core/session-manager.cpp | 68 +++++++++++++++++++ src/core/session-manager.h | 15 ++++ 9 files changed, 210 insertions(+), 14 deletions(-) diff --git a/data/com.kylinsec.kiran.session-manager.gschema.xml.in b/data/com.kylinsec.kiran.session-manager.gschema.xml.in index 6d2b361..b71dd3e 100644 --- a/data/com.kylinsec.kiran.session-manager.gschema.xml.in +++ b/data/com.kylinsec.kiran.session-manager.gschema.xml.in @@ -5,6 +5,16 @@ <summary>Time before session is considered idle</summary> <description>The number of minutes of inactivity before the session is considered idle</description> </key> + + <key name="screen-locked-when-suspend" type="b"> + <default>true</default> + <description>Whether lock screen when the computer is suspend.</description> + </key> + + <key name="screen-locked-when-hibernate" type="b"> + <default>true</default> + <description>Whether lock screen when the computer is hibernate.</description> + </key> </schema> </schemalist> diff --git a/data/org.gnome.SessionManager.xml b/data/org.gnome.SessionManager.xml index 9b4cec5..92ba554 100644 --- a/data/org.gnome.SessionManager.xml +++ b/data/org.gnome.SessionManager.xml @@ -72,6 +72,28 @@ <description>This gets a list of all the inhibitors that are currently known to the session manager.</description> </method> + <method name="Suspend"> + <description>Suspend computer.</description> + </method> + + <method name="CanSuspend"> + <arg name="is_available" direction="out" type="b"> + <summary>True if suspend is available to the user, false otherwise.</summary> + </arg> + <description>Whether the user can suspend.</description> + </method> + + <method name="Hibernate"> + <description>Hibernate computer.</description> + </method> + + <method name="CanHibernate"> + <arg name="is_available" direction="out" type="b"> + <summary>True if hibernate is available to the user, false otherwise.</summary> + </arg> + <description>Whether the user can hibernate.</description> + </method> + <method name="Shutdown"> <description>Shutdown the system.</description> </method> @@ -126,6 +148,14 @@ <description>Adds the variable name to the application launch environment with the specified value. May only be used during the Session Manager initialization phase.</description> </method> + <property name="ScreenLockedWhenSuspend" type="b" access="readwrite"> + <description>Whether lock screen when the computer is suspend.</description> + </property> + + <property name="ScreenLockedWhenHibernate" type="b" access="readwrite"> + <description>Whether lock screen when the computer is hibernate.</description> + </property> + <signal name="InhibitorAdded"> <arg name="cookie" type="u"> <summary>The inhibitor cookie.</summary> @@ -145,5 +175,15 @@ <description>The stage where session manager is in.</description> </signal> + <signal name="ScreenLockedWhenSuspendChanged"> + <arg name="screen_locked_when_suspend" type="b" /> + <description>Whether lock screen when the computer is suspend.</description> + </signal> + + <signal name="ScreenLockedWhenHibernateChanged"> + <arg name="screen_locked_when_hibernate" type="b" /> + <description>Whether lock screen when the computer is hibernate.</description> + </signal> + </interface> </node> diff --git a/include/ksm-i.h b/include/ksm-i.h index 71376dc..ca4bb86 100644 --- a/include/ksm-i.h +++ b/include/ksm-i.h @@ -21,6 +21,8 @@ extern "C" #define DESKTOP_ENVIRONMENT "KIRAN" +/* 为了保持跟第三方应用(firefox、pluma等)兼容,暂时还是使用gnome名字。 + 但后续版本有可能更名,所以最好使用宏定义,不要直接使用字符串常量。*/ #define KSM_DBUS_NAME "org.gnome.SessionManager" #define KSM_DBUS_OBJECT_PATH "/org/gnome/SessionManager" #define KSM_DBUS_INTERFACE_NAME "org.gnome.SessionManager" @@ -34,10 +36,12 @@ extern "C" #define KSM_IDLE_DBUS_OBJECT_PATH "/com/kylinsec/Kiran/SessionManager/IdleMonitor" #define KSM_SCHEMA_ID "com.kylinsec.kiran.session-manager" -#define KSM_SCHEMA_KEY_SESSION_DAEMONS "session-daemons" -#define KSM_SCHEMA_KEY_WINDOW_MANAGER "window-manager" -#define KSM_SCHEMA_KEY_PANEL "panel" -#define KSM_SCHEMA_KEY_FILE_MANAGER "file-manager" +// 计算机多久未操作视为空闲 +#define KSM_SCHEMA_KEY_IDLE_DELAY "idle-delay" +// 待机时是否锁定屏幕 +#define KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_SUSPEND "screen-locked-when-suspend" +// 休眠时是否锁定屏幕 +#define KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_HIBERNATE "screen-locked-when-hibernate" // JK: json key #define KSM_INHIBITOR_JK_COOKIE "cookie" diff --git a/lib/dbus/systemd-login1.cpp b/lib/dbus/systemd-login1.cpp index dea49e8..e2416a3 100644 --- a/lib/dbus/systemd-login1.cpp +++ b/lib/dbus/systemd-login1.cpp @@ -188,6 +188,7 @@ bool SystemdLogin1::canDoMethod(const QString &methodName) auto canResult = replyMessage.arguments().takeFirst().toString(); KLOG_DEBUG() << "Function " << methodName << " return " << canResult; + // TODO: 需要确认challenge状态是否可以执行电源动作 return (canResult == "yes" || canResult == "challenge"); } diff --git a/src/core/power.cpp b/src/core/power.cpp index 2bc3ac5..87200fb 100644 --- a/src/core/power.cpp +++ b/src/core/power.cpp @@ -13,6 +13,7 @@ */ #include "src/core/power.h" +#include <QGSettings> #include "lib/base/base.h" #include "lib/dbus/display-manager.h" #include "lib/dbus/screensaver.h" @@ -22,6 +23,7 @@ namespace Kiran { Power::Power(QObject *parent) : QObject(parent) { + this->m_settings = new QGSettings(KSM_SCHEMA_ID, "", this); } void Power::init() @@ -54,7 +56,7 @@ bool Power::canPowerAction(PowerAction powerAction) bool Power::doPowerAction(PowerAction powerAction) { - KLOG_DEBUG() << "Power action: " << powerAction; + KLOG_DEBUG() << "Do power action: " << this->powerActionEnum2Str(powerAction); switch (powerAction) { @@ -84,20 +86,50 @@ bool Power::switchUser() bool Power::suspend() { + uint32_t throttle = 0; + RETURN_VAL_IF_TRUE(!SystemdLogin1::getDefault()->canSuspend(), false); - // 这里忽略锁屏失败的情况 - ScreenSaver::getDefault()->lock(); - return SystemdLogin1::getDefault()->suspend(); + // 挂起之前判断是否锁定屏幕 + auto lockscreen = this->m_settings->get(KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_SUSPEND).toBool(); + if (lockscreen) + { + throttle = ScreenSaver::getDefault()->lockAndThrottle("suspend"); + } + + auto retval = SystemdLogin1::getDefault()->suspend(); + + ScreenSaver::getDefault()->poke(); + if (throttle) + { + ScreenSaver::getDefault()->removeThrottle(throttle); + } + + return retval; } bool Power::hibernate() { + uint32_t throttle = 0; + RETURN_VAL_IF_TRUE(!SystemdLogin1::getDefault()->canHibernate(), false); - // 这里忽略锁屏失败的情况 - ScreenSaver::getDefault()->lock(); - return SystemdLogin1::getDefault()->hibernate(); + // 休眠之前判断是否锁定屏幕 + auto lockscreen = this->m_settings->get(KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_HIBERNATE).toBool(); + if (lockscreen) + { + throttle = ScreenSaver::getDefault()->lockAndThrottle("hibernate"); + } + + auto retval = SystemdLogin1::getDefault()->hibernate(); + + ScreenSaver::getDefault()->poke(); + if (throttle) + { + ScreenSaver::getDefault()->removeThrottle(throttle); + } + + return retval; } bool Power::shutdown() @@ -112,4 +144,26 @@ bool Power::reboot() return SystemdLogin1::getDefault()->reboot(); } +QString Power::powerActionEnum2Str(PowerAction powerAction) +{ + switch (powerAction) + { + case PowerAction::POWER_ACTION_SWITCH_USER: + return "switch user"; + case PowerAction::POWER_ACTION_LOGOUT: + return "logout"; + case PowerAction::POWER_ACTION_SUSPEND: + return "suspend"; + case PowerAction::POWER_ACTION_HIBERNATE: + return "hibernate"; + case PowerAction::POWER_ACTION_SHUTDOWN: + return "shutdown"; + case PowerAction::POWER_ACTION_REBOOT: + return "reboot"; + default: + break; + } + return "unknown"; +} + } // namespace Kiran \ No newline at end of file diff --git a/src/core/power.h b/src/core/power.h index cbc2b21..14bcdda 100644 --- a/src/core/power.h +++ b/src/core/power.h @@ -17,6 +17,8 @@ #include <QObject> #include "ksm-i.h" +class QGSettings; + namespace Kiran { class Power : public QObject @@ -44,5 +46,10 @@ private: bool shutdown(); // 重启 bool reboot(); + + QString powerActionEnum2Str(PowerAction powerAction); + +private: + QGSettings *m_settings; }; } // namespace Kiran \ No newline at end of file diff --git a/src/core/presence.cpp b/src/core/presence.cpp index f41fa24..d7e73f3 100644 --- a/src/core/presence.cpp +++ b/src/core/presence.cpp @@ -22,9 +22,6 @@ namespace Kiran { -#define KSM_SCHEMA_ID "com.kylinsec.kiran.session-manager" -#define KSM_SCHEMA_KEY_IDLE_DELAY "idleDelay" - Presence::Presence(QObject *parent) : QObject(parent), m_idleMonitorProxy(nullptr), m_enabledIdleTimeout(true), diff --git a/src/core/session-manager.cpp b/src/core/session-manager.cpp index 1f33db7..12dcc15 100644 --- a/src/core/session-manager.cpp +++ b/src/core/session-manager.cpp @@ -73,6 +73,39 @@ void SessionManager::start() this->processPhase(); } +bool SessionManager::screenLockedWhenHibernate() +{ + return this->m_settings->get(KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_HIBERNATE).toBool(); +} + +void SessionManager::setScreenLockedWhenHibernate(bool screenLockedWhenHibernate) +{ + if (screenLockedWhenHibernate != this->screenLockedWhenHibernate()) + { + this->m_settings->set(KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_HIBERNATE, screenLockedWhenHibernate); + Q_EMIT this->ScreenLockedWhenHibernateChanged(screenLockedWhenHibernate); + } +} + +bool SessionManager::screenLockedWhenSuspend() +{ + return this->m_settings->get(KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_SUSPEND).toBool(); +} + +void SessionManager::setScreenLockedWhenSuspend(bool screenLockedWhenSuspend) +{ + if (screenLockedWhenSuspend != this->screenLockedWhenSuspend()) + { + this->m_settings->set(KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_SUSPEND, screenLockedWhenSuspend); + Q_EMIT this->ScreenLockedWhenSuspendChanged(screenLockedWhenSuspend); + } +} + +bool SessionManager::CanHibernate() +{ + return this->m_power->canPowerAction(PowerAction::POWER_ACTION_HIBERNATE); +} + bool SessionManager::CanLogout() { return true; @@ -88,6 +121,11 @@ bool SessionManager::CanShutdown() return this->m_power->canPowerAction(PowerAction::POWER_ACTION_SHUTDOWN); } +bool SessionManager::CanSuspend() +{ + return this->m_power->canPowerAction(PowerAction::POWER_ACTION_SUSPEND); +} + QString SessionManager::GetInhibitor(uint cookie) { QJsonDocument jsonDoc; @@ -133,6 +171,21 @@ QString SessionManager::GetInhibitors() return QString(jsonDoc.toJson()); } +void SessionManager::Hibernate() +{ + if (this->m_currentPhase > KSMPhase::KSM_PHASE_RUNNING) + { + DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_INVALID); + } + + if (!this->m_power->canPowerAction(PowerAction::POWER_ACTION_HIBERNATE)) + { + DBUS_ERROR_REPLY_AND_RET(QDBusError::AccessDenied, KSMErrorCode::ERROR_MANAGER_POWER_ACTION_UNSUPPORTED); + } + + this->m_power->doPowerAction(PowerAction::POWER_ACTION_HIBERNATE); +} + uint SessionManager::SessionManager::Inhibit(const QString &appID, uint toplevelXID, const QString &reason, @@ -246,6 +299,21 @@ void SessionManager::Shutdown() this->startNextPhase(); } +void SessionManager::Suspend() +{ + if (this->m_currentPhase > KSMPhase::KSM_PHASE_RUNNING) + { + DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_INVALID); + } + + if (!this->m_power->canPowerAction(PowerAction::POWER_ACTION_SUSPEND)) + { + DBUS_ERROR_REPLY_AND_RET(QDBusError::AccessDenied, KSMErrorCode::ERROR_MANAGER_POWER_ACTION_UNSUPPORTED); + } + + this->m_power->doPowerAction(PowerAction::POWER_ACTION_SUSPEND); +} + void SessionManager::Uninhibit(uint inhibitCookie) { auto inhibitor = InhibitorManager::getInstance()->getInhibitor(inhibitCookie); diff --git a/src/core/session-manager.h b/src/core/session-manager.h index 8e6ffab..3d934e2 100644 --- a/src/core/session-manager.h +++ b/src/core/session-manager.h @@ -40,6 +40,9 @@ class SessionManager : public QObject, protected QDBusContext { Q_OBJECT + + Q_PROPERTY(bool ScreenLockedWhenHibernate READ screenLockedWhenHibernate WRITE setScreenLockedWhenHibernate) + Q_PROPERTY(bool ScreenLockedWhenSuspend READ screenLockedWhenSuspend WRITE setScreenLockedWhenSuspend) public: SessionManager(AppManager *appManager, ClientManager *clientManager, @@ -57,13 +60,22 @@ public: // 会话开始 void start(); + bool screenLockedWhenHibernate(); + void setScreenLockedWhenHibernate(bool screenLockedWhenHibernate); + + bool screenLockedWhenSuspend(); + void setScreenLockedWhenSuspend(bool screenLockedWhenSuspend); + public Q_SLOTS: // METHODS + bool CanHibernate(); bool CanLogout(); bool CanReboot(); bool CanShutdown(); + bool CanSuspend(); // 获取抑制器 QString GetInhibitor(uint cookie); QString GetInhibitors(); + void Hibernate(); // 添加抑制器 uint Inhibit(const QString &appID, uint toplevelXID, const QString &reason, uint flags); // 判断指定flags的抑制器是否存在 @@ -76,12 +88,15 @@ public Q_SLOTS: // METHODS // 添加会话程序的环境变量 void Setenv(const QString &name, const QString &value); void Shutdown(); + void Suspend(); // 删除抑制器 void Uninhibit(uint inhibitCookie); Q_SIGNALS: // SIGNALS void InhibitorAdded(uint cookie); void InhibitorRemoved(uint cookie); void PhaseChanged(int phase); + void ScreenLockedWhenHibernateChanged(bool screen_locked_when_hibernate); + void ScreenLockedWhenSuspendChanged(bool screen_locked_when_suspend); public Q_SLOTS: // 应用启动超时 -- 2.36.1 07070100000003000081A400000000000000000000000165AE3CE400000AC9000000000000000000000000000000000000006500000000kiran-session-manager-1705917668.255d400/0001-feature-session-Add-always-show-exit-window-flag.patchFrom 49da14ad556935f475a538090a7c3648485d3485 Mon Sep 17 00:00:00 2001 From: huangjiawen <huangjiawen@kylinsec.com.cn> Date: Wed, 31 May 2023 17:31:48 +0800 Subject: [PATCH] feature(session): Add always show exit window flag. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加总是显示退出窗口标志位 Signed-off-by: huangjiawen <huangjiawen@kylinsec.com.cn> --- data/com.kylinsec.kiran.session-manager.gschema.xml.in | 6 +++++- include/ksm-i.h | 4 +++- src/core/session-manager.cpp | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/data/com.kylinsec.kiran.session-manager.gschema.xml.in b/data/com.kylinsec.kiran.session-manager.gschema.xml.in index b71dd3e..313d055 100644 --- a/data/com.kylinsec.kiran.session-manager.gschema.xml.in +++ b/data/com.kylinsec.kiran.session-manager.gschema.xml.in @@ -15,6 +15,10 @@ <default>true</default> <description>Whether lock screen when the computer is hibernate.</description> </key> - </schema> + <key name="always-show-exit-window" type="b"> + <default>false</default> + <description>Set whether to always show the exit window.</description> + </key> + </schema> </schemalist> diff --git a/include/ksm-i.h b/include/ksm-i.h index ca4bb86..fb49a59 100644 --- a/include/ksm-i.h +++ b/include/ksm-i.h @@ -42,6 +42,8 @@ extern "C" #define KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_SUSPEND "screen-locked-when-suspend" // 休眠时是否锁定屏幕 #define KSM_SCHEMA_KEY_SCREEN_LOCKED_WHEN_HIBERNATE "screen-locked-when-hibernate" +// 退出时是否显示退出窗口 +#define KSM_SCHEMA_KEY_ALWAYS_SHOW_EXIT_WINDOW "always-show-exit-window" // JK: json key #define KSM_INHIBITOR_JK_COOKIE "cookie" @@ -96,4 +98,4 @@ extern "C" #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/src/core/session-manager.cpp b/src/core/session-manager.cpp index 12dcc15..6ca79be 100644 --- a/src/core/session-manager.cpp +++ b/src/core/session-manager.cpp @@ -725,8 +725,9 @@ void SessionManager::queryEndSessionComplete() this->m_waitingClientsTimeoutID->disconnect(); this->m_waitingClientsTimeoutID->stop(); + auto showExitWindow = this->m_settings->get(KSM_SCHEMA_KEY_ALWAYS_SHOW_EXIT_WINDOW).toBool(); // 如果不存在退出会话的抑制器,则直接进入下一个阶段 - if (!this->m_inhibitorManager->hasInhibitor(KSMInhibitorFlag::KSM_INHIBITOR_FLAG_QUIT)) + if (!showExitWindow && !this->m_inhibitorManager->hasInhibitor(KSMInhibitorFlag::KSM_INHIBITOR_FLAG_QUIT)) { this->startNextPhase(); return; -- 2.33.0 07070100000004000081A400000000000000000000000165AE3CE4000003F2000000000000000000000000000000000000006900000000kiran-session-manager-1705917668.255d400/0001-fix-blacklist-autostart-add-polkit-mate-authenticati.patchFrom 900779f8301993031bfc75e12d9b75fb27f6b990 Mon Sep 17 00:00:00 2001 From: liuxinhao <liuxinhao@kylinsec.com.cn> Date: Sat, 20 Jan 2024 12:57:58 +0800 Subject: [PATCH] fix(blacklist autostart): add polkit-mate-authentication-agent-1 to blacklist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加polkit-mate-authentication-agent-1进入自启动黑名单,2.5已有kiran-polkit-agent实现 --- data/blacklist_autostart_apps.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/blacklist_autostart_apps.txt b/data/blacklist_autostart_apps.txt index 8459d14..6302c5f 100644 --- a/data/blacklist_autostart_apps.txt +++ b/data/blacklist_autostart_apps.txt @@ -2,4 +2,5 @@ mate-screensaver.desktop mate-power-manager.desktop orca-autostart.desktop nm-applet.desktop -mate-volume-control-status-icon.desktop \ No newline at end of file +mate-volume-control-status-icon.desktop +polkit-mate-authentication-agent-1.desktop -- 2.33.0 07070100000005000081A400000000000000000000000165AE3CE400000445000000000000000000000000000000000000006900000000kiran-session-manager-1705917668.255d400/0001-fix-boot-Fix-fork-other-session-program-failed-by-ad.patchFrom 18165b636a6a2fc083b2139f0cfc71d1dac8f221 Mon Sep 17 00:00:00 2001 From: tangjie02 <tangjie02@kylinsec.com.cn> Date: Fri, 16 Jun 2023 15:34:21 +0800 Subject: [PATCH] fix(boot): Fix fork other session program failed by adding GDK_BACKEND and QT_QPA_FLATFORM environment variables. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复由于DISPLAY后端设置错误导致会话中的进程无法启动问题 Relates #I7C89D Signed-off-by: tangjie02 <tangjie02@kylinsec.com.cn> --- data/kiran-session-wayland.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/kiran-session-wayland.in b/data/kiran-session-wayland.in index 4bd1de9..1ffb0b1 100644 --- a/data/kiran-session-wayland.in +++ b/data/kiran-session-wayland.in @@ -1,3 +1,6 @@ #!/bin/sh -exec @CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager --session-type=kiran-wayland \ No newline at end of file +export GDK_BACKEND=x11 +export QT_QPA_PLATFORM=xcb + +exec @CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager --session-type=kiran-wayland -- 2.36.1 07070100000006000081A400000000000000000000000165AE3CE400000317000000000000000000000000000000000000006700000000kiran-session-manager-1705917668.255d400/0001-fix-kiran-session-manager-fixes-link-Qt5DBus-error.patchFrom 474e5d9a32f1b8fa4509b668ba48129d1061effc Mon Sep 17 00:00:00 2001 From: niko_yhc <yinhongchang@kylinsec.com.cn> Date: Thu, 7 Sep 2023 16:04:42 +0800 Subject: [PATCH] fix(kiran-session-manager):fixes link Qt5DBus error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复链接Qt5DBus的错误 --- src/core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4c4479b..2452ecd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -66,6 +66,7 @@ target_link_libraries( ${XTRANS_LIBRARIES} ${GSETTINGS_QT_LIBRARIES} Qt5::Core + Qt5::DBus KF5::ConfigCore KF5::KIOCore lib-base -- 2.27.0 07070100000007000081A400000000000000000000000165AE3CE400000C80000000000000000000000000000000000000006000000000kiran-session-manager-1705917668.255d400/0001-fix-xsmp-Ignore-the-cancel-shutdown-request.patchFrom 9c06f60de67e54bd835e66d1b1adca9e370f0b2b Mon Sep 17 00:00:00 2001 From: tangjie02 <tangjie02@kylinsec.com.cn> Date: Tue, 12 Sep 2023 20:29:06 +0800 Subject: [PATCH] fix(xsmp): Ignore the cancel shutdown request. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 用于响应客户端取消结束会话的事件不能通知到用户,会导致开始菜单注销按钮功能不能正常使用,影响用户体验,因此暂时禁止处理该请求 Signed-off-by: tangjie02 <tangjie02@kylinsec.com.cn> --- src/core/inhibitor-manager.cpp | 13 ++++++++++--- src/core/session-manager.cpp | 7 ++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/core/inhibitor-manager.cpp b/src/core/inhibitor-manager.cpp index b42b57d..552929a 100644 --- a/src/core/inhibitor-manager.cpp +++ b/src/core/inhibitor-manager.cpp @@ -129,9 +129,8 @@ void InhibitorManager::deleteInhibitorsWithStartupID() bool InhibitorManager::hasInhibitor(uint32_t flags) { - auto iter = std::find_if(this->m_inhibitors.begin(), this->m_inhibitors.end(), [flags](QSharedPointer<Inhibitor> iter) { - return ((flags & iter->flags) == flags); - }); + auto iter = std::find_if(this->m_inhibitors.begin(), this->m_inhibitors.end(), [flags](QSharedPointer<Inhibitor> iter) + { return ((flags & iter->flags) == flags); }); return (iter != this->m_inhibitors.end()); } @@ -147,6 +146,14 @@ bool InhibitorManager::addInhibitor(QSharedPointer<Inhibitor> inhibitor) KLOG_DEBUG() << "Cookie: " << inhibitor->cookie; + KLOG_DEBUG() << "Add a new inhibitor," + << " cookie: " << inhibitor->cookie + << ", appid: " << inhibitor->appID + << ", flags: " << inhibitor->flags + << ", reason: " << inhibitor->reason + << ", startupID: " << inhibitor->startupID + << ", toplevelXID: " << inhibitor->toplevelXID; + if (this->m_inhibitors.find(inhibitor->cookie) != this->m_inhibitors.end()) { KLOG_WARNING() << "The inhibitor " << inhibitor->cookie << " already exist."; diff --git a/src/core/session-manager.cpp b/src/core/session-manager.cpp index 6ca79be..b5bdb57 100644 --- a/src/core/session-manager.cpp +++ b/src/core/session-manager.cpp @@ -486,9 +486,10 @@ void SessionManager::onInteractDone(Client *client) void SessionManager::onShutdownCanceled(Client *client) { - KLOG_DEBUG() << "Client: " << client->getID() << " cancels shutdown."; - - this->cancelEndSession(); + KLOG_WARNING() << "Client: " << client->getID() << " want to cancels shutdown. ignore the client request."; + /* 如果QT的窗口在closeEvent函数中调用event->ignore()来忽略窗口关闭事件,则桌面会话退出时会收到QT客户端发送的取消结束会话的事件, + 用于响应客户端取消结束会话的事件不能通知到用户,会导致开始菜单->注销按钮功能不能正常使用,影响用户体验,因此暂时禁止处理该请求。*/ + // this->cancelEndSession(); } void SessionManager::onEndSessionPhase2Request(Client *client) -- 2.36.1 07070100000008000081A400000000000000000000000165AE3CE40000038D000000000000000000000000000000000000003600000000kiran-session-manager-1705917668.255d400/README.en.md# kiran-session-manager #### Description The session manager will load all necessary applications for a full-featured user session. #### Software Architecture Software architecture description #### Installation 1. xxxx 2. xxxx 3. xxxx #### Instructions 1. xxxx 2. xxxx 3. xxxx #### Contribution 1. Fork the repository 2. Create Feat_xxx branch 3. Commit your code 4. Create Pull Request #### Gitee Feature 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 4. The most valuable open source project [GVP](https://gitee.com/gvp) 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 07070100000009000081A400000000000000000000000165AE3CE4000003E6000000000000000000000000000000000000003300000000kiran-session-manager-1705917668.255d400/README.md# kiran-session-manager #### 介绍 The session manager will load all necessary applications for a full-featured user session. #### 软件架构 软件架构说明 #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 使用说明 1. xxxx 2. xxxx 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 0707010000000A000081A400000000000000000000000165AE3CE40006E000000000000000000000000000000000000000004C00000000kiran-session-manager-1705917668.255d400/kiran-session-manager-2.5.0.tar.gzkiran-session-manager-2.5.0/0000775000175000017500000000000014417211354017337 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/include/0000775000175000017500000000000014417211336020762 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/include/ksm-i.h0000664000175000017500000000560014417211336022154 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #ifdef __cplusplus extern "C" { #endif #define DESKTOP_ENVIRONMENT "KIRAN" #define KSM_DBUS_NAME "org.gnome.SessionManager" #define KSM_DBUS_OBJECT_PATH "/org/gnome/SessionManager" #define KSM_DBUS_INTERFACE_NAME "org.gnome.SessionManager" #define KSM_CLIENT_PRIVATE_DBUS_INTERFACE "org.gnome.SessionManager.ClientPrivate" #define KSM_PRESENCE_DBUS_OBJECT_PATH "/org/gnome/SessionManager/Presence" #define KSM_PRESENCE_DBUS_INTERFACE_NAME "org.gnome.SessionManager.Presence" #define KSM_IDLE_DBUS_NAME "com.kylinsec.Kiran.SessionManager.IdleMonitor" #define KSM_IDLE_DBUS_OBJECT_PATH "/com/kylinsec/Kiran/SessionManager/IdleMonitor" #define KSM_SCHEMA_ID "com.kylinsec.kiran.session-manager" #define KSM_SCHEMA_KEY_SESSION_DAEMONS "session-daemons" #define KSM_SCHEMA_KEY_WINDOW_MANAGER "window-manager" #define KSM_SCHEMA_KEY_PANEL "panel" #define KSM_SCHEMA_KEY_FILE_MANAGER "file-manager" // JK: json key #define KSM_INHIBITOR_JK_COOKIE "cookie" #define KSM_INHIBITOR_JK_APP_ID "app_id" #define KSM_INHIBITOR_JK_TOPLEVEL_XID "toplevel_xid" #define KSM_INHIBITOR_JK_REASON "reason" #define KSM_INHIBITOR_JK_FLAGS "flags" // 抑制器标记位 enum KSMInhibitorFlag { // 抑制注销、关机和重启 KSM_INHIBITOR_FLAG_QUIT = 1 << 0, // 抑制切换用户 KSM_INHIBITOR_FLAG_SWITCH_USER = 1 << 1, // 抑制休眠、挂起和待机 KSM_INHIBITOR_FLAG_SAVE = 1 << 2, // 一直空闲超时信号发送 KSM_INHIBITOR_FLAG_IDLE = 1 << 3 }; // 暂时兼容旧的gnome规范,新的会话管理部分状态未使用 enum KSMPresenceStatus { // 正常可用状态 KSM_PRESENCE_STATUS_AVAILABLE = 0, // 未使用 KSM_PRESENCE_STATUS_INVISIBLE, // 未使用 KSM_PRESENCE_STATUS_BUSY, // 空闲状态 KSM_PRESENCE_STATUS_IDLE, KSM_PRESENCE_STATUS_LAST, }; enum PowerAction { POWER_ACTION_NONE, // 切换用户 POWER_ACTION_SWITCH_USER, // 注销 POWER_ACTION_LOGOUT, // 挂起 POWER_ACTION_SUSPEND, // 休眠 POWER_ACTION_HIBERNATE, // 关机 POWER_ACTION_SHUTDOWN, // 重启 POWER_ACTION_REBOOT, }; #ifdef __cplusplus } #endifkiran-session-manager-2.5.0/include/ksm-error-i.h0000664000175000017500000000255614417211336023312 0ustar wangyuchengwangyucheng/** * @file /kiran-ssr-manager/home/tangjie02/git/kiran-session-manager/include/ksm-error-i.h * @brief * @author tangjie02 <tangjie02@kylinos.com.cn> * @copyright (c) 2020~2021 KylinSec Co., Ltd. All rights reserved. */ /** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #ifdef __cplusplus extern "C" { #endif enum KSMErrorCode { // Common SUCCESS, ERROR_FAILED, // MANAGER ERROR_MANAGER_PHASE_CANNOT_REGISTER, ERROR_MANAGER_CLIENT_ALREADY_REGISTERED, ERROR_MANAGER_GEN_UNIQUE_COOKIE_FAILED, ERROR_MANAGER_INHIBITOR_NOTFOUND, ERROR_MANAGER_PHASE_INVALID, ERROR_MANAGER_POWER_ACTION_UNSUPPORTED, // PRESENCE ERROR_PRESENCE_STATUS_INVALID, }; #ifdef __cplusplus } #endif kiran-session-manager-2.5.0/data/0000775000175000017500000000000014417211336020250 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/data/com.kylinsec.Kiran.SessionManager.IdleMonitor.xml0000664000175000017500000000150014417211336031570 0ustar wangyuchengwangyucheng<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'> <node> <interface name="com.kylinsec.Kiran.SessionManager.IdleMonitor"> <method name="GetIdletime"> <arg name="idletime" direction="out" type="t"/> </method> <method name="AddIdleTimeout"> <arg name="interval" direction="in" type="t" /> <arg name="id" direction="out" type="i" /> </method> <method name="RemoveIdleTimeout"> <arg name="id" direction="in" type="i" /> </method> <method name="SimulateUserActivity"/> <signal name="ResumingFromIdle" /> <signal name="TimeoutReached"> <arg name="id" direction="out" type="i" /> <arg name="interval" direction="out" type="t" /> </signal> </interface> </node>kiran-session-manager-2.5.0/data/kiran-session-wayland.in0000664000175000017500000000013614417211336025022 0ustar wangyuchengwangyucheng#!/bin/sh exec @CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager --session-type=kiran-waylandkiran-session-manager-2.5.0/data/90-lightdm-kiran-greeter.conf0000664000175000017500000000004714417211336025533 0ustar wangyuchengwangyucheng[Seat:*] greeter-session=kiran-greeter kiran-session-manager-2.5.0/data/blacklist_autostart_apps.txt0000664000175000017500000000013514417211336026111 0ustar wangyuchengwangyuchengmate-screensaver.desktop mate-power-manager.desktop orca-autostart.desktop nm-applet.desktop kiran-session-manager-2.5.0/data/kiran-wayland.desktop.in0000664000175000017500000000044214417211336025011 0ustar wangyuchengwangyucheng[Desktop Entry] Name=KIRAN Comment=This session logs you into KIRAN Comment[zh_CN]=此会话将您登录到 KIRAN Exec=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-kwayland TryExec=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-kwayland Type=Application DesktopNames=KIRAN Keywords=KIRAN;session; kiran-session-manager-2.5.0/data/CMakeLists.txt0000664000175000017500000000331114417211336023006 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.2) # xxx.in -> xxx file(GLOB XXX_IN_FILES ./*.in) foreach(XXX_IN_FILE IN LISTS XXX_IN_FILES) string(REGEX REPLACE ".+/(.+)\\..*" "\\1" XXX_FILE ${XXX_IN_FILE}) configure_file(${XXX_IN_FILE} ${PROJECT_BINARY_DIR}/data/${XXX_FILE} @ONLY) endforeach() # wayland executable file install(PROGRAMS ${PROJECT_BINARY_DIR}/data/kiran-session-wayland ${PROJECT_BINARY_DIR}/data/kiran-session-kwayland DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}/) # gschema.xml install( FILES ${PROJECT_BINARY_DIR}/data/com.kylinsec.kiran.session-manager.gschema.xml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/glib-2.0/schemas/) # conf install(FILES ${PROJECT_SOURCE_DIR}/data/90-lightdm-kiran-greeter.conf DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/lightdm/lightdm.conf.d) # desktop install(FILES ${PROJECT_BINARY_DIR}/data/kiran.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/xsessions) install(FILES ${PROJECT_BINARY_DIR}/data/kiran-wayland.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/wayland-sessions) install(FILES ${PROJECT_BINARY_DIR}/data/kiran-greeter.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/xgreeters/) install(FILES ${PROJECT_BINARY_DIR}/data/kiran-session-idlemonitor.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/applications/) # txt install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/blacklist_autostart_apps.txt DESTINATION "${KSM_INSTALL_DATADIR}/") # sessions install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/sessions/kiran.session ${CMAKE_CURRENT_SOURCE_DIR}/sessions/kiran-greeter.session ${CMAKE_CURRENT_SOURCE_DIR}/sessions/kiran-wayland.session DESTINATION "${KSM_INSTALL_DATADIR}/sessions/") kiran-session-manager-2.5.0/data/kiran-session-kwayland.in0000664000175000017500000000033114417211336025172 0ustar wangyuchengwangyucheng#!/bin/sh drs= if [ -z "${DBUS_SESSION_BUS_ADDRESS}" ]; then drs=dbus-run-session fi exec ${drs} kwin_wayland --xwayland --drm --no-lockscreen --exit-with-session=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-waylandkiran-session-manager-2.5.0/data/org.gnome.SessionManager.Presence.xml0000664000175000017500000000332314417211336027346 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> <interface name="org.gnome.SessionManager.Presence"> <method name="SetStatus"> <arg type="u" name="status" direction="in"> <summary>The status value</summary> </arg> <description>Set the status value of the session.</description> </method> <method name="SetStatusText"> <arg type="s" name="status_text" direction="in"> <summary>The descriptive status for the session.</summary> </arg> <description>Set the descriptive status text for the session.</description> </method> <property name="status" type="u" access="readwrite"> <description>The status of the session.</description> </property> <property name="status_text" type="s" access="readwrite"> <description>The descriptive status for the session.</description> </property> <signal name="StatusChanged"> <arg name="status" type="u"> <summary>The new status value</summary> </arg> <description>Indicates that the session status value has changed.</description> </signal> <signal name="StatusTextChanged"> <arg name="status_text" type="s"> <summary>The new status text</summary> </arg> <description>Indicates that the descriptive session status text has changed.</description> </signal> </interface> </node> kiran-session-manager-2.5.0/data/org.gnome.SessionManager.xml0000664000175000017500000001473114417211336025610 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> <interface name="org.gnome.SessionManager"> <method name="RegisterClient"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg type="s" name="app_id" direction="in"> <summary>The application id, that commmonly is desktop filename.</summary> </arg> <arg type="s" name="client_startup_id" direction="in"> <summary>Client startup id.</summary> </arg> <arg type="o" name="client_id" direction="out"> <summary>The object path for the client allocation.</summary> </arg> <description>Register a client for the caller.</description> </method> <method name="Inhibit"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg type="s" name="app_id" direction="in"> <summary>The application id.</summary> </arg> <arg type="u" name="toplevel_xid" direction="in"> <summary>The argument is ignored.</summary> </arg> <arg type="s" name="reason" direction="in"> <summary>The reason for the inhibit.</summary> </arg> <arg type="u" name="flags" direction="in"> <summary>Specify what should be inhibited, Refer to KSMInhibitorFlag in ksm-i.h</summary> </arg> <arg type="u" name="inhibit_cookie" direction="out"> <summary>The inhibitor cookie that is used to Uninhibit.</summary> </arg> <description>Inhibit that the session manager quit(logout, shutdown, reboot), save(hibernate, suspend) and idle.</description> </method> <method name="Uninhibit"> <annotation name="org.freedesktop.DBus.GLib.Async" value=""/> <arg type="u" name="inhibit_cookie" direction="in"> <summary>The inhibitor cookie.</summary> </arg> <description>Cancel the inhibitor.</description> </method> <method name="IsInhibited"> <arg type="u" name="flags" direction="in"> <summary>Specify the inhibitor flag, Refer to KSMInhibitorFlag in ksm-i.h</summary> </arg> <arg type="b" name="is_inhibited" direction="out"> <summary>Return true if all the bit in flags is set.</summary> </arg> <description>Determine if the operation specified by flags is set.</description> </method> <method name="GetInhibitor"> <arg name="cookie" direction="in" type="u"> <summary>The inhibitor cookie.</summary> </arg> <arg name="inhibitor" direction="out" type="s"> <summary>A json string that contains inhibitor informations.</summary> </arg> <description>This gets an inhibitor that are currently known to the session manager.</description> </method> <method name="GetInhibitors"> <arg name="inhibitors" direction="out" type="s"> <summary>A json string that contain all inhibitors informations.</summary> </arg> <description>This gets a list of all the inhibitors that are currently known to the session manager.</description> </method> <method name="Shutdown"> <description>Shutdown the system.</description> </method> <method name="RequestShutdown"> <description>Shutdown the system, the interface is designed to compatible with other application.</description> </method> <method name="CanShutdown"> <arg name="is_available" direction="out" type="b"> <summary>True if shutdown is available to the user, false otherwise.</summary> </arg> <description>Whether the user can shutdown.</description> </method> <method name="Logout"> <arg name="mode" type="u" direction="in"> <summary>The argument is ignored.</summary> </arg> <description>Logout the session.</description> </method> <method name="CanLogout"> <arg name="is_available" direction="out" type="b"> <summary>True if logout is available to the user, false otherwise.</summary> </arg> <description>Whether the user can logout.</description> </method> <method name="Reboot"> <description>Reboot the system.</description> </method> <method name="RequestReboot"> <description>Reboot the system, the interface is designed to compatible with other application.</description> </method> <method name="CanReboot"> <arg name="is_available" direction="out" type="b"> <summary>True if reboot is available to the user, false otherwise</summary> </arg> <description>Whether the user can reboot.</description> </method> <method name="Setenv"> <arg name="name" type="s" direction="in"> <summary>The environment variable name</summary> </arg> <arg name="value" type="s" direction="in"> <summary>The environment variable value</summary> </arg> <description>Adds the variable name to the application launch environment with the specified value. May only be used during the Session Manager initialization phase.</description> </method> <signal name="InhibitorAdded"> <arg name="cookie" type="u"> <summary>The inhibitor cookie.</summary> </arg> <description>Emitted when an inhibitor has been added to the session manager.</description> </signal> <signal name="InhibitorRemoved"> <arg name="cookie" type="u"> <summary>The inhibitor cookie.</summary> </arg> <description>Emitted when an inhibitor has been removed from the session manager.</description> </signal> <signal name="PhaseChanged"> <arg name="phase" type="i" /> <description>The stage where session manager is in.</description> </signal> </interface> </node> kiran-session-manager-2.5.0/data/main.css0000664000175000017500000000102314417211336021702 0ustar wangyuchengwangyucheng * { font-family: "Noto Sans CJK SC"; font-size: 14px; text-shadow: none; box-shadow: none; -gtk-icon-shadow: none; -gtk-icon-effect: none; } .exit-query-mask { background: rgba(34, 34, 34, 0.6); } .exit-query-content { background: transparent; color: white; } .exit-query-inhibitors-window { background: transparent; border: none; } .exit-query-inhibitor-row { background: transparent; } .exit-query-title { font-size: 24px; } .exit-query-ok { background: #2eb3ff; }kiran-session-manager-2.5.0/data/org.gnome.SessionManager.ClientPrivate.xml0000664000175000017500000000535514417211336030362 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> <interface name="org.gnome.SessionManager.ClientPrivate"> <method name="EndSessionResponse"> <arg name="is_ok" type="b" direction="in"> <summary>Whether or not it is OK to preceed</summary> </arg> <arg name="reason" type="s" direction="in"> <summary>The reason string</summary> </arg> <description>This method should be used by the client in response to the QueryEndSession and EndSession signals.</description> </method> <signal name="Stop"> <arg name="placeholder" type="b" /> <description>The client should stop and remove itself from the session in response to this signal.</description> </signal> <signal name="QueryEndSession"> <arg name="flags" type="u"> <summary>Flags</summary> </arg> <description>This signal is used to inform the client that the session is about to end. The client must respond by calling EndSessionResponse within one second of the signal emission. If the client responds with an EndSessionResponse is-ok argument equal to FALSE and a reason then this reason may be displayed to the user. The client must not attempt to perform any actions or interact with the user in response to this signal. Any actions required for a clean shutdown should take place in response to the EndSession signal. The client should limit operations until either a EndSession or CancelEndSession signal is received.</description> </signal> <signal name="EndSession"> <arg name="flags" type="u"> <summary>Flags</summary> </arg> <description>This signal is used to inform the client that the session is about to end. The client must respond by calling EndSessionResponse within ten seconds of the signal emission. The client must not attempt to interact with the user in response to this signal. The application will be given a maxium of ten seconds to perform any actions required for a clean shutdown.</description> </signal> <signal name="CancelEndSession"> <arg name="placeholder" type="b" /> <description>This signal indicates to the client that a previous emission ofQueryEndSession has been cancelled. The client should resume normal operations.</description> </signal> </interface> </node> kiran-session-manager-2.5.0/data/sessions/0000775000175000017500000000000014417211336022116 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/data/sessions/kiran-greeter.session0000664000175000017500000000022014417211336026254 0ustar wangyuchengwangyucheng[Kiran Session] Name=Kiran Session RequiredComponents=kiran-session-idlemonitor;kiran-session-daemon;mate-settings-daemon;lightdm-kiran-greeter kiran-session-manager-2.5.0/data/sessions/kiran-wayland.session0000664000175000017500000000021314417211336026260 0ustar wangyuchengwangyucheng[Kiran Session] Name=Kiran Session RequiredComponents=kiran-session-idlemonitor;kiran-session-daemon;mate-settings-daemon;kiran-panel;caja kiran-session-manager-2.5.0/data/sessions/kiran.session0000664000175000017500000000022114417211336024622 0ustar wangyuchengwangyucheng[Kiran Session] Name=Kiran Session RequiredComponents=kiran-session-idlemonitor;kiran-session-daemon;mate-settings-daemon;marco;kiran-panel;caja kiran-session-manager-2.5.0/data/kiran-greeter.desktop.in0000664000175000017500000000051414417211336025007 0ustar wangyuchengwangyucheng[Desktop Entry] Name=KIRAN Comment=This session logs you into KIRAN Comment[zh_CN]=此会话将您登录到 KIRAN Exec=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager --session-type=kiran-greeter --autostart="" TryExec=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager Type=Application DesktopNames=KIRAN Keywords=KIRAN;session; kiran-session-manager-2.5.0/data/kiran.desktop.in0000664000175000017500000000046514417211336023361 0ustar wangyuchengwangyucheng[Desktop Entry] Name=KIRAN Comment=This session logs you into KIRAN Comment[zh_CN]=此会话将您登录到 KIRAN Exec=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager --session-type=kiran TryExec=@CMAKE_INSTALL_FULL_BINDIR@/kiran-session-manager Type=Application DesktopNames=KIRAN Keywords=KIRAN;session; kiran-session-manager-2.5.0/data/com.kylinsec.kiran.session-manager.gschema.xml.in0000664000175000017500000000067614417211336031611 0ustar wangyuchengwangyucheng<schemalist gettext-domain="@GETTEXT_PACKAGE@"> <schema id="com.kylinsec.kiran.session-manager" path="/com/kylinsec/kiran/session-manager/"> <key name="idle-delay" type="i"> <default>5</default> <summary>Time before session is considered idle</summary> <description>The number of minutes of inactivity before the session is considered idle</description> </key> </schema> </schemalist> kiran-session-manager-2.5.0/data/kiran-session-idlemonitor.desktop.in0000664000175000017500000000031014417211336027352 0ustar wangyuchengwangyucheng[Desktop Entry] Name=Kiran Session Idle Monitor Exec=/usr/bin/kiran-session-idlemonitor NoDisplay=true X-KIRAN-Autostart-Phase=PostDisplayServer X-KIRAN-Autostart-Notify=true X-KIRAN-AutoRestart=true kiran-session-manager-2.5.0/.clang-format0000664000175000017500000000775014417211336021723 0ustar wangyuchengwangyuchengBasedOnStyle: Google IndentWidth: 4 --- Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Allman BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 0 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: true DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve IncludeCategories: - Regex: '^<ext/.*\.h>' Priority: 2 - Regex: '^<.*\.h>' Priority: 1 - Regex: '^<.*' Priority: 2 - Regex: '.*' Priority: 3 IncludeIsMainRegex: '([-_](test|unittest))?$' IndentCaseLabels: false IndentPPDirectives: None IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Never ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left RawStringFormats: - Language: Cpp Delimiters: - cc - CC - cpp - Cpp - CPP - 'c++' - 'C++' CanonicalDelimiter: '' BasedOnStyle: google - Language: TextProto Delimiters: - pb - PB - proto - PROTO EnclosingFunctions: - EqualsProto - EquivToProto - PARSE_PARTIAL_TEXT_PROTO - PARSE_TEST_PROTO - PARSE_TEXT_PROTO - ParseTextOrDie - ParseTextProtoOrDie CanonicalDelimiter: '' BasedOnStyle: google ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION TabWidth: 8 UseTab: Never ... kiran-session-manager-2.5.0/config.h.in0000664000175000017500000000051514417211336021363 0ustar wangyuchengwangyucheng #pragma once #define KSM_LOCALEDIR "@CMAKE_INSTALL_FULL_DATADIR@/locale" #define KSM_INSTALL_BINDIR "@CMAKE_INSTALL_FULL_BINDIR@" #define KSM_INSTALL_DATADIR "@KSM_INSTALL_DATADIR@" #define KSM_INSTALL_TRANSLATIONDIR "@KSM_INSTALL_TRANSLATIONDIR@" #define PROJECT_NAME "@PROJECT_NAME@" #define PROJECT_VERSION "@PROJECT_VERSION@" kiran-session-manager-2.5.0/CMakeLists.txt0000664000175000017500000000200214417211336022071 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.2) project(kiran-session-manager VERSION 2.3) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(KSM REQUIRED) find_package(PkgConfig REQUIRED) find_package(Qt5 COMPONENTS Core Widgets DBus LinguistTools) find_package(KF5Config) find_package(KF5KIO) find_package(KF5IdleTime) pkg_search_module(KLOG_QT5 REQUIRED klog-qt5) pkg_search_module(GTEST REQUIRED gtest) pkg_search_module(FMT REQUIRED fmt) pkg_search_module(X11_ICE REQUIRED ice) pkg_search_module(X11_SM REQUIRED sm) pkg_search_module(XEXT REQUIRED xext) pkg_search_module(XTRANS REQUIRED xtrans) pkg_search_module(GSETTINGS_QT REQUIRED gsettings-qt) pkg_search_module(GLIB2 REQUIRED glib-2.0) pkg_search_module(KIRAN_STYLE REQUIRED kiran-style-helper) configure_file(config.h.in ${PROJECT_BINARY_DIR}/config.h) add_subdirectory(data) add_subdirectory(lib) add_subdirectory(src) # add_subdirectory(test) kiran-session-manager-2.5.0/README.md0000664000175000017500000000102214417211336020611 0ustar wangyuchengwangyucheng# KIRAN会话管理 该项目为KIRAN桌面环境的会话管理程序。 ## 编译安装 ``` # yum install cmake glibmm24-devel glib2-devel gtkmm30-devel systemd-devel gettext gcc-c++ dbus-daemon jsoncpp-devel kiran-log-gtk3-devel gdbus-codegen-glibmm fmt-devel gtest-devel libICE-devel libSM-devel # mkdir build # cd build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. # make # make install ``` ## 运行 该服务是在登陆界面选择kiran桌面环境后,由lightdm拉起,启动的配置为/usr/share/xsession/kiran.desktop kiran-session-manager-2.5.0/cmake/0000775000175000017500000000000014417211336020417 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/cmake/ksm_macros.cmake0000664000175000017500000000250614417211336023562 0ustar wangyuchengwangyuchengmacro (list_join) foreach(elem IN LISTS ${ARGV0}) string(APPEND ${ARGV2} ${ARGV1} ${elem}) endforeach() endmacro() macro(SET_COMMON_COMPILER_FLAGS) list_join(KSM_COMPILER_FLAGS " " CMAKE_CXX_FLAGS) #list_join(KSM_COMPILER_FLAGS_DEBUG " " CMAKE_CXX_FLAGS_DEBUG) #list_join(KSM_COMPILER_FLAGS_RELEASE " " CMAKE_CXX_FLAGS_RELEASE) endmacro() macro(GEN_DBUS_CPP UPPER LOWER INTERFACE_PREFIX XML_PATH) SET (${UPPER}_INTROSPECTION_XML ${XML_PATH}) SET (${UPPER}_GENERATED_CPP_FILES ${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus_stub.cpp ${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus_stub.h ${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus_common.cpp ${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus_common.h ${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus_proxy.cpp ${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus_proxy.h ) ADD_CUSTOM_COMMAND (OUTPUT ${${UPPER}_GENERATED_CPP_FILES} COMMAND mkdir -p ${CMAKE_BINARY_DIR}/generated/ COMMAND ${GDBUS_CODEGEN} --generate-cpp-code=${CMAKE_BINARY_DIR}/generated/${LOWER}_dbus --interface-prefix=${INTERFACE_PREFIX} ${${UPPER}_INTROSPECTION_XML} DEPENDS ${${UPPER}_INTROSPECTION_XML} COMMENT "Generate the stub for the ${LOWER}") endmacro() kiran-session-manager-2.5.0/cmake/ksm_variables.cmake0000664000175000017500000000064414417211336024247 0ustar wangyuchengwangyuchenginclude(GNUInstallDirs) set(KSM_INSTALL_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}) set(KSM_INSTALL_INCLUDE ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${PROJECT_NAME}) set(KSM_INSTALL_TRANSLATIONDIR ${KSM_INSTALL_DATADIR}/translations) set(GETTEXT_PACKAGE ${PROJECT_NAME}) list(APPEND KSM_COMPILER_FLAGS -Wno-parentheses # Disable parentheses warning ) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED on) kiran-session-manager-2.5.0/cmake/FindKSM.cmake0000664000175000017500000000006114417211336022651 0ustar wangyuchengwangyuchenginclude("ksm_variables") include("ksm_macros") kiran-session-manager-2.5.0/LICENSE0000664000175000017500000002276714417211336020362 0ustar wangyuchengwangyucheng 木兰宽松许可证, 第2版 木兰宽松许可证, 第2版 2020年1月 http://license.coscl.org.cn/MulanPSL2 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: 0. 定义 “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 “法人实体”是指提交贡献的机构及其“关联实体”。 “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 1. 授予版权许可 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 2. 授予专利许可 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 3. 无商标许可 “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 4. 分发限制 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 5. 免责声明与责任限制 “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 6. 语言 “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 条款结束 如何将木兰宽松许可证,第2版,应用到您的软件 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; 3, 请将如下声明文本放入每个源文件的头部注释中。 Copyright (c) [Year] [name of copyright holder] [Software Name] is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. Mulan Permissive Software License,Version 2 Mulan Permissive Software License,Version 2 (Mulan PSL v2) January 2020 http://license.coscl.org.cn/MulanPSL2 Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: 0. Definition Software means the program and related documents which are licensed under this License and comprise all Contribution(s). Contribution means the copyrightable work licensed by a particular Contributor under this License. Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. Legal Entity means the entity making a Contribution and all its Affiliates. Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. 1. Grant of Copyright License Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. 2. Grant of Patent License Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. 3. No Trademark License No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. 4. Distribution Restriction You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. 5. Disclaimer of Warranty and Limitation of Liability THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 6. Language THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. END OF THE TERMS AND CONDITIONS How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. Copyright (c) [Year] [name of copyright holder] [Software Name] is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. kiran-session-manager-2.5.0/translations/0000775000175000017500000000000014417211336022060 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/translations/kiran-session-window.mn_MN.ts0000664000175000017500000001516414417211336027534 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.ui" line="14"/> <source>MainWindow</source> <translation>MainWindow</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="73"/> <source>Closing apps</source> <translation>Хаалтын апп-ууд</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="86"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>Хэрвээ та буцаж очоод ажлаа аврахыг хүсвэл 'cancel' дарж, хийхийг хүссэн зүйлээ дуусгаарай</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="132"/> <source>Forced shutdown</source> <translation>Албадан хаах</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="145"/> <source>Cancel</source> <translation>Цуцлах</translation> </message> </context> <context> <name>InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.ui" line="14"/> <source>Form</source> <translation>Маягт</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="29"/> <source>PushButton</source> <translation type="unfinished">ПушБуттон</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="44"/> <location filename="../src/ui/inhibitor-row.ui" line="51"/> <source>TextLabel</source> <translation type="unfinished">TextLabel</translation> </message> <message> <source>Unknown application</source> <translation type="obsolete">Үл мэдэх өргөдөл</translation> </message> </context> <context> <name>Kiran::ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.cpp" line="92"/> <source>Closing %1 apps</source> <translation>Хаах %1 апп</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="93"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>Хэрвээ та буцаж очоод ажлаа аврахыг хүсвэл 'cancel' дарж, хийхийг хүссэн зүйлээ дуусгаарай</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="108"/> <source>Forced logout</source> <translation>Хүчээр логут</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="111"/> <source>Forced shutdown</source> <translation>Албадан хаах</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="114"/> <source>Forced reboot</source> <translation>Хүчээр дахин ажил хийлгэх</translation> </message> </context> <context> <name>Kiran::InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.cpp" line="45"/> <source>Unknown application</source> <translation>Үл мэдэх өргөдөл</translation> </message> </context> <context> <name>QObject</name> <message> <source>The phase cannot be register.</source> <translation type="vanished">Үе шатыг бүртгэж болохгүй.</translation> </message> <message> <source>The client %s already registered.</source> <translation type="vanished">Үйлчлүүлэгч %s аль хэдийн бүртгэгдсэн байна.</translation> </message> <message> <source>Failed to generate unique cookie.</source> <translation type="vanished">Өвөрмөц жигнэмэг хийж чадаагүй.</translation> </message> <message> <source>The inhibitor is not found.</source> <translation type="vanished">Хориглож байгаа хүн олдсонгүй.</translation> </message> <message> <source>Internal error.</source> <translation type="vanished">Дотоод алдаа.</translation> </message> <message> <source>The status is invalid.</source> <translation type="vanished">Статус нь хүчингүй.</translation> </message> <message> <source>The action is not supported.</source> <translation type="vanished">Үйлдлийг дэмждэггүй.</translation> </message> <message> <source>Unknown error.</source> <translation type="vanished">Тодорхойгүй алдаа.</translation> </message> <message> <source> (error code: 0x%x)</source> <translation type="vanished">(алдааны код: 0x%x)</translation> </message> </context> <context> <name>main</name> <message> <source>Output version information and exit.</source> <translation type="vanished">Өгөгдлийн хувилбарын мэдээлэл ба гаралт.</translation> </message> <message> <source>Specify a session type that contains required components.</source> <translation type="vanished">Шаардлагатай бүрэлдэхүүн хэсгүүдийг агуулсан хуралдааны төрлийг тодорхойл.</translation> </message> <message> <source>session type</source> <translation type="obsolete">хуралдааны төрөл</translation> </message> <message> <source>Specify a session that contains required components.</source> <translation type="vanished">Шаардлагатай бүрэлдэхүүн хэсгүүдийг агуулсан хуралдааныг тодорхойл.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="55"/> <source>Power action.</source> <translation>Хүчний үйл ажиллагаа.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="56"/> <source>power action</source> <translation>эрчим хүчний үйл ажиллагаа</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-window.ug_CN.ts0000664000175000017500000001521114417211336027514 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.ui" line="14"/> <source>MainWindow</source> <translation>MainWindow</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="73"/> <source>Closing apps</source> <translation>ئەپلەرنى تاقاش</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="86"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>ئەگەر قايتىپ خىزمىتىڭىزنى ساقلىماقچى بولسىڭىز ، «كانسېل» نى چېكىپ ، قىلماقچى بولغان ئىشىڭىزنى تاماملاڭ</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="132"/> <source>Forced shutdown</source> <translation>مەجبۇرىي تاقاش</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="145"/> <source>Cancel</source> <translation>ئەمەلدىن قالدۇرۇڭ</translation> </message> </context> <context> <name>InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.ui" line="14"/> <source>Form</source> <translation>جەدۋەل</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="29"/> <source>PushButton</source> <translation type="unfinished">PushButton</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="44"/> <location filename="../src/ui/inhibitor-row.ui" line="51"/> <source>TextLabel</source> <translation type="unfinished">TextLabel</translation> </message> <message> <source>Unknown application</source> <translation type="obsolete">نامەلۇم قوللىنىشچان پروگرامما</translation> </message> </context> <context> <name>Kiran::ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.cpp" line="92"/> <source>Closing %1 apps</source> <translation>% 1 ئەپنى تاقاش</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="93"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>ئەگەر قايتىپ خىزمىتىڭىزنى ساقلىماقچى بولسىڭىز ، «كانسېل» نى چېكىپ ، قىلماقچى بولغان ئىشىڭىزنى تاماملاڭ</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="108"/> <source>Forced logout</source> <translation>مەجبۇرىي خاتىرە</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="111"/> <source>Forced shutdown</source> <translation>مەجبۇرىي تاقاش</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="114"/> <source>Forced reboot</source> <translation>مەجبۇرىي قايتا قوزغىتىش</translation> </message> </context> <context> <name>Kiran::InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.cpp" line="45"/> <source>Unknown application</source> <translation>نامەلۇم قوللىنىشچان پروگرامما</translation> </message> </context> <context> <name>QObject</name> <message> <source>The phase cannot be register.</source> <translation type="vanished">باسقۇچنى تىزىملاتقىلى بولمايدۇ.</translation> </message> <message> <source>The client %s already registered.</source> <translation type="vanished">خېرىدار ئاللىقاچان تىزىملاتقان.</translation> </message> <message> <source>Failed to generate unique cookie.</source> <translation type="vanished">ئۆزگىچە پېچىنە ھاسىل قىلالمىدى.</translation> </message> <message> <source>The inhibitor is not found.</source> <translation type="vanished">چەكلىگۈچ تېپىلمايدۇ.</translation> </message> <message> <source>Internal error.</source> <translation type="vanished">ئىچكى خاتالىق.</translation> </message> <message> <source>The status is invalid.</source> <translation type="vanished">ئورنى ئىناۋەتسىز.</translation> </message> <message> <source>The action is not supported.</source> <translation type="vanished">بۇ ھەرىكەتنى قوللىمايدۇ.</translation> </message> <message> <source>Unknown error.</source> <translation type="vanished">نامەلۇم خاتالىق.</translation> </message> <message> <source> (error code: 0x%x)</source> <translation type="vanished">( خاتالىق كودى: 0x% x )</translation> </message> </context> <context> <name>main</name> <message> <source>Output version information and exit.</source> <translation type="vanished">چىقىرىش نۇسخىسى ئۇچۇرى ۋە چىقىش ئېغىزى.</translation> </message> <message> <source>Specify a session type that contains required components.</source> <translation type="vanished">لازىملىق زاپچاسلارنى ئۆز ئىچىگە ئالغان يىغىن تۈرىنى بەلگىلەڭ.</translation> </message> <message> <source>session type</source> <translation type="obsolete">يىغىن تىپى</translation> </message> <message> <source>Specify a session that contains required components.</source> <translation type="vanished">لازىملىق زاپچاسلارنى ئۆز ئىچىگە ئالغان يىغىننى بەلگىلەڭ.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="55"/> <source>Power action.</source> <translation>كۈچ ھەرىكىتى.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="56"/> <source>power action</source> <translation>كۈچ ھەرىكىتى</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-window.kk_KZ.ts0000664000175000017500000001512214417211336027533 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.ui" line="14"/> <source>MainWindow</source> <translation>& Басты терезе</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="73"/> <source>Closing apps</source> <translation>Бағдарламаны жабу</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="86"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>Егер сіз жұмысты қайтарып, сақтағыңыз келсе, Болдырмау түймесін басып, қажетті әрекетті аяқтаңыз</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="132"/> <source>Forced shutdown</source> <translation>Мәжбүрлеп өшіру</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="145"/> <source>Cancel</source> <translation>Бас тарту</translation> </message> </context> <context> <name>InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.ui" line="14"/> <source>Form</source> <translation>Пішіні</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="29"/> <source>PushButton</source> <translation type="unfinished">& Түймешік</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="44"/> <location filename="../src/ui/inhibitor-row.ui" line="51"/> <source>TextLabel</source> <translation type="unfinished">Мәтін тегтері</translation> </message> <message> <source>Unknown application</source> <translation type="obsolete">Беймәлім қолданба</translation> </message> </context> <context> <name>Kiran::ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.cpp" line="92"/> <source>Closing %1 apps</source> <translation>% 1 қолданбаны жабу</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="93"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>Егер сіз жұмысты қайтарып, сақтағыңыз келсе, Болдырмау түймесін басып, қажетті әрекетті аяқтаңыз</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="108"/> <source>Forced logout</source> <translation>Мәжбүрлеп жою</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="111"/> <source>Forced shutdown</source> <translation>Мәжбүрлеп өшіру</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="114"/> <source>Forced reboot</source> <translation>Мәжбүрлеп қайта қосу</translation> </message> </context> <context> <name>Kiran::InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.cpp" line="45"/> <source>Unknown application</source> <translation>Беймәлім қолданба</translation> </message> </context> <context> <name>QObject</name> <message> <source>The phase cannot be register.</source> <translation type="vanished">Бұл кезеңге тіркелу мүмкін емес.</translation> </message> <message> <source>The client %s already registered.</source> <translation type="vanished">% s клиенті тіркелген.</translation> </message> <message> <source>Failed to generate unique cookie.</source> <translation type="vanished">Бірегей cookie файлдарын жасау мүмкін емес.</translation> </message> <message> <source>The inhibitor is not found.</source> <translation type="vanished">Ингибитор табылмады.</translation> </message> <message> <source>Internal error.</source> <translation type="vanished">Ішкі қате.</translation> </message> <message> <source>The status is invalid.</source> <translation type="vanished">Күй жарамсыз.</translation> </message> <message> <source>The action is not supported.</source> <translation type="vanished">Бұл әрекетке қолдау көрсетілмейді.</translation> </message> <message> <source>Unknown error.</source> <translation type="vanished">Беймәлім қате.</translation> </message> <message> <source> (error code: 0x%x)</source> <translation type="vanished">(Қате коды: 0x%)</translation> </message> </context> <context> <name>main</name> <message> <source>Output version information and exit.</source> <translation type="vanished">Нұсқа туралы ақпаратты шығарыңыз және шығыңыз.</translation> </message> <message> <source>Specify a session type that contains required components.</source> <translation type="vanished">Қажетті компоненттері бар сеанстың түрін анықтайды.</translation> </message> <message> <source>session type</source> <translation type="obsolete">Сеанс түрі</translation> </message> <message> <source>Specify a session that contains required components.</source> <translation type="vanished">Қажетті компоненттері бар сеансты анықтайды.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="55"/> <source>Power action.</source> <translation>Динамикалық әрекет.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="56"/> <source>power action</source> <translation>Динамикалық әсер</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-window.kk_KG.ts0000664000175000017500000001527214417211336027516 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.ui" line="14"/> <source>MainWindow</source> <translation>MainWindow</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="73"/> <source>Closing apps</source> <translation>Колдонмолорду жабуу</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="86"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>Эгер артка кайтып, жумушуңузду сактап калгыңыз келсе, "жокко чыгаруу" баскычын чыкылдатып, эмне кылгыңыз келсе, ошону аягына чыгарыңыз</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="132"/> <source>Forced shutdown</source> <translation>Аргасыз өчүрүү</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="145"/> <source>Cancel</source> <translation>жокко чыгаруу</translation> </message> </context> <context> <name>InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.ui" line="14"/> <source>Form</source> <translation>форма</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="29"/> <source>PushButton</source> <translation type="unfinished">PushButton</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="44"/> <location filename="../src/ui/inhibitor-row.ui" line="51"/> <source>TextLabel</source> <translation type="unfinished">TextLabel</translation> </message> <message> <source>Unknown application</source> <translation type="obsolete">Белгисиз колдонмо</translation> </message> </context> <context> <name>Kiran::ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.cpp" line="92"/> <source>Closing %1 apps</source> <translation>% 1 колдонмолорун жабуу</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="93"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>Эгер артка кайтып, жумушуңузду сактап калгыңыз келсе, "жокко чыгаруу" баскычын чыкылдатып, эмне кылгыңыз келсе, ошону аягына чыгарыңыз</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="108"/> <source>Forced logout</source> <translation>Аргасыз чыгуу</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="111"/> <source>Forced shutdown</source> <translation>Аргасыз өчүрүү</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="114"/> <source>Forced reboot</source> <translation>Аргасыз кайра жүктөө</translation> </message> </context> <context> <name>Kiran::InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.cpp" line="45"/> <source>Unknown application</source> <translation>Белгисиз колдонмо</translation> </message> </context> <context> <name>QObject</name> <message> <source>The phase cannot be register.</source> <translation type="vanished">Фаза катталбайт.</translation> </message> <message> <source>The client %s already registered.</source> <translation type="vanished">Кардар% s мурунтан эле катталган.</translation> </message> <message> <source>Failed to generate unique cookie.</source> <translation type="vanished">Уникалдуу куки жарата алган жок.</translation> </message> <message> <source>The inhibitor is not found.</source> <translation type="vanished">Ингибитор табылган жок.</translation> </message> <message> <source>Internal error.</source> <translation type="vanished">Ички ката.</translation> </message> <message> <source>The status is invalid.</source> <translation type="vanished">Статус жараксыз.</translation> </message> <message> <source>The action is not supported.</source> <translation type="vanished">Акция колдоого алынбайт.</translation> </message> <message> <source>Unknown error.</source> <translation type="vanished">Белгисиз ката.</translation> </message> <message> <source> (error code: 0x%x)</source> <translation type="vanished">( ката коду: 0x% x )</translation> </message> </context> <context> <name>main</name> <message> <source>Output version information and exit.</source> <translation type="vanished">Чыгуу нускасы жөнүндө маалымат жана чыгуу.</translation> </message> <message> <source>Specify a session type that contains required components.</source> <translation type="vanished">Керектүү компоненттерди камтыган сессиянын түрүн белгилеңиз.</translation> </message> <message> <source>session type</source> <translation type="obsolete">сессия түрү</translation> </message> <message> <source>Specify a session that contains required components.</source> <translation type="vanished">Керектүү компоненттерди камтыган сессияны белгилеңиз.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="55"/> <source>Power action.</source> <translation>Кубат аракети.</translation> </message> <message> <location filename="../src/ui/main.cpp" line="56"/> <source>power action</source> <translation>күч аракет</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-manager.bo_CN.ts0000664000175000017500000000723014417211336027606 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>Kiran::SessionManager</name> <message> <location filename="../src/core/session-manager.cpp" line="295"/> <source>This program is not responding</source> <translation>གོ་རིམ་འདི་ལ་ལན་མི་འདེབས།</translation> </message> <message> <location filename="../src/core/session-manager.cpp" line="393"/> <source>This program is blocking exit</source> <translation>གོ་རིམ་འདིས་ཕྱིར་གཏོང་བྱེད་པར་བཀག་འགོག་བྱེད</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="../lib/base/error.cpp" line="32"/> <source>The phase cannot be register.</source> <translation>དུས་རིམ་དེ་ཐོ་འགོད་བྱེད་མི་ཐུབ།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="34"/> <source>The client %s already registered.</source> <translation>མངགས་བཅོལ་བྱེད་མཁན་གྱིས་ཐོ་འགོད་བྱས་ཟིན།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="37"/> <source>Failed to generate unique cookie.</source> <translation>ཐུན་མོང་མ་ཡིན་པའི་ཀ་ར་གོ་རེ་ཐོན་སྐྱེད་བྱེད་མ་ཐུབ</translation> </message> <message> <location filename="../lib/base/error.cpp" line="40"/> <source>The inhibitor is not found.</source> <translation>ཚོད་འཛིན་ཡོ་བྱད་མ་རྙེད།།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="49"/> <source>Internal error.</source> <translation>ནང་ཁུལ་གྱི་ནོར་འཁྲུལ།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="43"/> <source>The status is invalid.</source> <translation>གོ་མི་ཆོད་པའི་གནས་ཚུལ་བྱུང་བ་རེད།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="46"/> <source>The action is not supported.</source> <translation>བྱ་སྤྱོད་དེར་རྒྱབ་སྐྱོར་མི་བྱེད།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="52"/> <source>Unknown error.</source> <translation>ཤེས་མེད་པའི་ནོར་འཁྲུལ།</translation> </message> <message> <location filename="../lib/base/error.cpp" line="57"/> <source> (error code: 0x%x)</source> <translation>(ནོར་འཁྲུལ་གྱི་ཚབ་རྟགས་ 0x%x)</translation> </message> </context> <context> <name>main</name> <message> <location filename="../src/core/main.cpp" line="125"/> <source>Specify a session type that contains required components.</source> <translation>指定指定组件,指定组件类型。</translation> </message> <message> <location filename="../src/core/main.cpp" line="126"/> <source>session type</source> <translation>ཚོགས་འདུའི་རིགས་དབྱིབས།</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-manager.kk_KZ.ts0000664000175000017500000000617314417211336027644 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>Kiran::SessionManager</name> <message> <location filename="../src/core/session-manager.cpp" line="295"/> <source>This program is not responding</source> <translation>Бұл бағдарлама жауап бермейді</translation> </message> <message> <location filename="../src/core/session-manager.cpp" line="393"/> <source>This program is blocking exit</source> <translation>Бұл бағдарлама шығуды болдырмайды</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="../lib/base/error.cpp" line="32"/> <source>The phase cannot be register.</source> <translation>Бұл кезеңге тіркелу мүмкін емес.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="34"/> <source>The client %s already registered.</source> <translation>% s клиенті тіркелген.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="37"/> <source>Failed to generate unique cookie.</source> <translation>Бірегей cookie файлдарын жасау мүмкін емес.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="40"/> <source>The inhibitor is not found.</source> <translation>Ингибитор табылмады.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="49"/> <source>Internal error.</source> <translation>Ішкі қате.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="43"/> <source>The status is invalid.</source> <translation>Күй жарамсыз.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="46"/> <source>The action is not supported.</source> <translation>Бұл әрекетке қолдау көрсетілмейді.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="52"/> <source>Unknown error.</source> <translation>Беймәлім қате.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="57"/> <source> (error code: 0x%x)</source> <translation>(Қате коды: 0x%)</translation> </message> </context> <context> <name>main</name> <message> <location filename="../src/core/main.cpp" line="125"/> <source>Specify a session type that contains required components.</source> <translation>Қажетті компоненттері бар сеанстың түрін анықтайды.</translation> </message> <message> <location filename="../src/core/main.cpp" line="126"/> <source>session type</source> <translation>Сеанс түрі</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-manager.mn_MN.ts0000664000175000017500000000633114417211336027633 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>Kiran::SessionManager</name> <message> <location filename="../src/core/session-manager.cpp" line="295"/> <source>This program is not responding</source> <translation>Энэ хөтөлбөр хариу өгөхгүй байна</translation> </message> <message> <location filename="../src/core/session-manager.cpp" line="393"/> <source>This program is blocking exit</source> <translation>Энэ хөтөлбөр гарахыг хааж байна</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="../lib/base/error.cpp" line="32"/> <source>The phase cannot be register.</source> <translation>Үе шатыг бүртгэж болохгүй.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="34"/> <source>The client %s already registered.</source> <translation>Үйлчлүүлэгч %s аль хэдийн бүртгэгдсэн байна.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="37"/> <source>Failed to generate unique cookie.</source> <translation>Өвөрмөц жигнэмэг хийж чадаагүй.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="40"/> <source>The inhibitor is not found.</source> <translation>Хориглож байгаа хүн олдсонгүй.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="49"/> <source>Internal error.</source> <translation>Дотоод алдаа.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="43"/> <source>The status is invalid.</source> <translation>Статус нь хүчингүй.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="46"/> <source>The action is not supported.</source> <translation>Үйлдлийг дэмждэггүй.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="52"/> <source>Unknown error.</source> <translation>Тодорхойгүй алдаа.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="57"/> <source> (error code: 0x%x)</source> <translation>(алдааны код: 0x%x)</translation> </message> </context> <context> <name>main</name> <message> <location filename="../src/core/main.cpp" line="125"/> <source>Specify a session type that contains required components.</source> <translation>Шаардлагатай бүрэлдэхүүн хэсгүүдийг агуулсан хуралдааны төрлийг тодорхойл.</translation> </message> <message> <location filename="../src/core/main.cpp" line="126"/> <source>session type</source> <translation>хуралдааны төрөл</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-window.zh_CN.ts0000664000175000017500000001370614417211336027531 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="zh_CN"> <context> <name>ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.ui" line="14"/> <source>MainWindow</source> <translation>主窗口</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="73"/> <source>Closing apps</source> <translation>正在关闭应用</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="86"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>如果想要返回并保存你的工作,可单击'取消',然后完成你要执行的操作</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="132"/> <source>Forced shutdown</source> <translation>强制关机</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="145"/> <source>Cancel</source> <translation>取消</translation> </message> </context> <context> <name>InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.ui" line="14"/> <source>Form</source> <translation>Form</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="29"/> <source>PushButton</source> <translation type="unfinished"></translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="44"/> <location filename="../src/ui/inhibitor-row.ui" line="51"/> <source>TextLabel</source> <translation type="unfinished"></translation> </message> <message> <source>Unknown application</source> <translation type="obsolete">未知应用</translation> </message> </context> <context> <name>Kiran::ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.cpp" line="92"/> <source>Closing %1 apps</source> <translation>正在关闭%1个应用程序</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="93"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>如果想要返回并保存你的工作,可单击'取消',然后完成你要执行的操作</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="108"/> <source>Forced logout</source> <translation>强制注销</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="111"/> <source>Forced shutdown</source> <translation>强制关机</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="114"/> <source>Forced reboot</source> <translation>强制重启</translation> </message> </context> <context> <name>Kiran::InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.cpp" line="45"/> <source>Unknown application</source> <translation>未知应用</translation> </message> </context> <context> <name>QObject</name> <message> <source>The phase cannot be register.</source> <translation type="vanished">该阶段不允许注册。</translation> </message> <message> <source>The client %s already registered.</source> <translation type="vanished">客户端 %s 已经注册。</translation> </message> <message> <source>Failed to generate unique cookie.</source> <translation type="vanished">生成cookie失败。</translation> </message> <message> <source>The inhibitor is not found.</source> <translation type="vanished">抑制器未发现。</translation> </message> <message> <source>Internal error.</source> <translation type="vanished">内部错误。</translation> </message> <message> <source>The status is invalid.</source> <translation type="vanished">状态不合法。</translation> </message> <message> <source>The action is not supported.</source> <translation type="vanished">操作不支持。</translation> </message> <message> <source>Unknown error.</source> <translation type="vanished">未知错误。</translation> </message> <message> <source> (error code: 0x%x)</source> <translation type="vanished"> (错误码: 0x%x)</translation> </message> </context> <context> <name>main</name> <message> <source>Output version information and exit.</source> <translation type="vanished">输出版本信息并退出。</translation> </message> <message> <source>Specify a session type that contains required components.</source> <translation type="vanished">指定一个会话类型,该会话类型包含需要加载的组件列表。</translation> </message> <message> <source>session type</source> <translation type="obsolete">会话类型</translation> </message> <message> <source>Specify a session that contains required components.</source> <translation type="vanished">指定一个会话,该会话包含需要加载的组件列表。</translation> </message> <message> <location filename="../src/ui/main.cpp" line="55"/> <source>Power action.</source> <translation>电源动作</translation> </message> <message> <location filename="../src/ui/main.cpp" line="56"/> <source>power action</source> <translation>电源动作</translation> </message> </context> </TS> kiran-session-manager-2.5.0/translations/kiran-session-window.bo_CN.ts0000664000175000017500000001750014417211336027504 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.ui" line="14"/> <source>MainWindow</source> <translation>རླུང་གཙོ་བོ།</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="73"/> <source>Closing apps</source> <translation>སྒོ་རྒྱག་ཉེར་སྤྱོད།</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="86"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>གལ་ཏེ་ཕྱིར་སོང་ནས་ལས་ཀ་གྲོན་ཆུང་བྱེད་འདོད་ན། "མེད་པར་བཟོ་བ་"མནན་ནས་རང་ཉིད་ཀྱིས་བསྒྲུབ་འདོད་པའི་བྱ་བ་བསྒྲུབས་ཚར།</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="132"/> <source>Forced shutdown</source> <translation>བཙན་ཤེད་ཀྱིས་ལས་མཚམས་</translation> </message> <message> <location filename="../src/ui/exit-query-window.ui" line="145"/> <source>Cancel</source> <translation>ཕྱིར་འཐེན།</translation> </message> </context> <context> <name>InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.ui" line="14"/> <source>Form</source> <translation>རྣམ་པ།</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="29"/> <source>PushButton</source> <translation type="unfinished">སྐུལ་འདེད་པུའུ་ཏུན།</translation> </message> <message> <location filename="../src/ui/inhibitor-row.ui" line="44"/> <location filename="../src/ui/inhibitor-row.ui" line="51"/> <source>TextLabel</source> <translation type="unfinished">ཡི་གེ་ལ་པེར་གྱིས་བཤད་རྒྱུར</translation> </message> <message> <source>Unknown application</source> <translation type="obsolete">ཤེས་མེད་པའི་ཉེར་སྤྱོད།</translation> </message> </context> <context> <name>Kiran::ExitQueryWindow</name> <message> <location filename="../src/ui/exit-query-window.cpp" line="92"/> <source>Closing %1 apps</source> <translation>%1 ཉེར་སྤྱོད་གོ་རིམ་མཇུག་སྒྲིལ་བ།</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="93"/> <source>If you want to go back and save your work, click 'cancel' and finish what you want to do</source> <translation>གལ་ཏེ་ཕྱིར་སོང་ནས་ལས་ཀ་གྲོན་ཆུང་བྱེད་འདོད་ན། "མེད་པར་བཟོ་བ་"མནན་ནས་རང་ཉིད་ཀྱིས་བསྒྲུབ་འདོད་པའི་བྱ་བ་བསྒྲུབས་ཚར།</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="108"/> <source>Forced logout</source> <translation>བཙན་ཤེད་ཀྱིས་ཐོ་འགོད་བྱེད་</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="111"/> <source>Forced shutdown</source> <translation>བཙན་ཤེད་ཀྱིས་ལས་མཚམས་</translation> </message> <message> <location filename="../src/ui/exit-query-window.cpp" line="114"/> <source>Forced reboot</source> <translation>བཙན་ཤེད་ཀྱིས་བསྐྱར་དུ་ཕྱིར་འཐེན་བྱེད་</translation> </message> </context> <context> <name>Kiran::InhibitorRow</name> <message> <location filename="../src/ui/inhibitor-row.cpp" line="45"/> <source>Unknown application</source> <translation>ཤེས་མེད་པའི་ཉེར་སྤྱོད།</translation> </message> </context> <context> <name>QObject</name> <message> <source>The phase cannot be register.</source> <translation type="vanished">དུས་རིམ་དེ་ཐོ་འགོད་བྱེད་མི་ཐུབ།</translation> </message> <message> <source>The client %s already registered.</source> <translation type="vanished">མངགས་བཅོལ་བྱེད་མཁན་གྱིས་ཐོ་འགོད་བྱས་ཟིན།</translation> </message> <message> <source>Failed to generate unique cookie.</source> <translation type="vanished">ཐུན་མོང་མ་ཡིན་པའི་ཀ་ར་གོ་རེ་ཐོན་སྐྱེད་བྱེད་མ་ཐུབ</translation> </message> <message> <source>The inhibitor is not found.</source> <translation type="vanished">ཚོད་འཛིན་ཡོ་བྱད་མ་རྙེད།།</translation> </message> <message> <source>Internal error.</source> <translation type="vanished">ནང་ཁུལ་གྱི་ནོར་འཁྲུལ།</translation> </message> <message> <source>The status is invalid.</source> <translation type="vanished">གོ་མི་ཆོད་པའི་གནས་ཚུལ་བྱུང་བ་རེད།</translation> </message> <message> <source>The action is not supported.</source> <translation type="vanished">བྱ་སྤྱོད་དེར་རྒྱབ་སྐྱོར་མི་བྱེད།</translation> </message> <message> <source>Unknown error.</source> <translation type="vanished">ཤེས་མེད་པའི་ནོར་འཁྲུལ།</translation> </message> <message> <source> (error code: 0x%x)</source> <translation type="vanished">(ནོར་འཁྲུལ་གྱི་ཚབ་རྟགས་ 0x%x)</translation> </message> </context> <context> <name>main</name> <message> <source>Output version information and exit.</source> <translation type="vanished">ཐོན་རྫས་ཀྱི་པར་གཞིའི་ཆ་འཕྲིན་དང་ཕྱིར་གཏོང་།</translation> </message> <message> <source>Specify a session type that contains required components.</source> <translation type="vanished">指定指定组件,指定组件类型。</translation> </message> <message> <source>session type</source> <translation type="obsolete">ཚོགས་འདུའི་རིགས་དབྱིབས།</translation> </message> <message> <source>Specify a session that contains required components.</source> <translation type="vanished">指定组件。。</translation> </message> <message> <location filename="../src/ui/main.cpp" line="55"/> <source>Power action.</source> <translation>དབང་ཆའི་བྱ་སྤྱོད།</translation> </message> <message> <location filename="../src/ui/main.cpp" line="56"/> <source>power action</source> <translation>སྒུལ་ཤུགས་ཀྱི་བྱ་སྤྱོད།</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-manager.zh_CN.ts0000664000175000017500000000555614417211336027640 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1" language="zh_CN"> <context> <name>Kiran::SessionManager</name> <message> <location filename="../src/core/session-manager.cpp" line="295"/> <source>This program is not responding</source> <translation>程序未响应</translation> </message> <message> <location filename="../src/core/session-manager.cpp" line="393"/> <source>This program is blocking exit</source> <translation>程序正在阻止退出</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="../lib/base/error.cpp" line="32"/> <source>The phase cannot be register.</source> <translation>该阶段不允许注册。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="34"/> <source>The client %s already registered.</source> <translation>客户端 %s 已经注册。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="37"/> <source>Failed to generate unique cookie.</source> <translation>生成cookie失败。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="40"/> <source>The inhibitor is not found.</source> <translation>抑制器未发现。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="49"/> <source>Internal error.</source> <translation>内部错误。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="43"/> <source>The status is invalid.</source> <translation>状态不合法。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="46"/> <source>The action is not supported.</source> <translation>操作不支持。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="52"/> <source>Unknown error.</source> <translation>未知错误。</translation> </message> <message> <location filename="../lib/base/error.cpp" line="57"/> <source> (error code: 0x%x)</source> <translation> (错误码: 0x%x)</translation> </message> </context> <context> <name>main</name> <message> <location filename="../src/core/main.cpp" line="125"/> <source>Specify a session type that contains required components.</source> <translation>指定一个会话类型,该会话类型包含需要加载的组件列表。</translation> </message> <message> <location filename="../src/core/main.cpp" line="126"/> <source>session type</source> <translation>会话类型</translation> </message> </context> </TS> kiran-session-manager-2.5.0/translations/kiran-session-manager.kk_KG.ts0000664000175000017500000000616314417211336027620 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>Kiran::SessionManager</name> <message> <location filename="../src/core/session-manager.cpp" line="295"/> <source>This program is not responding</source> <translation>Бул программа жооп бербейт</translation> </message> <message> <location filename="../src/core/session-manager.cpp" line="393"/> <source>This program is blocking exit</source> <translation>Бул программа чыгууну бөгөттөп жатат</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="../lib/base/error.cpp" line="32"/> <source>The phase cannot be register.</source> <translation>Фаза катталбайт.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="34"/> <source>The client %s already registered.</source> <translation>Кардар% s мурунтан эле катталган.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="37"/> <source>Failed to generate unique cookie.</source> <translation>Уникалдуу куки жарата алган жок.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="40"/> <source>The inhibitor is not found.</source> <translation>Ингибитор табылган жок.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="49"/> <source>Internal error.</source> <translation>Ички ката.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="43"/> <source>The status is invalid.</source> <translation>Статус жараксыз.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="46"/> <source>The action is not supported.</source> <translation>Акция колдоого алынбайт.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="52"/> <source>Unknown error.</source> <translation>Белгисиз ката.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="57"/> <source> (error code: 0x%x)</source> <translation>( ката коду: 0x% x )</translation> </message> </context> <context> <name>main</name> <message> <location filename="../src/core/main.cpp" line="125"/> <source>Specify a session type that contains required components.</source> <translation>Керектүү компоненттерди камтыган сессиянын түрүн белгилеңиз.</translation> </message> <message> <location filename="../src/core/main.cpp" line="126"/> <source>session type</source> <translation>сессия түрү</translation> </message> </context> </TS>kiran-session-manager-2.5.0/translations/kiran-session-manager.ug_CN.ts0000664000175000017500000000623114417211336027621 0ustar wangyuchengwangyucheng<?xml version="1.0" ?><!DOCTYPE TS><TS version="2.1" language="zh_CN"> <context> <name>Kiran::SessionManager</name> <message> <location filename="../src/core/session-manager.cpp" line="295"/> <source>This program is not responding</source> <translation>بۇ پروگرامما ئىنكاس قايتۇرمايدۇ</translation> </message> <message> <location filename="../src/core/session-manager.cpp" line="393"/> <source>This program is blocking exit</source> <translation>بۇ پروگرامما چېكىنىشنى توسىدۇ</translation> </message> </context> <context> <name>QObject</name> <message> <location filename="../lib/base/error.cpp" line="32"/> <source>The phase cannot be register.</source> <translation>باسقۇچنى تىزىملاتقىلى بولمايدۇ.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="34"/> <source>The client %s already registered.</source> <translation>خېرىدار ئاللىقاچان تىزىملاتقان.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="37"/> <source>Failed to generate unique cookie.</source> <translation>ئۆزگىچە پېچىنە ھاسىل قىلالمىدى.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="40"/> <source>The inhibitor is not found.</source> <translation>چەكلىگۈچ تېپىلمايدۇ.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="49"/> <source>Internal error.</source> <translation>ئىچكى خاتالىق.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="43"/> <source>The status is invalid.</source> <translation>ئورنى ئىناۋەتسىز.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="46"/> <source>The action is not supported.</source> <translation>بۇ ھەرىكەتنى قوللىمايدۇ.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="52"/> <source>Unknown error.</source> <translation>نامەلۇم خاتالىق.</translation> </message> <message> <location filename="../lib/base/error.cpp" line="57"/> <source> (error code: 0x%x)</source> <translation>( خاتالىق كودى: 0x% x )</translation> </message> </context> <context> <name>main</name> <message> <location filename="../src/core/main.cpp" line="125"/> <source>Specify a session type that contains required components.</source> <translation>لازىملىق زاپچاسلارنى ئۆز ئىچىگە ئالغان يىغىن تۈرىنى بەلگىلەڭ.</translation> </message> <message> <location filename="../src/core/main.cpp" line="126"/> <source>session type</source> <translation>يىغىن تىپى</translation> </message> </context> </TS>kiran-session-manager-2.5.0/resources/0000775000175000017500000000000014417211336021351 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/resources/images/0000775000175000017500000000000014417211336022616 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/resources/images/app-missing.svg0000664000175000017500000013272714417211336025602 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.0" width="96" height="96" id="svg2408"> <defs id="defs2410"> <linearGradient id="linearGradient4384"> <stop id="stop4386" style="stop-color:#ffffff;stop-opacity:1" offset="0" /> <stop id="stop4388" style="stop-color:#ffffff;stop-opacity:0" offset="1" /> </linearGradient> <linearGradient id="linearGradient4367"> <stop id="stop4369" style="stop-color:#ffffff;stop-opacity:0.71755725" offset="0" /> <stop id="stop4371" style="stop-color:#ffffff;stop-opacity:1" offset="1" /> </linearGradient> <linearGradient x1="45.447727" y1="92.539597" x2="45.447727" y2="7.0165396" id="ButtonShadow" gradientUnits="userSpaceOnUse" gradientTransform="scale(1.0058652,0.994169)"> <stop id="stop3750" style="stop-color:#000000;stop-opacity:1" offset="0" /> <stop id="stop3752" style="stop-color:#000000;stop-opacity:0.58823532" offset="1" /> </linearGradient> <linearGradient id="linearGradient3737"> <stop id="stop3739" style="stop-color:#ffffff;stop-opacity:1" offset="0" /> <stop id="stop3741" style="stop-color:#ffffff;stop-opacity:0" offset="1" /> </linearGradient> <filter color-interpolation-filters="sRGB" id="filter3174"> <feGaussianBlur id="feGaussianBlur3176" stdDeviation="1.71" /> </filter> <filter x="-0.192" y="-0.192" width="1.3839999" height="1.3839999" color-interpolation-filters="sRGB" id="filter3794"> <feGaussianBlur id="feGaussianBlur3796" stdDeviation="5.28" /> </filter> <linearGradient x1="48" y1="20.220806" x2="48" y2="138.66119" id="linearGradient3613" xlink:href="#linearGradient3737" gradientUnits="userSpaceOnUse" /> <linearGradient x1="45.447727" y1="92.539597" x2="45.447727" y2="7.0165396" id="ButtonShadow-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0058652,0,0,0.994169,100,0)"> <stop id="stop3750-8" style="stop-color:#000000;stop-opacity:1" offset="0" /> <stop id="stop3752-5" style="stop-color:#000000;stop-opacity:0.58823532" offset="1" /> </linearGradient> <linearGradient x1="32.251034" y1="6.1317081" x2="32.251034" y2="90.238609" id="linearGradient3780" xlink:href="#ButtonShadow-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" /> <linearGradient x1="32.251034" y1="6.1317081" x2="32.251034" y2="90.238609" id="linearGradient3772" xlink:href="#ButtonShadow-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" /> <linearGradient x1="32.251034" y1="6.1317081" x2="32.251034" y2="90.238609" id="linearGradient3725" xlink:href="#ButtonShadow-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" /> <linearGradient x1="32.251034" y1="6.1317081" x2="32.251034" y2="90.238609" id="linearGradient3721" xlink:href="#ButtonShadow-0" gradientUnits="userSpaceOnUse" gradientTransform="translate(0,-97)" /> <linearGradient x1="32.251034" y1="6.1317081" x2="32.251034" y2="90.238609" id="linearGradient3026" xlink:href="#ButtonShadow-0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" /> <clipPath id="clipPath4355"> <rect width="84" height="80" rx="6" ry="6" x="6" y="6" id="rect4357" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /> </clipPath> <radialGradient cx="48" cy="87.792389" r="42" fx="48" fy="87.792389" id="radialGradient4375" xlink:href="#linearGradient4367" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,-6.7114942e-8,8.4282233e-8,1.2557894,109.99999,-24.505592)" /> <linearGradient x1="48" y1="88" x2="48" y2="-40" id="linearGradient4390" xlink:href="#linearGradient4384" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,-1,0,92)" /> <linearGradient x1="48" y1="82" x2="112.12357" y2="82.454597" id="linearGradient4429" xlink:href="#linearGradient4384" gradientUnits="userSpaceOnUse" spreadMethod="reflect" /> <linearGradient id="linearGradient3892"> <stop id="stop3894" style="stop-color:#000000;stop-opacity:0.58823532" offset="0" /> <stop id="stop3896" style="stop-color:#000000;stop-opacity:0.47058824" offset="0.11780351" /> <stop id="stop3898" style="stop-color:#000000;stop-opacity:0.39215687" offset="0.23809524" /> <stop id="stop3900" style="stop-color:#000000;stop-opacity:0.3137255" offset="1" /> </linearGradient> <linearGradient x1="90" y1="88" x2="48" y2="88" id="linearGradient3228" xlink:href="#linearGradient3892" gradientUnits="userSpaceOnUse" spreadMethod="reflect" /> <linearGradient x1="10.31979" y1="21" x2="10.31979" y2="0.99929649" id="ButtonColor-7" gradientUnits="userSpaceOnUse"> <stop id="stop3189" style="stop-color:#787878;stop-opacity:1" offset="0" /> <stop id="stop3191" style="stop-color:#b4b4b4;stop-opacity:1" offset="1" /> </linearGradient> <linearGradient x1="48" y1="90" x2="48" y2="5.9877172" id="linearGradient3161" xlink:href="#ButtonColor-7" gradientUnits="userSpaceOnUse" /> <clipPath id="clipPath4403"> <path d="m 30.916245,135.971 c -0.937266,0.54113 -1.228304,1.74752 -0.677924,2.7008 l 1.9375,3.35585 c -1.418086,1.4141 -2.622273,3.01198 -3.595451,4.71 l -3.783634,-0.99095 c -0.531629,-0.14245 -1.037926,-0.11751 -1.476221,0.13061 -0.438159,0.24835 -0.796545,0.66758 -0.936598,1.19027 l -1.978825,7.38507 c -0.280102,1.04538 0.365953,2.06538 1.429126,2.35032 l 3.772195,1.03363 c -0.0062,1.95711 0.237711,3.94301 0.758755,5.87671 l -3.355849,1.9375 c -0.95328,0.55037 -1.304431,1.74066 -0.763301,2.67792 l 3.8125,6.60344 c 0.54113,0.93727 1.747521,1.2283 2.700801,0.67793 l 3.355849,-1.9375 c 1.414106,1.41808 3.011983,2.62227 4.709995,3.59545 l -0.990945,3.78363 c -0.284894,1.06325 0.275431,2.13275 1.320874,2.41282 l 7.385075,1.97883 c 1.045371,0.28011 2.065425,-0.36588 2.35032,-1.42913 l 1.033633,-3.77219 c 1.957118,0.006 3.943015,-0.23771 5.876701,-0.75876 l 1.9375,3.35585 c 0.550375,0.95328 1.740658,1.30443 2.677924,0.7633 l 6.603444,-3.8125 c 0.937258,-0.54113 1.228299,-1.74752 0.677924,-2.7008 l -1.9375,-3.35585 c 1.418087,-1.4141 2.622272,-3.01197 3.595452,-4.70999 l 3.783633,0.99094 c 1.063244,0.2849 2.132709,-0.27549 2.41282,-1.32087 l 1.978825,-7.38508 c 0.280102,-1.04537 -0.365953,-2.06538 -1.429127,-2.35032 l -3.772195,-1.03363 c 0.0062,-1.95711 -0.237701,-3.94301 -0.758754,-5.8767 l 3.355848,-1.9375 c 0.953272,-0.55037 1.304431,-1.74066 0.763301,-2.67793 l -3.8125,-6.60344 c -0.54113,-0.93726 -1.747529,-1.2283 -2.700801,-0.67792 l -3.355849,1.9375 c -1.414093,-1.4181 -3.011984,-2.62228 -4.709995,-3.59546 l 0.990945,-3.78363 c 0.284894,-1.06324 -0.275422,-2.13275 -1.320874,-2.41282 l -7.385074,-1.97882 c -1.045381,-0.28011 -2.065426,0.36588 -2.35032,1.42912 l -1.033633,3.7722 c -1.95712,-0.006 -3.943015,0.2377 -5.876702,0.75875 l -1.9375,-3.35585 c -0.55038,-0.95328 -1.740666,-1.30442 -2.677924,-0.7633 l -6.603444,3.8125 z m 10.051722,9.7851 c 6.696096,-3.866 15.258361,-1.57175 19.124356,5.12435 3.865995,6.6961 1.57174,15.25836 -5.124356,19.12436 -6.696096,3.86599 -15.258361,1.57174 -19.124356,-5.12436 -3.865995,-6.6961 -1.57174,-15.25836 5.124356,-19.12435 z" inkscape:connector-curvature="0" id="path4405" style="fill:url(#linearGradient4407);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> </clipPath> <linearGradient x1="48.233639" y1="48.047016" x2="126.13924" y2="66.232674" id="linearGradient4213" xlink:href="#linearGradient4071-3" gradientUnits="userSpaceOnUse" /> <linearGradient id="linearGradient4071-3"> <stop id="stop4073-8" style="stop-color:#000000;stop-opacity:1" offset="0" /> <stop id="stop4075-4" style="stop-color:#000000;stop-opacity:0" offset="1" /> </linearGradient> <linearGradient x1="48.055065" y1="48.031517" x2="126.67282" y2="62.838562" id="linearGradient4215" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient id="linearGradient4047-2"> <stop id="stop4049-0" style="stop-color:#000000;stop-opacity:1" offset="0" /> <stop id="stop4051-5" style="stop-color:#000000;stop-opacity:0" offset="1" /> </linearGradient> <linearGradient x1="47.997307" y1="48.028725" x2="127.05216" y2="60.289631" id="linearGradient4217" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.99826" y1="48.028797" x2="127.41583" y2="57.664623" id="linearGradient4219" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.233643" y1="48.04702" x2="126.13924" y2="66.232674" id="linearGradient4221" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient id="linearGradient4115-2"> <stop id="stop4117-3" style="stop-color:#ffffff;stop-opacity:1" offset="0" /> <stop id="stop4119-6" style="stop-color:#ffffff;stop-opacity:0" offset="1" /> </linearGradient> <linearGradient x1="48.055069" y1="48.031521" x2="126.67282" y2="62.838566" id="linearGradient4223" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.997311" y1="48.028728" x2="127.05216" y2="60.289635" id="linearGradient4225" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.998264" y1="48.028801" x2="127.41583" y2="57.664627" id="linearGradient4227" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.233639" y1="48.047016" x2="126.13924" y2="66.232674" id="linearGradient4229" xlink:href="#linearGradient4071-3" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.055065" y1="48.031517" x2="126.67282" y2="62.838562" id="linearGradient4231" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.997307" y1="48.028725" x2="127.05216" y2="60.289631" id="linearGradient4233" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.99826" y1="48.028797" x2="127.41583" y2="57.664623" id="linearGradient4235" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.233639" y1="48.047016" x2="126.13924" y2="66.232674" id="linearGradient4237" xlink:href="#linearGradient4071-3" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.055065" y1="48.031517" x2="126.67282" y2="62.838562" id="linearGradient4239" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.997307" y1="48.028725" x2="127.05216" y2="60.289631" id="linearGradient4241" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.99826" y1="48.028797" x2="127.41583" y2="57.664623" id="linearGradient4243" xlink:href="#linearGradient4047-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.233643" y1="48.04702" x2="126.13924" y2="66.232674" id="linearGradient4245" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="48.055069" y1="48.031521" x2="126.67282" y2="62.838566" id="linearGradient4247" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.997311" y1="48.028728" x2="127.05216" y2="60.289635" id="linearGradient4249" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="47.998264" y1="48.028801" x2="127.41583" y2="57.664627" id="linearGradient4251" xlink:href="#linearGradient4115-2" gradientUnits="userSpaceOnUse" /> <linearGradient x1="20.758585" y1="1" x2="20.758585" y2="45.017357" id="linearGradient3141" xlink:href="#linearGradient3309" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.2790652,0,0,1.2790652,17.302433,16.5815)" /> <linearGradient x1="63.9995" y1="3.1001" x2="63.9995" y2="122.8994" id="linearGradient3309" gradientUnits="userSpaceOnUse"> <stop id="stop3311" style="stop-color:#f0f0f0;stop-opacity:1" offset="0" /> <stop id="stop3313" style="stop-color:#aaaaaa;stop-opacity:1" offset="1" /> </linearGradient> </defs> <metadata id="metadata2413"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> <dc:title /> </cc:Work> </rdf:RDF> </metadata> <g id="layer2" style="display:none"> <rect width="86" height="85" rx="6" ry="6" x="5" y="7" id="rect3745" style="opacity:0.9;fill:url(#ButtonShadow);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3174)" /> </g> <g id="layer3" style="display:inline"> <path d="m 12,-95.03125 c -5.5110903,0 -10.03125,4.52016 -10.03125,10.03125 l 0,71 c 0,5.5110902 4.5201598,10.03125 10.03125,10.03125 l 72,0 c 5.51109,0 10.03125,-4.5201597 10.03125,-10.03125 l 0,-71 c 0,-5.51109 -4.52016,-10.03125 -10.03125,-10.03125 l -72,0 z" transform="scale(1,-1)" id="path3786" style="opacity:0.07999998;fill:url(#linearGradient3026);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /> <path d="m 12,-94.03125 c -4.971633,0 -9.03125,4.059617 -9.03125,9.03125 l 0,71 c 0,4.9716329 4.0596171,9.03125 9.03125,9.03125 l 72,0 c 4.971633,0 9.03125,-4.059617 9.03125,-9.03125 l 0,-71 c 0,-4.971633 -4.059617,-9.03125 -9.03125,-9.03125 l -72,0 z" transform="scale(1,-1)" id="path3778" style="opacity:0.1;fill:url(#linearGradient3780);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /> <path d="m 12,-93 c -4.4091333,0 -8,3.590867 -8,8 l 0,71 c 0,4.4091333 3.5908667,8 8,8 l 72,0 c 4.409133,0 8,-3.5908667 8,-8 l 0,-71 c 0,-4.409133 -3.590867,-8 -8,-8 l -72,0 z" transform="scale(1,-1)" id="path3770" style="opacity:0.2;fill:url(#linearGradient3772);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /> <rect width="86" height="85" rx="7" ry="7" x="5" y="-92" transform="scale(1,-1)" id="rect3723" style="opacity:0.3;fill:url(#linearGradient3725);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /> <rect width="84" height="84" rx="6" ry="6" x="6" y="-91" transform="scale(1,-1)" id="rect3716" style="opacity:0.45;fill:url(#linearGradient3721);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /> </g> <g id="layer1"> <rect width="84" height="84" rx="6" ry="6" x="6" y="6" id="rect2419" style="fill:url(#linearGradient3161);fill-opacity:1;fill-rule:nonzero;stroke:none" /> <path d="M 120.78125,6.125 C 118.04223,6.6826484 116,9.0915 116,12 l 0,68 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 l 0,-68 c 0,-2.9085 -2.04223,-5.3173516 -4.78125,-5.875 2.20512,0.5362071 3.8125,2.4908437 3.8125,4.875 l 0,68 c 0,2.80489 -2.22636,5.03125 -5.03125,5.03125 l -72,0 c -2.80489,0 -5.03125,-2.22636 -5.03125,-5.03125 l 0,-68 c 0,-2.3841563 1.60738,-4.3387929 3.8125,-4.875 z" inkscape:connector-curvature="0" id="rect4359" style="opacity:0.2;fill:url(#radialGradient4375);fill-opacity:1;fill-rule:nonzero;stroke:none" /> <path d="M 12,86 C 8.676,86 6,83.324 6,80 L 6,12 C 6,8.676 8.676,6 12,6 l 72,0 c 3.324,0 6,2.676 6,6 l 0,68 c 0,3.324 -2.676,6 -6,6 z m 0,-0.96875 72,0 c 2.80489,0 5.03125,-2.22636 5.03125,-5.03125 l 0,-68 C 89.03125,9.19511 86.80489,6.96875 84,6.96875 l -72,0 C 9.1951102,6.96875 6.96875,9.19511 6.96875,12 l 0,68 c 0,2.80489 2.2263602,5.03125 5.03125,5.03125 z" inkscape:connector-curvature="0" id="rect4377" style="opacity:0.3;fill:url(#linearGradient4390);fill-opacity:1;fill-rule:nonzero;stroke:none" /> <path d="m 6,78 0,2 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 l 0,-2 c 0,3.324 -2.676,6 -6,6 L 12,84 C 8.676,84 6,81.324 6,78 z" inkscape:connector-curvature="0" id="rect4414" style="opacity:0.1;fill:url(#linearGradient4429);fill-opacity:1;fill-rule:nonzero;stroke:none" /> <path d="m 6,100 0,1 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 l 0,-1 c 0,3.324 -2.676,6 -6,6 l -72,0 c -3.324,0 -6,-2.676 -6,-6 z" inkscape:connector-curvature="0" id="path4412" style="opacity:0.15;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /> </g> <g id="layer4" style="display:inline"> <path d="m 6,80 0,4 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 l 0,-4 c 0,3.324 -2.676,6 -6,6 L 12,86 C 8.676,86 6,83.324 6,80 z" inkscape:connector-curvature="0" id="path3888" style="fill:url(#linearGradient3228);fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /> <path d="m 6,82 0,2 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 l 0,-2 c 0,3.324 -2.676,6 -6,6 L 12,88 C 8.676,88 6,85.324 6,82 z" inkscape:connector-curvature="0" id="rect4345" style="opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 6,83 0,1 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 l 0,-1 c 0,3.324 -2.676,6 -6,6 L 12,89 C 8.676,89 6,86.324 6,83 z" inkscape:connector-curvature="0" id="rect4336" style="opacity:0.15;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> </g> <g id="layer5" style="display:inline"> <rect width="66" height="62" rx="12" ry="12" x="15" y="15" clip-path="url(#clipPath4355)" id="rect3171" style="opacity:0.1;fill:url(#linearGradient3613);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3794)" /> </g> <g id="layer6"> <path d="m 44.1875,18.40625 c -2.812128,0 -5.03125,2.349265 -5.03125,5.09375 l 0,1.875 C 38.598195,25.583065 38.041936,25.784088 37.5,26.03125 l -1.3125,-1.3125 c -0.815424,-0.815417 -2.045979,-1.518664 -3.53125,-1.53125 -1.303265,-0.01113 -2.609586,0.484578 -3.59375,1.46875 l -5.40625,5.40625 c -1.98399,1.98401 -1.846217,5.216073 0.0625,7.125 l 1.3125,1.3125 c -0.247161,0.541936 -0.448185,1.098196 -0.65625,1.65625 l -1.875,0 c -2.744488,0 -5.09375,2.219124 -5.09375,5.03125 l 0,7.625 c 0,2.812126 2.349262,5.03125 5.09375,5.03125 l 1.875,0 c 0.208065,0.558055 0.409089,1.114314 0.65625,1.65625 l -1.3125,1.3125 c -1.908896,1.908901 -2.046661,5.141029 -0.0625,7.125 l 5.40625,5.40625 c 1.983946,1.983966 5.216043,1.846454 7.125,-0.0625 L 37.5,71.96875 c 0.541936,0.247162 1.098195,0.448185 1.65625,0.65625 l 0,1.875 c 0,2.744484 2.219121,5.09375 5.03125,5.09375 l 7.625,0 c 2.812123,0 5.03125,-2.349259 5.03125,-5.09375 l 0,-1.875 C 57.401805,72.416935 57.958064,72.215912 58.5,71.96875 l 1.3125,1.3125 c 1.908959,1.908964 5.141053,2.046443 7.125,0.0625 l 5.40625,-5.40625 c 1.983992,-1.984009 1.846223,-5.216074 -0.0625,-7.125 L 70.96875,59.5 c 0.247162,-0.541935 0.448185,-1.098194 0.65625,-1.65625 l 1.875,0 c 2.744481,0 5.09375,-2.219118 5.09375,-5.03125 l 0,-7.625 c 0,-2.812131 -2.349267,-5.03125 -5.09375,-5.03125 l -1.875,0 C 71.416935,39.598194 71.215912,39.041936 70.96875,38.5 l 1.3125,-1.3125 c 1.908886,-1.908892 2.046695,-5.141025 0.0625,-7.125 L 66.9375,24.65625 c -1.983947,-1.983938 -5.21604,-1.846464 -7.125,0.0625 L 58.5,26.03125 C 57.958064,25.784088 57.401805,25.583065 56.84375,25.375 l 0,-1.875 c 0,-2.744491 -2.219127,-5.09375 -5.03125,-5.09375 l -7.625,0 z M 48,38.09375 c 6.075308,0 10.90625,4.830942 10.90625,10.90625 0,6.075308 -4.830942,10.90625 -10.90625,10.90625 -6.075308,0 -10.90625,-4.830942 -10.90625,-10.90625 0,-6.075308 4.830942,-10.90625 10.90625,-10.90625 z" transform="translate(0,-2)" id="path4367" style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> <path d="m 44.1875,19.4375 c -2.226603,0 -4,1.88144 -4,4.0625 l 0,2.5625 c -1.016644,0.349685 -1.987325,0.744874 -2.9375,1.21875 l -1.8125,-1.8125 c -0.671479,-0.671474 -1.634818,-1.240285 -2.78125,-1.25 -1.022124,-0.0087 -2.053465,0.397209 -2.84375,1.1875 l -5.40625,5.40625 c -1.570335,1.570351 -1.455432,4.106901 0.0625,5.625 l 1.8125,1.8125 c -0.473875,0.950174 -0.869064,1.920858 -1.21875,2.9375 l -2.5625,0 c -2.181063,0 -4.0625,1.773399 -4.0625,4 l 0,7.625 c 0,2.226601 1.881437,4 4.0625,4 l 2.5625,0 c 0.349686,1.016643 0.744875,1.987326 1.21875,2.9375 l -1.8125,1.8125 c -1.518074,1.518078 -1.632971,4.054679 -0.0625,5.625 l 5.40625,5.40625 c 1.570306,1.570322 4.106882,1.455615 5.625,-0.0625 l 1.8125,-1.8125 c 0.950175,0.473877 1.920856,0.869066 2.9375,1.21875 l 0,2.5625 c 0,2.181059 1.773396,4.0625 4,4.0625 l 7.625,0 c 2.226598,0 4,-1.881434 4,-4.0625 l 0,-2.5625 c 1.016644,-0.349684 1.987325,-0.744873 2.9375,-1.21875 l 1.8125,1.8125 c 1.518117,1.518121 4.054691,1.632806 5.625,0.0625 l 5.40625,-5.40625 c 1.570337,-1.570351 1.455437,-4.106902 -0.0625,-5.625 L 69.71875,59.75 c 0.473875,-0.950173 0.869065,-1.920855 1.21875,-2.9375 l 2.5625,0 c 2.181056,0 4.0625,-1.773393 4.0625,-4 l 0,-7.625 c 0,-2.226606 -1.881442,-4 -4.0625,-4 l -2.5625,0 C 70.587815,40.170854 70.192626,39.200173 69.71875,38.25 l 1.8125,-1.8125 c 1.518067,-1.518072 1.632997,-4.054677 0.0625,-5.625 L 66.1875,25.40625 c -1.570309,-1.570302 -4.106883,-1.45562 -5.625,0.0625 L 58.75,27.28125 C 57.799825,26.807374 56.829144,26.412185 55.8125,26.0625 l 0,-2.5625 c 0,-2.181066 -1.773402,-4.0625 -4,-4.0625 l -7.625,0 z M 48,37.0625 c 6.630024,0 11.9375,5.307476 11.9375,11.9375 0,6.630024 -5.307476,11.9375 -11.9375,11.9375 -6.630024,0 -11.9375,-5.307476 -11.9375,-11.9375 0,-6.630024 5.307476,-11.9375 11.9375,-11.9375 z" transform="translate(0,-2)" id="path4363" style="opacity:0.07999998;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> <path d="m 44.1875,20.46875 c -1.649639,0 -2.96875,1.39995 -2.96875,3.03125 l 0,3.21875 c -1.461857,0.450067 -2.865234,1.039291 -4.1875,1.75 l -2.3125,-2.28125 c -0.52527,-0.525266 -1.250126,-0.930616 -2.0625,-0.9375 -0.759326,-0.0065 -1.530481,0.280476 -2.125,0.875 L 25.125,31.53125 c -1.161458,1.16147 -1.074579,3.050296 0.0625,4.1875 l 2.28125,2.3125 c -0.710706,1.322265 -1.299929,2.725645 -1.75,4.1875 l -3.21875,0 c -1.631303,0 -3.03125,1.319113 -3.03125,2.96875 l 0,7.625 c 0,1.649637 1.399947,2.96875 3.03125,2.96875 l 3.21875,0 c 0.450071,1.461856 1.039294,2.865236 1.75,4.1875 l -2.28125,2.3125 c -1.137183,1.137186 -1.224059,3.026052 -0.0625,4.1875 l 5.40625,5.40625 c 1.161443,1.161455 3.050289,1.074709 4.1875,-0.0625 l 2.3125,-2.28125 c 1.322267,0.71071 2.725643,1.299933 4.1875,1.75 l 0,3.21875 c 0,1.631299 1.319111,3.03125 2.96875,3.03125 l 7.625,0 c 1.649634,0 2.96875,-1.399944 2.96875,-3.03125 l 0,-3.21875 c 1.461857,-0.450067 2.865233,-1.03929 4.1875,-1.75 l 2.3125,2.28125 c 1.137207,1.13721 3.026053,1.223945 4.1875,0.0625 L 70.875,66.46875 c 1.16146,-1.16147 1.074582,-3.050297 -0.0625,-4.1875 l -2.28125,-2.3125 c 0.710707,-1.322263 1.299931,-2.72564 1.75,-4.1875 l 3.21875,0 c 1.631297,0 3.03125,-1.319107 3.03125,-2.96875 l 0,-7.625 c 0,-1.649642 -1.399951,-2.96875 -3.03125,-2.96875 l -3.21875,0 c -0.450068,-1.461861 -1.039293,-2.865237 -1.75,-4.1875 l 2.28125,-2.3125 c 1.137179,-1.137183 1.224077,-3.026052 0.0625,-4.1875 L 65.46875,26.125 c -1.161447,-1.161442 -3.050293,-1.074709 -4.1875,0.0625 l -2.3125,2.28125 c -1.322266,-0.710709 -2.725643,-1.299933 -4.1875,-1.75 l 0,-3.21875 c 0,-1.631306 -1.319116,-3.03125 -2.96875,-3.03125 l -7.625,0 z M 48,36.03125 c 7.178426,0 12.96875,5.790324 12.96875,12.96875 0,7.178426 -5.790324,12.96875 -12.96875,12.96875 -7.178426,0 -12.96875,-5.790324 -12.96875,-12.96875 0,-7.178426 5.790324,-12.96875 12.96875,-12.96875 z" transform="translate(0,-2)" id="path4359" style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> <path d="m 44.1875,19.5 c -1.082262,0 -1.9375,0.899245 -1.9375,2 l 0,3.875 c -1.935147,0.515597 -3.776942,1.297312 -5.46875,2.28125 L 34,24.90625 c -0.389179,-0.389176 -0.840116,-0.620732 -1.34375,-0.625 -0.503633,-0.0043 -1.023619,0.179866 -1.40625,0.5625 L 25.84375,30.25 c -0.765262,0.76527 -0.715766,1.971648 0.0625,2.75 l 2.75,2.78125 C 27.672316,37.473053 26.89061,39.314849 26.375,41.25 l -3.875,0 c -1.100753,0 -2,0.855244 -2,1.9375 l 0,7.625 c 0,1.082256 0.899247,1.9375 2,1.9375 l 3.875,0 c 0.51561,1.935152 1.297316,3.776947 2.28125,5.46875 L 25.90625,61 c -0.778348,0.77835 -0.827844,1.984729 -0.0625,2.75 L 31.25,69.15625 c 0.765262,0.76527 1.971652,0.715847 2.75,-0.0625 l 2.78125,-2.75 c 1.691808,0.983939 3.533603,1.765652 5.46875,2.28125 l 0,3.875 c 0,1.100754 0.855238,2 1.9375,2 l 7.625,0 c 1.082252,0 1.9375,-0.899246 1.9375,-2 l 0,-3.875 c 1.935147,-0.515598 3.776941,-1.297311 5.46875,-2.28125 L 62,69.09375 c 0.778348,0.77835 1.984727,0.827772 2.75,0.0625 L 70.15625,63.75 c 0.765263,-0.76527 0.715767,-1.97165 -0.0625,-2.75 l -2.75,-2.78125 C 68.327683,56.526947 69.109401,54.685152 69.625,52.75 l 3.875,0 c 1.100744,0 2,-0.855243 2,-1.9375 l 0,-7.625 c 0,-1.082255 -0.899256,-1.9375 -2,-1.9375 l -3.875,0 C 69.109405,39.314849 68.327683,37.473053 67.34375,35.78125 L 70.09375,33 c 0.778348,-0.778351 0.827855,-1.98473 0.0625,-2.75 L 64.75,24.84375 C 63.984727,24.07848 62.778348,24.127901 62,24.90625 l -2.78125,2.75 C 57.526941,26.672312 55.685147,25.890597 53.75,25.375 l 0,-3.875 c 0,-1.100755 -0.855248,-2 -1.9375,-2 l -7.625,0 z M 48,33 c 7.731986,0 14,6.268014 14,14 0,7.731986 -6.268014,14 -14,14 -7.731986,0 -14,-6.268014 -14,-14 0,-7.731986 6.268014,-14 14,-14 z" inkscape:connector-curvature="0" id="path4353" style="opacity:0.3;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> <path d="m 44.1875,18.5 c -1.082262,0 -1.9375,0.899245 -1.9375,2 l 0,3.875 c -1.935147,0.515597 -3.776942,1.297312 -5.46875,2.28125 L 34,23.90625 c -0.389179,-0.389176 -0.840116,-0.620732 -1.34375,-0.625 -0.503633,-0.0043 -1.023619,0.179866 -1.40625,0.5625 L 25.84375,29.25 c -0.765262,0.76527 -0.715766,1.971648 0.0625,2.75 l 2.75,2.78125 C 27.672316,36.473053 26.89061,38.314849 26.375,40.25 l -3.875,0 c -1.100753,0 -2,0.855244 -2,1.9375 l 0,7.625 c 0,1.082256 0.899247,1.9375 2,1.9375 l 3.875,0 c 0.51561,1.935152 1.297316,3.776947 2.28125,5.46875 L 25.90625,60 c -0.778348,0.77835 -0.827844,1.984729 -0.0625,2.75 L 31.25,68.15625 c 0.765262,0.76527 1.971652,0.715847 2.75,-0.0625 l 2.78125,-2.75 c 1.691808,0.983939 3.533603,1.765652 5.46875,2.28125 l 0,3.875 c 0,1.100754 0.855238,2 1.9375,2 l 7.625,0 c 1.082252,0 1.9375,-0.899246 1.9375,-2 l 0,-3.875 c 1.935147,-0.515598 3.776941,-1.297311 5.46875,-2.28125 L 62,68.09375 c 0.778348,0.77835 1.984727,0.827772 2.75,0.0625 L 70.15625,62.75 c 0.765263,-0.76527 0.715767,-1.97165 -0.0625,-2.75 l -2.75,-2.78125 C 68.327683,55.526947 69.109401,53.685152 69.625,51.75 l 3.875,0 c 1.100744,0 2,-0.855243 2,-1.9375 l 0,-7.625 c 0,-1.082255 -0.899256,-1.9375 -2,-1.9375 l -3.875,0 C 69.109405,38.314849 68.327683,36.473053 67.34375,34.78125 L 70.09375,32 c 0.778348,-0.778351 0.827855,-1.98473 0.0625,-2.75 L 64.75,23.84375 C 63.984727,23.07848 62.778348,23.127901 62,23.90625 l -2.78125,2.75 C 57.526941,25.672312 55.685147,24.890597 53.75,24.375 l 0,-3.875 c 0,-1.100755 -0.855248,-2 -1.9375,-2 l -7.625,0 z M 48,32 c 7.731986,0 14,6.268014 14,14 0,7.731986 -6.268014,14 -14,14 -7.731986,0 -14,-6.268014 -14,-14 0,-7.731986 6.268014,-14 14,-14 z" inkscape:connector-curvature="0" id="rect3267" style="fill:url(#linearGradient3141);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> <g transform="matrix(0.8660254,0.5,-0.5,0.8660254,85.39875,-114.71247)" clip-path="url(#clipPath4403)" id="g4176"> <g transform="matrix(0.1413721,0.99271966,-1.1651755,0.12044784,96.937266,104.80532)" id="g4011" style="opacity:0.9"> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -6.54616,27.466658 L 48,48 z" transform="matrix(0.99411049,-0.1083712,0.1083712,0.99411049,-5.1582185,5.4918915)" id="path4009" style="opacity:0.05;color:#000000;fill:url(#linearGradient4213);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -4.45721,22.86887 L 48,48 z" transform="matrix(0.99786084,-0.06537382,0.06537382,0.99786084,-3.0940115,3.2415713)" id="path4007" style="opacity:0.07000002;color:#000000;fill:url(#linearGradient4215);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -3.12994,19.271878 L 48,48 z" transform="matrix(0.99945136,-0.0331207,0.0331207,0.99945136,-1.5634586,1.6161281)" id="path4005" style="opacity:0.1;color:#000000;fill:url(#linearGradient4217);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -2.07497,15.76102 L 48,48 z" id="path4003" style="opacity:0.05;color:#000000;fill:url(#linearGradient4219);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> </g> <g transform="matrix(1.062807,-0.13087531,-0.74010065,3.227468,32.525111,9.33226)" id="g4027" style="opacity:0.9;fill:#ffffff"> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -6.54616,27.466658 L 48,48 z" transform="matrix(0.99411049,-0.1083712,0.1083712,0.99411049,-5.1582185,5.4918915)" id="path4029" style="opacity:0.2;color:#000000;fill:url(#linearGradient4221);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -4.45721,22.86887 L 48,48 z" transform="matrix(0.99786084,-0.06537382,0.06537382,0.99786084,-3.0940115,3.2415713)" id="path4031" style="opacity:0.4;color:#000000;fill:url(#linearGradient4223);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -3.12994,19.271878 L 48,48 z" transform="matrix(0.99945136,-0.0331207,0.0331207,0.99945136,-1.5634586,1.6161281)" id="path4033" style="opacity:0.6;color:#000000;fill:url(#linearGradient4225);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -2.07497,15.76102 L 48,48 z" id="path4035" style="opacity:0.8;color:#000000;fill:url(#linearGradient4227);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> </g> <g transform="matrix(-0.61678932,0.78712829,-0.78712829,-0.61678932,115.00148,150.01193)" id="g4079" style="opacity:0.5"> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -6.54616,27.466658 L 48,48 z" transform="matrix(0.99411049,-0.1083712,0.1083712,0.99411049,-5.1582185,5.4918915)" id="path4081" style="opacity:0.05;color:#000000;fill:url(#linearGradient4229);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -4.45721,22.86887 L 48,48 z" transform="matrix(0.99786084,-0.06537382,0.06537382,0.99786084,-3.0940115,3.2415713)" id="path4083" style="opacity:0.07000002;color:#000000;fill:url(#linearGradient4231);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -3.12994,19.271878 L 48,48 z" transform="matrix(0.99945136,-0.0331207,0.0331207,0.99945136,-1.5634586,1.6161281)" id="path4085" style="opacity:0.1;color:#000000;fill:url(#linearGradient4233);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -2.07497,15.76102 L 48,48 z" id="path4087" style="opacity:0.1;color:#000000;fill:url(#linearGradient4235);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> </g> <g transform="matrix(-0.06817198,-1.0460056,2.710673,0.60162586,-79.095447,179.08013)" id="g4097" style="opacity:0.8"> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -6.54616,27.466658 L 48,48 z" transform="matrix(0.99411049,-0.1083712,0.1083712,0.99411049,-5.1582185,5.4918915)" id="path4099" style="opacity:0.05;color:#000000;fill:url(#linearGradient4237);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -4.45721,22.86887 L 48,48 z" transform="matrix(0.99786084,-0.06537382,0.06537382,0.99786084,-3.0940115,3.2415713)" id="path4101" style="opacity:0.07000002;color:#000000;fill:url(#linearGradient4239);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -3.12994,19.271878 L 48,48 z" transform="matrix(0.99945136,-0.0331207,0.0331207,0.99945136,-1.5634586,1.6161281)" id="path4103" style="opacity:0.1;color:#000000;fill:url(#linearGradient4241);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -2.07497,15.76102 L 48,48 z" id="path4105" style="opacity:0.1;color:#000000;fill:url(#linearGradient4243);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> </g> <g transform="matrix(-1.062807,0.1308753,0.74010064,-3.227468,62.996694,306.66774)" id="g4147" style="opacity:0.9;fill:#ffffff"> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -6.54616,27.466658 L 48,48 z" transform="matrix(0.99411049,-0.1083712,0.1083712,0.99411049,-5.1582185,5.4918915)" id="path4149" style="opacity:0.2;color:#000000;fill:url(#linearGradient4245);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -4.45721,22.86887 L 48,48 z" transform="matrix(0.99786084,-0.06537382,0.06537382,0.99786084,-3.0940115,3.2415713)" id="path4151" style="opacity:0.4;color:#000000;fill:url(#linearGradient4247);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -3.12994,19.271878 L 48,48 z" transform="matrix(0.99945136,-0.0331207,0.0331207,0.99945136,-1.5634586,1.6161281)" id="path4153" style="opacity:0.6;color:#000000;fill:url(#linearGradient4249);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <path d="m 108.8959,48 a 60.895905,60.895905 0 0 1 -2.07497,15.76102 L 48,48 z" id="path4155" style="opacity:0.8;color:#000000;fill:url(#linearGradient4251);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> </g> </g> <path d="m 44.1875,18.5 c -1.082262,0 -1.9375,0.899245 -1.9375,2 l 0,1 c 0,-1.100755 0.855238,-2 1.9375,-2 l 7.625,0 c 1.082252,0 1.9375,0.899245 1.9375,2 l 0,-1 c 0,-1.100755 -0.855248,-2 -1.9375,-2 l -7.625,0 z m -11.53125,4.78125 c -0.503633,-0.0043 -1.023619,0.179866 -1.40625,0.5625 L 25.84375,29.25 c -0.496443,0.496448 -0.634599,1.182061 -0.46875,1.8125 0.0841,-0.291632 0.234756,-0.578504 0.46875,-0.8125 L 31.25,24.84375 c 0.382631,-0.382634 0.902617,-0.5668 1.40625,-0.5625 0.503634,0.0043 0.954571,0.235824 1.34375,0.625 l 2.78125,2.75 C 38.473058,26.672312 40.314853,25.890597 42.25,25.375 l 0,-1 c -1.935147,0.515597 -3.776942,1.297312 -5.46875,2.28125 L 34,23.90625 c -0.389179,-0.389176 -0.840116,-0.620732 -1.34375,-0.625 z m 30.71875,0 c -0.494547,0.01399 -0.985826,0.235826 -1.375,0.625 l -2.78125,2.75 C 57.526941,25.672312 55.685147,24.890597 53.75,24.375 l 0,1 c 1.935147,0.515597 3.776941,1.297312 5.46875,2.28125 L 62,24.90625 c 0.778348,-0.778349 1.984727,-0.82777 2.75,-0.0625 L 70.15625,30.25 c 0.234022,0.233996 0.38464,0.520868 0.46875,0.8125 0.165867,-0.630439 0.02775,-1.316052 -0.46875,-1.8125 L 64.75,23.84375 c -0.382637,-0.382635 -0.880453,-0.57649 -1.375,-0.5625 z M 28.3125,35.4375 c -0.812756,1.508863 -1.487562,3.123824 -1.9375,4.8125 l -3.875,0 c -1.100753,0 -2,0.855244 -2,1.9375 l 0,1 c 0,-1.082256 0.899247,-1.9375 2,-1.9375 l 3.875,0 c 0.51561,-1.935151 1.297316,-3.776947 2.28125,-5.46875 L 28.3125,35.4375 z m 39.375,0 -0.34375,0.34375 c 0.983933,1.691803 1.765655,3.533599 2.28125,5.46875 l 3.875,0 c 1.100744,0 2,0.855245 2,1.9375 l 0,-1 c 0,-1.082255 -0.899256,-1.9375 -2,-1.9375 l -3.875,0 C 69.175075,38.561324 68.500258,36.946363 67.6875,35.4375 z M 34.03125,46.5 C 34.02535,46.66679 34,46.831775 34,47 c 0,7.731986 6.268014,14 14,14 7.731986,0 14,-6.268014 14,-14 0,-0.168225 -0.02537,-0.33321 -0.03125,-0.5 C 61.704161,53.999218 55.563761,60 48,60 40.436239,60 34.295839,53.999218 34.03125,46.5 z M 28.3125,57.5625 25.90625,60 C 25.365897,60.540355 25.184033,61.275367 25.375,61.9375 25.46481,61.596123 25.632834,61.273417 25.90625,61 l 2.75,-2.78125 C 28.530929,58.00327 28.431128,57.78273 28.3125,57.5625 z m 39.375,0 c -0.118628,0.22023 -0.218429,0.44077 -0.34375,0.65625 L 70.09375,61 c 0.273388,0.273417 0.441444,0.596123 0.53125,0.9375 C 70.815945,61.275367 70.634,60.540355 70.09375,60 L 67.6875,57.5625 z" inkscape:connector-curvature="0" id="path4382" style="opacity:0.7;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> <path d="M 25.375,30.0625 C 25.184055,30.724633 25.366,31.459644 25.90625,32 l 2.40625,2.4375 c 0.118628,-0.22023 0.218429,-0.44077 0.34375,-0.65625 L 25.90625,31 C 25.632863,30.726583 25.464806,30.403877 25.375,30.0625 z m 45.25,0 C 70.53518,30.403877 70.367166,30.726583 70.09375,31 l -2.75,2.78125 c 0.125321,0.21548 0.225122,0.43602 0.34375,0.65625 L 70.09375,32 c 0.540353,-0.540355 0.722218,-1.275367 0.53125,-1.9375 z M 48,31 c -7.731986,0 -14,6.268014 -14,14 0,0.168225 0.02537,0.33321 0.03125,0.5 C 34.295839,38.000782 40.436239,32 48,32 55.563761,32 61.704161,38.000782 61.96875,45.5 61.97465,45.33321 62,45.168225 62,45 62,37.268014 55.731986,31 48,31 z m -27.5,17.8125 0,1 c 0,1.082256 0.899247,1.9375 2,1.9375 l 3.875,0 c 0.449938,1.688677 1.124744,3.303637 1.9375,4.8125 l 0.34375,-0.34375 C 27.672316,54.526947 26.89061,52.685152 26.375,50.75 l -3.875,0 c -1.100753,0 -2,-0.855244 -2,-1.9375 z m 55,0 c 0,1.082257 -0.899256,1.9375 -2,1.9375 l -3.875,0 c -0.515599,1.935152 -1.297317,3.776947 -2.28125,5.46875 l 0.34375,0.34375 c 0.812757,-1.508863 1.487571,-3.123823 1.9375,-4.8125 l 3.875,0 c 1.100744,0 2,-0.855243 2,-1.9375 l 0,-1 z m -50.125,12.125 c -0.165865,0.630439 -0.02775,1.316051 0.46875,1.8125 L 31.25,68.15625 c 0.765262,0.76527 1.971652,0.715847 2.75,-0.0625 l 2.78125,-2.75 c 1.691808,0.983939 3.533603,1.765652 5.46875,2.28125 l 0,-1 C 40.314853,66.109402 38.473058,65.327689 36.78125,64.34375 L 34,67.09375 c -0.778348,0.778347 -1.984738,0.82777 -2.75,0.0625 L 25.84375,61.75 C 25.609731,61.516004 25.45911,61.229132 25.375,60.9375 z m 45.25,0 c -0.0841,0.291632 -0.234756,0.578504 -0.46875,0.8125 L 64.75,67.15625 C 63.984727,67.921522 62.778348,67.8721 62,67.09375 l -2.78125,-2.75 C 57.526941,65.327689 55.685147,66.109402 53.75,66.625 l 0,1 c 1.935147,-0.515598 3.776941,-1.297311 5.46875,-2.28125 L 62,68.09375 c 0.778348,0.77835 1.984727,0.827772 2.75,0.0625 L 70.15625,62.75 c 0.496443,-0.496448 0.634599,-1.182061 0.46875,-1.8125 z M 42.25,70.5 l 0,1 c 0,1.100754 0.855238,2 1.9375,2 l 7.625,0 c 1.082252,0 1.9375,-0.899246 1.9375,-2 l 0,-1 c 0,1.100754 -0.855248,2 -1.9375,2 l -7.625,0 c -1.082262,0 -1.9375,-0.899246 -1.9375,-2 z" inkscape:connector-curvature="0" id="path4391" style="opacity:0.2;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:block;overflow:visible;enable-background:accumulate" /> </g> </svg> kiran-session-manager-2.5.0/resources/styles/0000775000175000017500000000000014417211336022674 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/resources/styles/kiran-session-window.qss0000664000175000017500000000040314417211336027513 0ustar wangyuchengwangyucheng QWidget#m_mask { background: rgba(34, 34, 34, 60%); } QLabel { color: white; } QLabel#m_title { font-size: 24px; } QWidget#m_inhibitors { background: transparent; border: none; } QWidget#InhibitorRow { background: transparent; } kiran-session-manager-2.5.0/resources/resources.qrc0000664000175000017500000000036114417211336024072 0ustar wangyuchengwangyucheng<RCC> <!--主题--> <qresource prefix="/"> <file>styles/kiran-session-window.qss</file> </qresource> <qresource prefix="/"> <file alias="app-missing.svg">images/app-missing.svg</file> </qresource> </RCC> kiran-session-manager-2.5.0/lib/0000775000175000017500000000000014417211336020105 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/lib/CMakeLists.txt0000664000175000017500000000005614417211336022646 0ustar wangyuchengwangyucheng add_subdirectory(base) add_subdirectory(dbus)kiran-session-manager-2.5.0/lib/dbus/0000775000175000017500000000000014417211336021042 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/lib/dbus/systemd-login1.cpp0000664000175000017500000002056014417211336024430 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "lib/dbus/systemd-login1.h" #include <qt5-log-i.h> #include <unistd.h> #include <QDBusArgument> #include <QDBusConnection> #include <QDBusMessage> #include <QDBusMetaType> #include <QDBusObjectPath> #include <QDBusVariant> #include <QSharedPointer> #include "lib/base/def.h" struct SessionItem { QString sessionID; uint userID; QString userName; QString seatID; QDBusObjectPath objectPath; }; Q_DECLARE_METATYPE(SessionItem); QDBusArgument &operator<<(QDBusArgument &argument, const SessionItem &item) { argument.beginStructure(); argument << item.sessionID << item.userID << item.userName << item.seatID << item.objectPath; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, SessionItem &item) { argument.beginStructure(); argument >> item.sessionID >> item.userID >> item.userName >> item.seatID >> item.objectPath; argument.endStructure(); return argument; } namespace Kiran { #define LOGIN1_DBUS_NAME "org.freedesktop.login1" #define LOGIN1_DBUS_OBJECT_PATH "/org/freedesktop/login1" #define LOGIN1_MANAGER_DBUS_INTERFACE "org.freedesktop.login1.Manager" #define LOGIN1_SESSION_DBUS_INTERFACE "org.freedesktop.login1.Session" SystemdLogin1::SystemdLogin1() { auto sendMessage = QDBusMessage::createMethodCall(LOGIN1_DBUS_NAME, LOGIN1_DBUS_OBJECT_PATH, LOGIN1_MANAGER_DBUS_INTERFACE, "GetSessionByPID"); sendMessage << (uint32_t)getpid(); auto replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call GetSessionByPID failed: " << replyMessage.errorMessage(); return; } this->m_sessionObjectPath = replyMessage.arguments().takeFirst().value<QDBusObjectPath>(); qDBusRegisterMetaType<SessionItem>(); } QSharedPointer<SystemdLogin1> SystemdLogin1::m_instance = nullptr; QSharedPointer<SystemdLogin1> SystemdLogin1::getDefault() { if (!m_instance) { m_instance = QSharedPointer<SystemdLogin1>::create(); m_instance->init(); } return m_instance; } bool SystemdLogin1::setIdleHint(bool isIdle) { auto sendMessage = QDBusMessage::createMethodCall(LOGIN1_DBUS_NAME, this->m_sessionObjectPath.path(), LOGIN1_SESSION_DBUS_INTERFACE, "SetIdleHint"); sendMessage << isIdle; auto replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call SetIdleHint failed: " << replyMessage.errorMessage(); return false; } return true; } bool SystemdLogin1::isLastSession() { auto sendMessage = QDBusMessage::createMethodCall(LOGIN1_DBUS_NAME, LOGIN1_DBUS_OBJECT_PATH, LOGIN1_MANAGER_DBUS_INTERFACE, "ListSessions"); auto replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call ListSessions failed: " << replyMessage.errorMessage(); return false; } auto userUID = getuid(); auto replyArgs = replyMessage.arguments(); auto replySessions = replyArgs.takeFirst().value<QDBusArgument>(); replySessions.beginArray(); while (!replySessions.atEnd()) { SessionItem sessionItem; replySessions >> sessionItem; CONTINUE_IF_TRUE(sessionItem.userID != userUID); CONTINUE_IF_TRUE(sessionItem.objectPath == this->m_sessionObjectPath); QString state; QString type; #define GET_STRING_PROPERTY(propertyName, propertyVariable) \ { \ auto propSendMessage = QDBusMessage::createMethodCall(LOGIN1_DBUS_NAME, \ sessionItem.objectPath.path(), \ "org.freedesktop.DBus.Properties", \ "Get"); \ propSendMessage << LOGIN1_SESSION_DBUS_INTERFACE << #propertyName; \ auto propReplyMessage = QDBusConnection::systemBus().call(propSendMessage, QDBus::Block, DBUS_TIMEOUT_MS); \ if (propReplyMessage.type() == QDBusMessage::ErrorMessage) \ { \ KLOG_WARNING() << "Get " << #propertyName << " property failed: " << propReplyMessage.errorMessage(); \ continue; \ } \ auto firstArg = propReplyMessage.arguments().takeFirst().value<QDBusVariant>(); \ propertyVariable = firstArg.variant().value<QString>(); \ } GET_STRING_PROPERTY(State, state) GET_STRING_PROPERTY(Type, type) CONTINUE_IF_TRUE(state == "closing"); CONTINUE_IF_TRUE(type != "x11" && type != "wayland"); KLOG_DEBUG() << "Has other session running: " << sessionItem.objectPath.path(); return false; } return true; } void SystemdLogin1::init() { } bool SystemdLogin1::canDoMethod(const QString &methodName) { KLOG_DEBUG() << "Call function " << methodName; auto sendMessage = QDBusMessage::createMethodCall(LOGIN1_DBUS_NAME, LOGIN1_DBUS_OBJECT_PATH, LOGIN1_MANAGER_DBUS_INTERFACE, methodName); auto replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call " << methodName << " failed: " << replyMessage.errorMessage(); return false; } auto canResult = replyMessage.arguments().takeFirst().toString(); KLOG_DEBUG() << "Function " << methodName << " return " << canResult; return (canResult == "yes" || canResult == "challenge"); } bool SystemdLogin1::doMethod(const QString &methodName) { KLOG_DEBUG() << "Call function " << methodName; auto sendMessage = QDBusMessage::createMethodCall(LOGIN1_DBUS_NAME, LOGIN1_DBUS_OBJECT_PATH, LOGIN1_MANAGER_DBUS_INTERFACE, methodName); sendMessage << false; auto replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call " << methodName << " failed: " << replyMessage.errorMessage(); return false; } return true; } } // namespace Kirankiran-session-manager-2.5.0/lib/dbus/display-manager.h0000664000175000017500000000201114417211336024262 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QSharedPointer> namespace Kiran { class DisplayManager { public: DisplayManager(); virtual ~DisplayManager(){}; static QSharedPointer<DisplayManager> getDefault(); // 是否可切换用户 bool canSwitchUser(); // 切换用户 bool switchUser(); private: static QSharedPointer<DisplayManager> m_instance; QString m_xdgSeatPath; }; } // namespace Kiran kiran-session-manager-2.5.0/lib/dbus/screensaver.cpp0000664000175000017500000001142614417211336024072 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "lib/dbus/screensaver.h" #include <qt5-log-i.h> #include <QDBusConnection> #include <QDBusMessage> #include <QDBusVariant> #include <QSharedPointer> #include "lib/base/def.h" namespace Kiran { #define SCREENSAVER_DBUS_NAME "com.kylinsec.Kiran.ScreenSaver" #define SCREENSAVER_DBUS_OBJECT_PATH "/com/kylinsec/Kiran/ScreenSaver" #define SCREENSAVER_DBUS_INTERFACE "com.kylinsec.Kiran.ScreenSaver" // 屏保锁屏后,检查锁屏状态的最大次数 #define SCREENSAVER_LOCK_CHECK_MAX_COUNT 50 ScreenSaver::ScreenSaver() { } QSharedPointer<ScreenSaver> ScreenSaver::m_instance = nullptr; QSharedPointer<ScreenSaver> ScreenSaver::getDefault() { if (!m_instance) { m_instance = QSharedPointer<ScreenSaver>::create(); m_instance->init(); } return m_instance; } bool ScreenSaver::lock() { KLOG_DEBUG("Lock screen."); /* 注意:Lock函数无返回值,因此这里锁屏有可能会失败,如果需要检查锁屏是否成功,需要调用 GetActive函数检查屏保活动状态。*/ auto sendMessage = QDBusMessage::createMethodCall(SCREENSAVER_DBUS_NAME, SCREENSAVER_DBUS_OBJECT_PATH, SCREENSAVER_DBUS_INTERFACE, "Lock"); auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::NoBlock); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call Lock failed: " << replyMessage.errorMessage(); return false; } return true; } uint32_t ScreenSaver::addThrottle(const QString& reason) { KLOG_DEBUG() << "Add throttle, reason: " << reason; auto sendMessage = QDBusMessage::createMethodCall(SCREENSAVER_DBUS_NAME, SCREENSAVER_DBUS_OBJECT_PATH, SCREENSAVER_DBUS_INTERFACE, "Throttle"); sendMessage << QString("Power screensaver") << reason; auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call Throttle failed: " << replyMessage.errorMessage(); return 0; } auto replyArgs = replyMessage.arguments(); auto cookie = replyArgs.takeFirst().toUInt(); KLOG_DEBUG() << "Receive cookie: " << cookie; return cookie; } uint32_t ScreenSaver::lockAndThrottle(const QString& reason) { KLOG_DEBUG() << "Lock and throttle, reason: " << reason; RETURN_VAL_IF_FALSE(this->lock(), 0); return this->addThrottle(reason); } bool ScreenSaver::removeThrottle(uint32_t cookie) { KLOG_DEBUG() << "Remove cookie: " << cookie; auto sendMessage = QDBusMessage::createMethodCall(SCREENSAVER_DBUS_NAME, SCREENSAVER_DBUS_OBJECT_PATH, SCREENSAVER_DBUS_INTERFACE, "UnThrottle"); sendMessage << cookie; auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call UnThrottle failed: " << replyMessage.errorMessage(); return false; } return true; } bool ScreenSaver::poke() { KLOG_DEBUG() << "Call poke to screensaver"; auto sendMessage = QDBusMessage::createMethodCall(SCREENSAVER_DBUS_NAME, SCREENSAVER_DBUS_OBJECT_PATH, SCREENSAVER_DBUS_INTERFACE, "SimulateUserActivity"); auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::NoBlock); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call SimulateUserActivity failed: " << replyMessage.errorMessage(); return false; } return true; } void ScreenSaver::init() { } } // namespace Kiran kiran-session-manager-2.5.0/lib/dbus/CMakeLists.txt0000664000175000017500000000071514417211336023605 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.0) set(TARGET_NAME lib-dbus) file(GLOB_RECURSE DBUS_H_FILES ./*.h) file(GLOB_RECURSE DBUS_CPP_FILES ./*.cpp) set(ALL_FILES ${DBUS_H_FILES} ${DBUS_CPP_FILES}) add_library(${TARGET_NAME} STATIC ${ALL_FILES}) target_include_directories(${TARGET_NAME} PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include) target_link_libraries(${TARGET_NAME} PRIVATE Qt5::DBus lib-base) kiran-session-manager-2.5.0/lib/dbus/screensaver.h0000664000175000017500000000257014417211336023537 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QSharedPointer> namespace Kiran { // 对screensaver的dbus接口的封装 class ScreenSaver { public: ScreenSaver(); virtual ~ScreenSaver(){}; static QSharedPointer<ScreenSaver> getDefault(); // 锁屏 bool lock(); // 添加throttle,禁止运行屏保主题。函数返回一个cookie,可以通过cookie移除该throttle uint32_t addThrottle(const QString &reason); // 锁屏并添加throttle,如果失败则返回0,否则返回cookie uint32_t lockAndThrottle(const QString &reason); // 移除throttle bool removeThrottle(uint32_t cookie); // 模拟用户激活操作 bool poke(); private: void init(); private: static QSharedPointer<ScreenSaver> m_instance; }; } // namespace Kiran kiran-session-manager-2.5.0/lib/dbus/systemd-login1.h0000664000175000017500000000362514417211336024100 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QDBusObjectPath> #include <QSharedPointer> namespace Kiran { // 对systemd-login1的dbus接口的封装 class SystemdLogin1 { public: SystemdLogin1(); virtual ~SystemdLogin1(){}; static QSharedPointer<SystemdLogin1> getDefault(); // 是否支持关机 bool canShutdown() { return this->canDoMethod("CanPowerOff"); }; // 是否支持重启 bool canReboot() { return this->canDoMethod("CanReboot"); }; // 是否支持休眠 bool canHibernate() { return this->canDoMethod("CanHibernate"); }; // 是否支持挂起 bool canSuspend() { return this->canDoMethod("CanSuspend"); }; // 关机 bool shutdown() { return this->doMethod("PowerOff"); }; // 重启 bool reboot() { return this->doMethod("Reboot"); }; // 休眠 bool hibernate() { return this->doMethod("Hibernate"); }; // 挂起 bool suspend() { return this->doMethod("Suspend"); }; // 设置空闲提示 bool setIdleHint(bool isIdle); // 是否为当前用户的最后一个会话 bool isLastSession(); private: void init(); bool canDoMethod(const QString &methodName); bool doMethod(const QString &methodName); private: static QSharedPointer<SystemdLogin1> m_instance; QDBusObjectPath m_sessionObjectPath; }; } // namespace Kiran kiran-session-manager-2.5.0/lib/dbus/display-manager.cpp0000664000175000017500000000617414417211336024633 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "lib/dbus/display-manager.h" #include <qt5-log-i.h> #include <QDBusConnection> #include <QDBusMessage> #include <QDBusVariant> #include <QSharedPointer> #include "lib/base/def.h" namespace Kiran { #define DISPLAY_MANAGER_DBUS_NAME "org.freedesktop.DisplayManager" #define DISPLAY_MANAGER_DBUS_INTERFACE "org.freedesktop.DisplayManager.Seat" DisplayManager::DisplayManager() { this->m_xdgSeatPath = qgetenv("XDG_SEAT_PATH"); if (this->m_xdgSeatPath.isEmpty()) { KLOG_WARNING() << "Not found XDG_SEAT_PATH"; } } QSharedPointer<DisplayManager> DisplayManager::m_instance = nullptr; QSharedPointer<DisplayManager> DisplayManager::getDefault() { if (!m_instance) { m_instance = QSharedPointer<DisplayManager>::create(); } return m_instance; } bool DisplayManager::canSwitchUser() { QDBusMessage sendMessage = QDBusMessage::createMethodCall(DISPLAY_MANAGER_DBUS_NAME, this->m_xdgSeatPath, "org.freedesktop.DBus.Properties", "Get"); sendMessage << QString(DISPLAY_MANAGER_DBUS_INTERFACE) << QString("CanSwitch"); QDBusMessage replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call Get failed: " << replyMessage.errorMessage(); return false; } QList<QVariant> argList = replyMessage.arguments(); if (argList.size() == 0) { KLOG_WARNING() << "no arguments"; return false; } QVariant firstArg = argList.takeFirst(); QDBusVariant busVariant = firstArg.value<QDBusVariant>(); QVariant iconFileVar = busVariant.variant(); return iconFileVar.toBool(); } bool DisplayManager::switchUser() { auto sendMessage = QDBusMessage::createMethodCall(DISPLAY_MANAGER_DBUS_NAME, this->m_xdgSeatPath, DISPLAY_MANAGER_DBUS_INTERFACE, "SwitchToGreeter"); auto replyMessage = QDBusConnection::systemBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call SwitchToGreeter failed: " << replyMessage.errorMessage(); return false; } return true; } } // namespace Kiran kiran-session-manager-2.5.0/lib/base/0000775000175000017500000000000014417211336021017 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/lib/base/error.cpp0000664000175000017500000000402614417211336022656 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "lib/base/error.h" #include <fmt/format.h> #include <QObject> namespace Kiran { KSMError::KSMError() { } QString KSMError::getErrorDesc(KSMErrorCode error_code) { QString error_desc; switch (error_code) { case KSMErrorCode::ERROR_MANAGER_PHASE_CANNOT_REGISTER: error_desc = QObject::tr("The phase cannot be register."); case KSMErrorCode::ERROR_MANAGER_CLIENT_ALREADY_REGISTERED: error_desc = QObject::tr("The client %s already registered."); break; case KSMErrorCode::ERROR_MANAGER_GEN_UNIQUE_COOKIE_FAILED: error_desc = QObject::tr("Failed to generate unique cookie."); break; case KSMErrorCode::ERROR_MANAGER_INHIBITOR_NOTFOUND: error_desc = QObject::tr("The inhibitor is not found."); break; case KSMErrorCode::ERROR_PRESENCE_STATUS_INVALID: error_desc = QObject::tr("The status is invalid."); break; case KSMErrorCode::ERROR_MANAGER_POWER_ACTION_UNSUPPORTED: error_desc = QObject::tr("The action is not supported."); break; case KSMErrorCode::ERROR_MANAGER_PHASE_INVALID: error_desc = QObject::tr("Internal error."); break; default: error_desc = QObject::tr("Unknown error."); break; } // TODO: 测试 error_desc += QString::asprintf(QObject::tr(" (error code: 0x%x)").toStdString().c_str(), int32_t(error_code)); return error_desc; } } // namespace Kiran kiran-session-manager-2.5.0/lib/base/CMakeLists.txt0000664000175000017500000000112714417211336023560 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.0) set (TARGET_NAME lib-base) file(GLOB_RECURSE BASE_H_FILES ./*.h) file(GLOB_RECURSE BASE_CPP_FILES ./*.cpp) set (ALL_FILES ${BASE_H_FILES} ${BASE_CPP_FILES}) add_library(${TARGET_NAME} STATIC ${ALL_FILES}) target_include_directories(${TARGET_NAME} PUBLIC ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR} ${KLOG_QT5_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} PUBLIC Qt5::Core ${KLOG_QT5_LIBRARIES} ${FMT_LIBRARIES} ${JSONCPP_LIBRARIES}) kiran-session-manager-2.5.0/lib/base/error.h0000664000175000017500000000270014417211336022320 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <fmt/format.h> #include <QString> #include <cstdint> #include "ksm-error-i.h" namespace Kiran { #define KSM_ERROR2STR(errorCode) KSMError::getErrorDesc(errorCode) #define DBUS_ERROR_REPLY(type, errorCode, ...) \ { \ auto errMessage = fmt::format(KSM_ERROR2STR(errorCode).toStdString(), ##__VA_ARGS__); \ sendErrorReply(type, QString(errMessage.c_str())); \ } #define DBUS_ERROR_REPLY_AND_RET(type, errorCode, ...) \ DBUS_ERROR_REPLY(type, errorCode, ##__VA_ARGS__); \ return; class KSMError { public: KSMError(); virtual ~KSMError(){}; static QString getErrorDesc(KSMErrorCode errorCode); }; } // namespace Kirankiran-session-manager-2.5.0/lib/base/str-utils.cpp0000664000175000017500000000706714417211336023503 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "lib/base/str-utils.h" #include <algorithm> namespace Kiran { std::vector<std::string> StrUtils::split_lines(const std::string &s) { std::vector<std::string> ret; size_t i = 0; size_t line_start = 0; while (i < s.length()) { if (s[i] == '\n') { ret.push_back(s.substr(line_start, i - line_start)); i++; line_start = i; } else if (s[i] == '\r') { if ((i + 1 < s.length() && s[i + 1] != '\n') || i + 1 >= s.length()) { ret.push_back(s.substr(line_start, i - line_start)); i++; line_start = i; } else // if (i + 1 < s.length() && s[i + 1] == '\n') { ret.push_back(s.substr(line_start, i - line_start)); i += 2; line_start = i; } } else { i++; } } ret.push_back(s.substr(line_start, s.length() - line_start)); return ret; } std::string StrUtils::tolower(const std::string &str) { std::string new_str = str; std::transform(new_str.begin(), new_str.end(), new_str.begin(), ::tolower); return new_str; } std::string StrUtils::toupper(const std::string &str) { std::string new_str = str; std::transform(new_str.begin(), new_str.end(), new_str.begin(), ::toupper); return new_str; } std::vector<std::string> StrUtils::split_with_char(const std::string &s, char delimiter, bool is_merge_delimiter) { std::vector<std::string> v; size_t start = 0; size_t i = 0; while (i < s.length()) { if (delimiter == s[i]) { if (i > start || !is_merge_delimiter) { v.push_back(s.substr(start, i - start)); } i++; start = i; } else { i++; } } v.push_back(s.substr(start, s.length() - start)); return v; } std::string StrUtils::ltrim(const std::string &s) { auto iter = std::find_if(s.begin(), s.end(), [](char c) -> bool { return (std::isspace(c) == 0); }); return std::string(iter, s.end()); } std::string StrUtils::rtrim(const std::string &s) { auto iter = std::find_if(s.rbegin(), s.rend(), [](char c) -> bool { return (std::isspace(c) == 0); }); return std::string(s.begin(), iter.base()); } std::string StrUtils::trim(const std::string &s) { return StrUtils::ltrim(StrUtils::rtrim(s)); } bool StrUtils::startswith(const std::string &str, const std::string &prefix) { RETURN_VAL_IF_TRUE(str.size() < prefix.size(), false); return (str.substr(0, prefix.size()) == prefix); } bool StrUtils::endswith(const std::string &str, const std::string &suffix) { RETURN_VAL_IF_TRUE(str.size() < suffix.size(), false); return (str.substr(str.size() - suffix.size(), suffix.size()) == suffix); } } // namespace Kirankiran-session-manager-2.5.0/lib/base/str-utils.h0000664000175000017500000000362414417211336023143 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include "lib/base/base.h" namespace Kiran { class StrUtils { public: StrUtils(){}; virtual ~StrUtils(){}; static std::vector<std::string> split_lines(const std::string &s); static std::string tolower(const std::string &str); static std::string toupper(const std::string &str); static std::vector<std::string> split_with_char(const std::string &s, char delimiter, bool is_merge_delimiter = false); // 去掉字符串前后的空白字符 static std::string ltrim(const std::string &s); static std::string rtrim(const std::string &s); static std::string trim(const std::string &s); // 判断str是否以prefix字符串开头 static bool startswith(const std::string &str, const std::string &prefix); static bool endswith(const std::string &str, const std::string &suffix); template <class T> static std::string join(const std::vector<T> &vec, const std::string &join_chars); }; template <class T> std::string StrUtils::join(const std::vector<T> &vec, const std::string &join_chars) { std::string str; for (size_t i = 0; i < vec.size(); ++i) { str += fmt::format("{0}", vec[i]); if (i + 1 < vec.size()) { str += fmt::format("{0}", join_chars); } } return str; } } // namespace Kirankiran-session-manager-2.5.0/lib/base/base.h0000664000175000017500000000154714417211336022111 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <fmt/format.h> #include <qt5-log-i.h> #include <map> #include <memory> #include <string> #include <vector> #include "config.h" #include "ksm-i.h" #include "lib/base/def.h" #include "lib/base/error.h" #include "lib/base/str-utils.h"kiran-session-manager-2.5.0/lib/base/def.h0000664000175000017500000001026314417211336021730 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <fmt/format.h> #include <cstdio> #include <functional> #include <vector> namespace Kiran { #define DAEMON_DBUS_NAME "org.freedesktop.DBus" #define DAEMON_DBUS_OBJECT_PATH "/org/freedesktop/DBus" #define DAEMON_DBUS_INTERFACE_NAME "org.freedesktop.DBus" #define DAEMON_DBUS_SIGNAL_NAME_OWNER_CHANGED "NameOwnerChanged" #define SYSTEMD_DBUS_NAME "org.freedesktop.systemd1" #define SYSTEMD_DBUS_OBJECT_PATH "/org/freedesktop/systemd1" #define SYSTEMD_DBUS_INTERFACE_NAME "org.freedesktop.systemd1.Manager" #define DBUS_TIMEOUT_MS 300 #define GRESOURCE_PATH "/com/kylinsec/Kiran/SessionManager" #define EPS 1e-6 #define CONNECTION(text1, text2) text1##text2 #define CONNECT(text1, text2) CONNECTION(text1, text2) class KSMDefer { public: KSMDefer(std::function<void(std::string)> func, std::string fun_name) : func_(func), fun_name_(fun_name) {} ~KSMDefer() { func_(fun_name_); } private: std::function<void(std::string)> func_; std::string fun_name_; }; // helper macro for KSMDefer class #define SCOPE_EXIT(block) KSMDefer CONNECT(_defer_, __LINE__)([&](std::string _arg_function) block, __FUNCTION__) #define RETURN_VAL_IF_FALSE(cond, val) \ { \ if (!(cond)) \ { \ KLOG_DEBUG("The condition is false."); \ return val; \ } \ } #define RETURN_VAL_IF_TRUE(cond, val) \ { \ if (cond) return val; \ } #define RETURN_IF_FALSE(cond) \ { \ if (!(cond)) \ { \ KLOG_DEBUG("The condition is false."); \ return; \ } \ } #define RETURN_IF_TRUE(cond) \ { \ if (cond) return; \ } #define CONTINUE_IF_FALSE(cond) \ { \ if (!(cond)) continue; \ } #define CONTINUE_IF_TRUE(cond) \ { \ if (cond) continue; \ } #define IGNORE_EXCEPTION(expr) \ { \ try \ { \ expr; \ } \ catch (const Glib::Error &e) \ { \ } \ catch (const std::exception &e) \ { \ } \ } #define POINTER_TO_STRING(p) ((p) ? QString(p) : QString()) using StringHash = uint32_t; constexpr StringHash prime = 9973; constexpr StringHash basis = 0xCBF29CE4ul; constexpr StringHash hash_compile_time(char const *str, StringHash last_value = basis) { return *str ? hash_compile_time(str + 1, (StringHash)((*str ^ last_value) * (uint64_t)prime)) : last_value; } inline StringHash shash(char const *str) { StringHash ret{basis}; while (*str) { ret ^= *str; ret *= prime; str++; } return ret; } /// compile-time hash of string. /// usage: "XXX"_hash constexpr StringHash operator"" _hash(char const *p, size_t) { return hash_compile_time(p); } } // namespace Kirankiran-session-manager-2.5.0/src/0000775000175000017500000000000014417211336020126 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/src/core/0000775000175000017500000000000014417211336021056 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/src/core/xsmp-server.h0000664000175000017500000000622314417211336023525 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <glib.h> #include <QObject> /* XSMP是一套X会话管理的规范,会话管理和客户端之间的通信是遵循ICE协议规范。ICE协议规范定义了一套客户端之间的交互接口。 ICE通信的大致过程如下: 1. 初始化 1.1 客户端: 1.1.1 客户端需要调用IceRegisterForProtocolSetup函数进行协议注册,该函数返回一个主协议号。 1.1.2 客户端调用IceOpenConnection函数与服务器进行连接,获取连接的句柄 1.1.3 客户端调用IceProtocolSetup函数并附带主协议号来安装(激活)之前注册的协议 1.2 服务端: 1.2.1 服务端调用IceRegisterForProtocolReply来响应协议的激活 1.2.2 服务端调用IceListenForConnections函数来监听客户端的连接 1.2.3 当收到连接请求时,调用IceAcceptConnection获取连接句柄。 2. 连接成功 2.1 客户端和服务器分别监听连接句柄,当句柄有可读数据时,可调用IceProcessMessages接口获取数据头信息, 调用PoProcessMsgProc/IcePaProcessMsgProc获取消息体信息并进行unpack操作 */ struct _IceConn; typedef struct _IceConn *IceConn; struct _IceListenObj; typedef struct _IceListenObj *IceListenObj; namespace Kiran { struct ConnectionWatch; class XsmpServer : public QObject { Q_OBJECT public: XsmpServer(); virtual ~XsmpServer(); static XsmpServer *getInstance() { return m_instance; }; static void globalInit(); static void globalDeinit() { delete m_instance; }; signals: // 存在新的客户端连接 void newClientConnected(unsigned long *, void *); // 收到Ice连接错误或关闭的消息 void iceConnStatusChanged(int32_t, IceConn); private: void init(); // 监听网络连接 void listenSocket(); // 更新认证文件 void updateIceAuthority(); // 创建并通过IceSetPaAuthData将认证项存储在内存中 void *createAndStoreAuthEntry(const std::string &protocolName, const std::string &networkID); static gboolean onAcceptIceConnection(GIOChannel *source, GIOCondition condition, gpointer data); static gboolean onAuthIochannelWatch(GIOChannel *source, GIOCondition condition, gpointer user_data); private: static XsmpServer *m_instance; // 监听的socket总量 int m_numListenSockets; // 监听的本地socket数量 int m_numLocalListenSockets; IceListenObj *m_listenSockets; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/session-manager.h0000664000175000017500000001245414417211336024330 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QDBusContext> #include <QDBusObjectPath> #include <QList> #include <QObject> #include "ksm-i.h" class SessionManagerAdaptor; class QGSettings; class QTimer; class QProcess; namespace Kiran { class AppManager; class ClientManager; class Inhibitor; class InhibitorManager; class ExitQueryWindow; class App; class Client; class Power; class SessionManager : public QObject, protected QDBusContext { Q_OBJECT public: SessionManager(AppManager *appManager, ClientManager *clientManager, InhibitorManager *inhibitorManager); virtual ~SessionManager(); static SessionManager *getInstance() { return m_instance; }; static void globalInit(AppManager *appManager, ClientManager *clientManager, InhibitorManager *inhibitorManager); static void globalDeinit() { delete m_instance; }; // 会话开始 void start(); public Q_SLOTS: // METHODS bool CanLogout(); bool CanReboot(); bool CanShutdown(); // 获取抑制器 QString GetInhibitor(uint cookie); QString GetInhibitors(); // 添加抑制器 uint Inhibit(const QString &appID, uint toplevelXID, const QString &reason, uint flags); // 判断指定flags的抑制器是否存在 bool IsInhibited(uint flags); void Logout(uint mode); void Reboot(); QDBusObjectPath RegisterClient(const QString &appID, const QString &clientStartupID); void RequestReboot(); void RequestShutdown(); // 添加会话程序的环境变量 void Setenv(const QString &name, const QString &value); void Shutdown(); // 删除抑制器 void Uninhibit(uint inhibitCookie); Q_SIGNALS: // SIGNALS void InhibitorAdded(uint cookie); void InhibitorRemoved(uint cookie); void PhaseChanged(int phase); public Q_SLOTS: // 应用启动超时 void onPhaseStartupTimeout(); void onAppExited(App *app); void onClientAdded(Client *client); void onClientChanged(Client *client); void onClientDeleted(Client *client); void onInteractRequest(Client *client); void onInteractDone(Client *client); // xsmp客户端请求取消结束会话响应 void onShutdownCanceled(Client *client); void onEndSessionPhase2Request(Client *client); void onEndSessionResponse(Client *client); void onInhibitorAdded(QSharedPointer<Inhibitor> inhibitor); void onInhibitorDeleted(QSharedPointer<Inhibitor> inhibitor); // 退出会话确认对话框响应 void onExitWindowResponse(); // 系统信号处理 void onSystemSignal(int signo); private: void init(); void processPhase(); // 开始阶段 void processPhaseStartup(); // 准备结束会话,此时会询问已注册的客户端会话是否可以结束,客户端收到应该进行响应 void processPhaseQueryEndSession(); // 询问客户端会话是否结束处理完毕 void queryEndSessionComplete(); // 取消结束会话 void cancelEndSession(); // 会话结束第一阶段 void processPhaseEndSessionPhase1(); // 会话结束第二阶段 void processPhaseEndSessionPhase2(); // 退出阶段 void processPhaseExit(); // 如果是当前账户的最后一个会话,需要停止会话中的dbus程序 void maybeRestartUserBus(); // 开始下一个阶段 void startNextPhase(); // 处理application阶段结束 void processPhaseApplicationEnd(); // 所有跟客户端的交互都已经处理完毕,开始真正的退出会话 void quitSession(); // 触发登出动作 void doPowerAction(PowerAction power_action); // KSMLogoutAction logout_type2action(KSMPowerAction logout_type); /* ----------------- 以下为回调处理函数 ------------------- */ // 应用已启动完成回调 void onAppStartupFinished(App *app); void onWaitingSessionTimeout(std::function<void(void)> phase_complete_callback); private: static SessionManager *m_instance; SessionManagerAdaptor *m_dbusAdaptor; AppManager *m_appManager; ClientManager *m_clientManager; InhibitorManager *m_inhibitorManager; QGSettings *m_settings; // 会话运行的阶段 int32_t m_currentPhase; // 等待启动完成的应用 QList<App *> m_waitingApps; QTimer *m_waitingAppsTimeoutID; // 等待响应的客户端列表 QList<Client *> m_waitingClients; QTimer *m_waitingClientsTimeoutID; // 请求进入第二阶段的客户端列表 QList<Client *> phase2_request_clients_; Power *m_power; // 抑制对话框 // std::shared_ptr<ExitQueryWindow> exit_query_window_; PowerAction m_powerAction; QProcess *m_process; }; } // namespace Kirankiran-session-manager-2.5.0/src/core/main.cpp0000664000175000017500000001233314417211336022510 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include <QCommandLineParser> #include <QCoreApplication> #include <QFileInfo> #include <QProcessEnvironment> #include <QRegularExpression> #include <QTranslator> #include <QtGlobal> #include <iostream> #include <unistd.h> #include "config.h" #include "lib/base/base.h" #include "src/core/app/app-manager.h" #include "src/core/client/client-manager.h" #include "src/core/inhibitor-manager.h" #include "src/core/session-manager.h" #include "src/core/utils.h" #include "src/core/xsmp-server.h" using namespace Kiran; #define DBUS_LAUNCH_COMMAND "dbus-launch" void startDBusSession(int argc, char **argv) { int i = 0; RETURN_IF_TRUE(!qgetenv("DBUS_SESSION_BUS_ADDRESS").isEmpty()); RETURN_IF_TRUE(QString(argv[0]).startsWith(DBUS_LAUNCH_COMMAND)); char **new_argv = (char **)g_malloc(argc + 3 * sizeof(*argv)); new_argv[0] = (char *)DBUS_LAUNCH_COMMAND; new_argv[1] = (char *)"--exit-with-session"; for (i = 0; i < argc; i++) { new_argv[i + 2] = argv[i]; } new_argv[i + 2] = NULL; KLOG_DEBUG("Start session manager by dbus-launch."); if (!execvp(DBUS_LAUNCH_COMMAND, new_argv)) { KLOG_WARNING("No session bus and could not exec dbus-launch: %s", g_strerror(errno)); } } void initEnv() { QMap<QString, QString> envs; auto key_regex = QRegularExpression("^[A-Za-z_][A-Za-z0-9_]*$", QRegularExpression::OptimizeOnFirstUsageOption); auto value_regex = QRegularExpression("^([[:blank:]]|[^[:cntrl:]])*$", QRegularExpression::OptimizeOnFirstUsageOption); auto system_environment = QProcessEnvironment::systemEnvironment(); for (const auto &key : system_environment.keys()) { auto value = system_environment.value(key); if (key_regex.match(key).hasMatch() && value_regex.match(value).hasMatch()) { envs.insert(key, value); KLOG_DEBUG() << "Add environment: " << key << "=" << value; } else { KLOG_WARNING() << "Filter environment: " << key << "=" << value; } } Utils::getDefault()->setEnvs(envs); if (qgetenv("XDG_CURRENT_DESKTOP").isEmpty()) { Utils::getDefault()->setEnv("XDG_CURRENT_DESKTOP", "KIRAN"); } } int main(int argc, char *argv[]) { auto argv0 = QFileInfo(argv[0]); auto programName = argv0.baseName(); if (klog_qt5_init(QString(), "kylinsec-session", PROJECT_NAME, programName) < 0) { fprintf(stderr, "Failed to init kiran-log."); } // wayland方式下可能需要自己启动dbus-daemon startDBusSession(argc, argv); QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(programName); QCoreApplication::setApplicationVersion(PROJECT_VERSION); QTranslator translator; if (!translator.load(QLocale(), qAppName(), ".", KSM_INSTALL_TRANSLATIONDIR, ".qm")) { KLOG_WARNING() << "Load translator failed!"; } else { app.installTranslator(&translator); } QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); parser.addOption(QCommandLineOption(QStringList({"s", "session-type"}), app.translate("main", "Specify a session type that contains required components."), app.translate("main", "SESSION_NAME"), QStringLiteral("kiran"))); parser.addOption(QCommandLineOption(QStringList({"a", "autostart"}), app.translate("main", "Override standard autostart directories."), app.translate("main", "AUTOSTART_DIRS"), QStringLiteral(""))); parser.process(app); initEnv(); auto sessionType = parser.value(QStringLiteral("session-type")); KLOG_DEBUG() << "sessionType: " << sessionType; if (parser.isSet("autostart")) { auto autostartDirs = parser.value(QStringLiteral("autostart")); Utils::getDefault()->setAutostartDirs(autostartDirs); } AppManager::globalInit(sessionType); XsmpServer::globalInit(); InhibitorManager::globalInit(); ClientManager::globalInit(XsmpServer::getInstance()); SessionManager::globalInit(AppManager::getInstance(), ClientManager::getInstance(), InhibitorManager::getInstance()); SessionManager::getInstance()->start(); auto retval = app.exec(); SessionManager::globalDeinit(); ClientManager::globalDeinit(); InhibitorManager::globalDeinit(); XsmpServer::globalDeinit(); AppManager::globalDeinit(); return retval; } kiran-session-manager-2.5.0/src/core/session-manager.cpp0000664000175000017500000007324314417211336024666 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/session-manager.h" #include <signal.h> #include <QGSettings> #include <QJsonDocument> #include <QJsonObject> #include <QJsonValue> #include <QProcess> #include <QTimer> #include "lib/base/base.h" #include "lib/dbus/systemd-login1.h" #include "src/core/app/app-manager.h" #include "src/core/client/client-manager.h" #include "src/core/inhibitor-manager.h" #include "src/core/power.h" #include "src/core/presence.h" #include "src/core/session_manager_adaptor.h" #include "src/core/signal-handler.h" #include "src/core/utils.h" namespace Kiran { // 在一个阶段等待所有应用的最长时间(秒) #define KSM_PHASE_STARTUP_TIMEOUT 5 SessionManager::SessionManager(AppManager *app_manager, ClientManager *client_manager, InhibitorManager *inhibitor_manager) : QObject(nullptr), m_appManager(app_manager), m_clientManager(client_manager), m_inhibitorManager(inhibitor_manager), m_currentPhase(KSMPhase::KSM_PHASE_IDLE), m_powerAction(PowerAction::POWER_ACTION_NONE) { this->m_dbusAdaptor = new SessionManagerAdaptor(this); this->m_settings = new QGSettings(KSM_SCHEMA_ID, "", this); this->m_power = new Power(this); this->m_process = new QProcess(this); this->m_waitingAppsTimeoutID = new QTimer(this); this->m_waitingClientsTimeoutID = new QTimer(this); } SessionManager::~SessionManager() { } SessionManager *SessionManager::m_instance = nullptr; void SessionManager::globalInit(AppManager *appManager, ClientManager *clientManager, InhibitorManager *inhibitorManager) { m_instance = new SessionManager(appManager, clientManager, inhibitorManager); m_instance->init(); } void SessionManager::start() { this->m_currentPhase = KSMPhase::KSM_PHASE_DISPLAY_SERVER; this->processPhase(); } bool SessionManager::CanLogout() { return true; } bool SessionManager::CanReboot() { return this->m_power->canPowerAction(PowerAction::POWER_ACTION_REBOOT); } bool SessionManager::CanShutdown() { return this->m_power->canPowerAction(PowerAction::POWER_ACTION_SHUTDOWN); } QString SessionManager::GetInhibitor(uint cookie) { QJsonDocument jsonDoc; QJsonObject jsonObj; auto inhibitor = InhibitorManager::getInstance()->getInhibitor(cookie); if (inhibitor) { jsonObj = QJsonObject{ {KSM_INHIBITOR_JK_COOKIE, int(inhibitor->cookie)}, {KSM_INHIBITOR_JK_APP_ID, inhibitor->appID}, {KSM_INHIBITOR_JK_TOPLEVEL_XID, int(inhibitor->toplevelXID)}, {KSM_INHIBITOR_JK_REASON, inhibitor->reason}, {KSM_INHIBITOR_JK_FLAGS, int(inhibitor->flags)}, }; } jsonDoc.setObject(jsonObj); return QString(jsonDoc.toJson()); } QString SessionManager::GetInhibitors() { QJsonDocument jsonDoc; QJsonArray jsonArr; int32_t i = 0; for (auto inhibitor : this->m_inhibitorManager->getInhibitors()) { QJsonObject jsonObj{ {KSM_INHIBITOR_JK_COOKIE, int(inhibitor->cookie)}, {KSM_INHIBITOR_JK_APP_ID, inhibitor->appID}, {KSM_INHIBITOR_JK_TOPLEVEL_XID, int(inhibitor->toplevelXID)}, {KSM_INHIBITOR_JK_REASON, inhibitor->reason}, {KSM_INHIBITOR_JK_FLAGS, int(inhibitor->flags)}, }; jsonArr.push_back(jsonObj); } jsonDoc.setArray(jsonArr); return QString(jsonDoc.toJson()); } uint SessionManager::SessionManager::Inhibit(const QString &appID, uint toplevelXID, const QString &reason, uint flags) { KLOG_DEBUG() << "App id: " << appID << ", toplevel xid: " << toplevelXID << ", reason: " << reason << ", flags: " << flags; auto inhibitor = this->m_inhibitorManager->addInhibitor(appID, toplevelXID, reason, flags); if (!inhibitor) { DBUS_ERROR_REPLY(QDBusError::Failed, KSMErrorCode::ERROR_MANAGER_GEN_UNIQUE_COOKIE_FAILED); return 0; } return inhibitor->cookie; } bool SessionManager::IsInhibited(uint flags) { return InhibitorManager::getInstance()->hasInhibitor(flags); } void SessionManager::Logout(uint mode) { if (this->m_currentPhase > KSMPhase::KSM_PHASE_RUNNING) { DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_INVALID); } if (!this->m_power->canPowerAction(PowerAction::POWER_ACTION_LOGOUT)) { DBUS_ERROR_REPLY_AND_RET(QDBusError::AccessDenied, KSMErrorCode::ERROR_MANAGER_POWER_ACTION_UNSUPPORTED); } this->m_powerAction = PowerAction::POWER_ACTION_LOGOUT; this->startNextPhase(); } void SessionManager::Reboot() { if (this->m_currentPhase > KSMPhase::KSM_PHASE_RUNNING) { DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_INVALID); } if (!this->m_power->canPowerAction(PowerAction::POWER_ACTION_REBOOT)) { DBUS_ERROR_REPLY_AND_RET(QDBusError::AccessDenied, KSMErrorCode::ERROR_MANAGER_POWER_ACTION_UNSUPPORTED); } this->m_powerAction = PowerAction::POWER_ACTION_REBOOT; this->startNextPhase(); } QDBusObjectPath SessionManager::RegisterClient(const QString &appID, const QString &clientStartupID) { KLOG_DEBUG() << "App id: " << appID << " , startup id: " << clientStartupID; if (this->m_currentPhase > KSMPhase::KSM_PHASE_RUNNING) { DBUS_ERROR_REPLY(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_CANNOT_REGISTER); return QDBusObjectPath(); } auto client = this->m_clientManager->addClientDBus(clientStartupID, this->message().service(), appID); if (!client) { DBUS_ERROR_REPLY(QDBusError::Failed, KSMErrorCode::ERROR_MANAGER_CLIENT_ALREADY_REGISTERED, clientStartupID.toUtf8().data()); return QDBusObjectPath(); } return client->getObjectPath(); } void SessionManager::RequestReboot() { this->Reboot(); } void SessionManager::RequestShutdown() { this->Shutdown(); } void SessionManager::Setenv(const QString &name, const QString &value) { KLOG_DEBUG() << "Set environment variable. name: " << name << ", value: " << value; if (this->m_currentPhase > KSMPhase::KSM_PHASE_INITIALIZATION) { DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_INVALID); } Utils::getDefault()->setEnv(name, value); } void SessionManager::Shutdown() { if (this->m_currentPhase > KSMPhase::KSM_PHASE_RUNNING) { DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_MANAGER_PHASE_INVALID); } if (!this->m_power->canPowerAction(PowerAction::POWER_ACTION_SHUTDOWN)) { DBUS_ERROR_REPLY_AND_RET(QDBusError::AccessDenied, KSMErrorCode::ERROR_MANAGER_POWER_ACTION_UNSUPPORTED); } this->m_powerAction = PowerAction::POWER_ACTION_SHUTDOWN; this->startNextPhase(); } void SessionManager::Uninhibit(uint inhibitCookie) { auto inhibitor = InhibitorManager::getInstance()->getInhibitor(inhibitCookie); if (!inhibitor) { DBUS_ERROR_REPLY_AND_RET(QDBusError::Failed, KSMErrorCode::ERROR_MANAGER_INHIBITOR_NOTFOUND); } InhibitorManager::getInstance()->deleteInhibitor(inhibitCookie); } void SessionManager::onPhaseStartupTimeout() { switch (this->m_currentPhase) { case KSMPhase::KSM_PHASE_IDLE: case KSMPhase::KSM_PHASE_DISPLAY_SERVER: case KSMPhase::KSM_PHASE_POST_DISPLAY_SERVER: case KSMPhase::KSM_PHASE_INITIALIZATION: case KSMPhase::KSM_PHASE_WINDOW_MANAGER: case KSMPhase::KSM_PHASE_PANEL: case KSMPhase::KSM_PHASE_DESKTOP: case KSMPhase::KSM_PHASE_APPLICATION: { for (auto app : this->m_waitingApps) { KLOG_WARNING() << "Wait app " << app->getAppID() << " startup timeout."; } break; } default: break; } this->m_waitingAppsTimeoutID->stop(); this->startNextPhase(); } void SessionManager::onWaitingSessionTimeout(std::function<void(void)> phase_complete_callback) { KLOG_WARNING() << "Wait session timeout."; for (auto client : this->m_waitingClients) { KLOG_WARNING() << "The client " << client->getID() << " doesn't response message. phase: " << App::phaseEnum2str(this->m_currentPhase); // 将交互超时的客户端加入抑制器 this->m_inhibitorManager->addInhibitor(client->getAppID(), 0, tr("This program is not responding"), KSMInhibitorFlag::KSM_INHIBITOR_FLAG_QUIT, client->getID()); } phase_complete_callback(); this->m_waitingClientsTimeoutID->disconnect(); this->m_waitingClientsTimeoutID->stop(); } void SessionManager::onAppExited(App *app) { this->onAppStartupFinished(app); } void SessionManager::onClientAdded(Client *client) { RETURN_IF_FALSE(client); KLOG_DEBUG() << "Client " << client->getID() << " added."; auto app = this->m_appManager->getAppByStartupID(client->getID()); if (!app) { KLOG_DEBUG() << "Not found app for the client " << client->getID(); return; } KLOG_DEBUG() << "The new client " << client->getID() << " match the app " << app->getAppID(); // 此时说明kiran-session-daemon已经关闭掉与mate-settings-daemon冲突的插件,这时可以运行mate-settings-daemon auto iter = std::find_if(this->m_waitingApps.begin(), this->m_waitingApps.end(), [](App *app) { return app->getAppID() == "mate-settings-daemon.desktop"; }); if (app->getAppID() == "kiran-session-daemon.desktop" && iter != this->m_waitingApps.end()) { KLOG_DEBUG() << "Start to boot " << (*iter)->getAppID(); (*iter)->start(); } this->onAppStartupFinished(app); } void SessionManager::onClientChanged(Client *client) { RETURN_IF_FALSE(client); // 通过xsmp协议添加客户端时,还不能获取到客户端的属性信息,所以需要在属性变化时再次进行判断 KLOG_DEBUG() << "Client " << client->getID() << " changed."; auto appID = client->getAppID(); if (!appID.isEmpty()) { auto app = this->m_appManager->getApp(appID); if (!app) { KLOG_DEBUG() << "Not found app by " << appID; return; } KLOG_DEBUG() << "The client " << client->getID() << " match the app " << app->getAppID(); this->onAppStartupFinished(app); } } void SessionManager::onClientDeleted(Client *client) { RETURN_IF_FALSE(client); KLOG_DEBUG() << "Client " << client->getID() << " deleted, AppID: " << client->getAppID(); // 客户端断开连接或者异常退出后无法再响应会话管理的请求,因此这里主动调用一次客户端响应回调函数来处理该客户端 this->onEndSessionResponse(client); if (this->m_currentPhase == KSMPhase::KSM_PHASE_RUNNING) { auto app = this->m_appManager->getAppByStartupID(client->getID()); /* QT应用程序不会使用会话管理通过DESKTOP_AUTOSTART_ID环境变量传递的值作为StartupID,在执行onRegisterClient回调时, QT传递的previousID为空,因此会话管理又重新生成了一个新的StartupID给QT程序,因此通过getAppByStartupID函数是无法找到 对应App对象的,因此这里计划通过Xsmp协议中ProgramName属性来作为AppID,然后关联到App对象。*/ if (!app) { app = this->m_appManager->getApp(client->getAppID()); } if (!app) { KLOG_DEBUG() << "No corresponding app found for client " << client->getID(); } /* 这里不调用restart而是start的原因是因为存在如下情况: 当已经存在一个caja进程时,再次运行caja,caja会重新发送一个新的clientID(正常逻辑应该是发送第一次启动caja时的ClientID) 而这个新发送的ClientID在稍后又被caja给关闭了,这样就会触发ClientDeleted信号,而且会触发两次, 第一次是通过dbus协议发送(监听name lost信号),第二次是通过x协议发送,在第二次时getAppID会查找到第一个clientID, 这样就导致app被重启(而实际上caja并未退出),然后caja又会循环这样的操作,导致caja一直无法拉起 */ if (app && app->getAutoRestart()) { QTimer::singleShot(600, app, &App::start); } } } void SessionManager::onInteractRequest(Client *client) { RETURN_IF_FALSE(this->m_currentPhase == KSMPhase::KSM_PHASE_QUERY_END_SESSION); // 需要跟用户进行交互,因此此处需要添加抑制器,不能马上进行退出操作 this->m_inhibitorManager->addInhibitor(client->getAppID(), 0, tr("This program is blocking exit"), KSMInhibitorFlag::KSM_INHIBITOR_FLAG_QUIT, client->getID()); /* 当通过SmsSaveYourself向xsmp客户端发起QueryEndSession时,客户端可能要求与用户交互(InteractRequest),也可能直接回复SaveYourselfDone, 无论是那种情况,都表示客户端已经收到了会话管理发送的消息,因此应该将该客户端从等待队列中删除。这里为了方便直接调用on_end_session_response_cb 函数进行处理了,如果后续需要针对这两个消息做不同的处理,此处的逻辑需要修改。*/ this->onEndSessionResponse(client); } void SessionManager::onInteractDone(Client *client) { this->m_inhibitorManager->deleteInhibitorByStartupID(client->getID()); } void SessionManager::onShutdownCanceled(Client *client) { KLOG_DEBUG() << "Client: " << client->getID() << " cancels shutdown."; this->cancelEndSession(); } void SessionManager::onEndSessionPhase2Request(Client *client) { KLOG_DEBUG() << "Receive client: " << client->getID() << " phase2 request."; // 需要第一阶段结束的所有客户端响应后才能进入第二阶段,因此这里先缓存第二阶段请求的客户端 this->phase2_request_clients_.push_back(client); } void SessionManager::onEndSessionResponse(Client *client) { RETURN_IF_FALSE(client); KLOG_DEBUG() << "Receive client " << client->getID() << " end session response. phase: " << App::phaseEnum2str(this->m_currentPhase); RETURN_IF_TRUE(this->m_currentPhase < KSMPhase::KSM_PHASE_QUERY_END_SESSION); auto iter = std::remove_if(this->m_waitingClients.begin(), this->m_waitingClients.end(), [client](Client *item) { return client->getID() == item->getID(); }); this->m_waitingClients.erase(iter, this->m_waitingClients.end()); if (m_waitingClients.size() == 0) { switch (this->m_currentPhase) { case KSMPhase::KSM_PHASE_QUERY_END_SESSION: this->queryEndSessionComplete(); break; case KSMPhase::KSM_PHASE_END_SESSION_PHASE1: case KSMPhase::KSM_PHASE_END_SESSION_PHASE2: this->startNextPhase(); break; default: KLOG_WARNING() << "The phase is invalid. current phase: " << App::phaseEnum2str(this->m_currentPhase) << ", client id: " << client->getID(); break; } } } void SessionManager::onInhibitorAdded(QSharedPointer<Inhibitor> inhibitor) { Q_EMIT this->InhibitorAdded(inhibitor->cookie); } void SessionManager::onInhibitorDeleted(QSharedPointer<Inhibitor> inhibitor) { Q_EMIT this->InhibitorRemoved(inhibitor->cookie); } void SessionManager::onExitWindowResponse() { QJsonParseError jsonError; this->m_process->disconnect(); auto standardOutput = this->m_process->readAllStandardOutput(); KLOG_DEBUG() << "Standard output: " << standardOutput; auto jsonDoc = QJsonDocument::fromJson(standardOutput, &jsonError); if (jsonDoc.isNull()) { KLOG_WARNING() << "Parser standard output failed: " << jsonError.errorString(); this->cancelEndSession(); return; } auto jsonRoot = jsonDoc.object(); auto responseID = jsonRoot["response_id"].toString().toLower(); switch (shash(responseID.toUtf8().data())) { case "ok"_hash: this->startNextPhase(); break; default: this->cancelEndSession(); break; } } void SessionManager::onSystemSignal(int signo) { KLOG_DEBUG("Receive signal: %d.", signo); if (signo == SIGTERM) { this->quitSession(); } } void SessionManager::init() { this->m_power->init(); this->m_waitingAppsTimeoutID->setInterval(KSM_PHASE_STARTUP_TIMEOUT * 1000); connect(this->m_waitingAppsTimeoutID, SIGNAL(timeout()), this, SLOT(onPhaseStartupTimeout())); connect(this->m_appManager, SIGNAL(AppExited(App *)), this, SLOT(onAppExited(App *))); connect(this->m_clientManager, SIGNAL(clientAdded(Client *)), this, SLOT(onClientAdded(Client *))); connect(this->m_clientManager, SIGNAL(clientChanged(Client *)), this, SLOT(onClientChanged(Client *))); connect(this->m_clientManager, SIGNAL(clientDeleted(Client *)), this, SLOT(onClientDeleted(Client *))); connect(this->m_clientManager, SIGNAL(interactRequesting(Client *)), this, SLOT(onInteractRequest(Client *))); connect(this->m_clientManager, SIGNAL(interactDone(Client *)), this, SLOT(onInteractDone(Client *))); connect(this->m_clientManager, SIGNAL(shutdownCanceled(Client *)), this, SLOT(onShutdownCanceled(Client *))); connect(this->m_clientManager, SIGNAL(endSessionPhase2Requesting(Client *)), this, SLOT(onEndSessionPhase2Request(Client *))); connect(this->m_clientManager, SIGNAL(endSessionResponse(Client *)), this, SLOT(onEndSessionResponse(Client *))); connect(this->m_inhibitorManager, SIGNAL(inhibitorAdded(QSharedPointer<Inhibitor>)), this, SLOT(onInhibitorAdded(QSharedPointer<Inhibitor>))); connect(this->m_inhibitorManager, SIGNAL(inhibitorDeleted(QSharedPointer<Inhibitor>)), this, SLOT(onInhibitorDeleted(QSharedPointer<Inhibitor>))); auto sessionConnection = QDBusConnection::sessionBus(); if (!sessionConnection.registerService(KSM_DBUS_NAME)) { KLOG_WARNING() << "Failed to register dbus name: " << KSM_DBUS_NAME; } if (!sessionConnection.registerObject(KSM_DBUS_OBJECT_PATH, this)) { KLOG_WARNING() << "Can't register object:" << sessionConnection.lastError(); } } void SessionManager::processPhase() { KLOG_DEBUG() << "Start phase: " << App::phaseEnum2str(this->m_currentPhase); this->m_waitingApps.clear(); this->m_waitingAppsTimeoutID->stop(); this->m_waitingClients.clear(); this->m_waitingClientsTimeoutID->disconnect(); this->m_waitingClientsTimeoutID->stop(); Q_EMIT this->PhaseChanged(this->m_currentPhase); switch (this->m_currentPhase) { case KSMPhase::KSM_PHASE_DISPLAY_SERVER: case KSMPhase::KSM_PHASE_POST_DISPLAY_SERVER: case KSMPhase::KSM_PHASE_INITIALIZATION: case KSMPhase::KSM_PHASE_WINDOW_MANAGER: case KSMPhase::KSM_PHASE_PANEL: case KSMPhase::KSM_PHASE_DESKTOP: case KSMPhase::KSM_PHASE_APPLICATION: this->processPhaseStartup(); break; case KSMPhase::KSM_PHASE_RUNNING: break; case KSMPhase::KSM_PHASE_QUERY_END_SESSION: this->processPhaseQueryEndSession(); break; case KSMPhase::KSM_PHASE_END_SESSION_PHASE1: this->processPhaseEndSessionPhase1(); break; case KSMPhase::KSM_PHASE_END_SESSION_PHASE2: this->processPhaseEndSessionPhase2(); break; case KSMPhase::KSM_PHASE_EXIT: this->processPhaseExit(); break; default: break; } } void SessionManager::processPhaseStartup() { auto apps = this->m_appManager->startApps(this->m_currentPhase); // 在KSM_PHASE_APPLICATION阶段前启动的应用在运行后需要(通过dbus或者xsmp规范)告知会话管理自己已经启动成功,这样会话管理才会进入下一个阶段。 if (this->m_currentPhase < KSMPhase::KSM_PHASE_APPLICATION) { this->m_waitingApps = std::move(apps); } // 一些应用需要延时执行或者需要等待其启动完毕的信号 if (this->m_waitingApps.size() > 0) { if (this->m_currentPhase < KSMPhase::KSM_PHASE_APPLICATION) { this->m_waitingAppsTimeoutID->start(); } } else { this->startNextPhase(); } } void SessionManager::processPhaseQueryEndSession() { for (auto client : this->m_clientManager->getClients()) { if (!client->queryEndSession(true)) { KLOG_WARNING() << "Failed to query client:" << client->getID(); } else { this->m_waitingClients.push_back(client); } } if (this->m_waitingClients.size() > 0) { connect(this->m_waitingClientsTimeoutID, &QTimer::timeout, [this]() -> void { this->onWaitingSessionTimeout(std::bind(&SessionManager::queryEndSessionComplete, this)); }); this->m_waitingClientsTimeoutID->start(300); } else { this->startNextPhase(); } } void SessionManager::queryEndSessionComplete() { KLOG_DEBUG() << "Query end session complete."; if (this->m_currentPhase != KSMPhase::KSM_PHASE_QUERY_END_SESSION) { KLOG_WARNING() << "The phase is error. phase: " << App::phaseEnum2str(this->m_currentPhase); return; } this->m_waitingClients.clear(); this->m_waitingClientsTimeoutID->disconnect(); this->m_waitingClientsTimeoutID->stop(); // 如果不存在退出会话的抑制器,则直接进入下一个阶段 if (!this->m_inhibitorManager->hasInhibitor(KSMInhibitorFlag::KSM_INHIBITOR_FLAG_QUIT)) { this->startNextPhase(); return; } if (this->m_process->state() != QProcess::Running) { this->m_process->setProgram("/usr/bin/kiran-session-window"); this->m_process->setArguments(QStringList(QString("--power-action=%1").arg(this->m_powerAction))); this->m_process->start(); connect(this->m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onExitWindowResponse())); } } void SessionManager::cancelEndSession() { RETURN_IF_TRUE(this->m_currentPhase < KSMPhase::KSM_PHASE_QUERY_END_SESSION); // 如果取消退出,则之前通过Interact Request请求加入的抑制器需要全部移除 this->m_inhibitorManager->deleteInhibitorsWithStartupID(); for (auto client : this->m_clientManager->getClients()) { if (!client->cancelEndSession()) { KLOG_WARNING() << "Failed to cancel end session for the client: " << client->getID(); } } // this->exit_query_window_ = nullptr; this->m_powerAction = PowerAction::POWER_ACTION_NONE; // 回到运行阶段 this->m_currentPhase = KSMPhase::KSM_PHASE_RUNNING; // 不能在process_phase中清理第二阶段缓存客户端,因为在调用process_phase_end_session_phase2函数时需要使用 this->phase2_request_clients_.clear(); this->processPhase(); } void SessionManager::processPhaseEndSessionPhase1() { for (auto client : this->m_clientManager->getClients()) { if (!client->endSession(false)) { KLOG_WARNING() << "Failed to end client: " << client->getID(); } else { this->m_waitingClients.push_back(client); } } if (this->m_waitingClients.size() > 0) { connect(this->m_waitingClientsTimeoutID, &QTimer::timeout, [this]() -> void { this->onWaitingSessionTimeout(std::bind(&SessionManager::startNextPhase, this)); }); this->m_waitingClientsTimeoutID->start(KSM_PHASE_STARTUP_TIMEOUT * 1000); } else { this->startNextPhase(); } } void SessionManager::processPhaseEndSessionPhase2() { // 如果有客户端需要进行第二阶段的数据保存操作,则告知这些客户端现在可以开始进行了 if (this->phase2_request_clients_.size() > 0) { for (auto client : this->phase2_request_clients_) { if (!client->endSessionPhase2()) { KLOG_WARNING() << "Failed to end session phase2 for the client: " << client->getID(); } else { this->m_waitingClients.push_back(client); } } this->phase2_request_clients_.clear(); } if (this->m_waitingClients.size() > 0) { connect(this->m_waitingClientsTimeoutID, &QTimer::timeout, [this]() -> void { this->onWaitingSessionTimeout(std::bind(&SessionManager::startNextPhase, this)); }); this->m_waitingClientsTimeoutID->start(KSM_PHASE_STARTUP_TIMEOUT * 1000); } else { this->startNextPhase(); } } void SessionManager::processPhaseExit() { for (auto client : this->m_clientManager->getClients()) { if (!client->stop()) { KLOG_WARNING() << "Failed to stop client: " << client->getID(); } } // FIXBUG: #53714 this->maybeRestartUserBus(); this->startNextPhase(); } void SessionManager::maybeRestartUserBus() { RETURN_IF_TRUE(!SystemdLogin1::getDefault()->isLastSession()); KLOG_DEBUG() << "Restart dbus.service."; auto sendMessage = QDBusMessage::createMethodCall(SYSTEMD_DBUS_NAME, SYSTEMD_DBUS_OBJECT_PATH, SYSTEMD_DBUS_INTERFACE_NAME, "TryRestartUnit"); sendMessage << QString("dbus.service") << QString("replace"); auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call TryRestartUnit failed: " << replyMessage.errorMessage(); } } void SessionManager::startNextPhase() { bool start_next_phase = true; switch (this->m_currentPhase) { case KSMPhase::KSM_PHASE_IDLE: case KSMPhase::KSM_PHASE_DISPLAY_SERVER: case KSMPhase::KSM_PHASE_POST_DISPLAY_SERVER: case KSMPhase::KSM_PHASE_INITIALIZATION: case KSMPhase::KSM_PHASE_WINDOW_MANAGER: case KSMPhase::KSM_PHASE_PANEL: case KSMPhase::KSM_PHASE_DESKTOP: break; case KSMPhase::KSM_PHASE_APPLICATION: this->processPhaseApplicationEnd(); break; case KSMPhase::KSM_PHASE_RUNNING: break; case KSMPhase::KSM_PHASE_QUERY_END_SESSION: break; case KSMPhase::KSM_PHASE_END_SESSION_PHASE1: // if (auto_save_is_enabled(manager)) // maybe_save_session(manager); break; case KSMPhase::KSM_PHASE_EXIT: this->quitSession(); start_next_phase = false; break; default: break; } if (start_next_phase) { this->m_currentPhase = (KSMPhase)(this->m_currentPhase + 1); KLOG_DEBUG() << "Start next phase: " << App::phaseEnum2str(this->m_currentPhase); this->processPhase(); } else { KLOG_DEBUG() << "Keep current phase: " << App::phaseEnum2str(this->m_currentPhase); } } void SessionManager::processPhaseApplicationEnd() { connect(SignalHandler::get_default(), &SignalHandler::signalReceived, QCoreApplication::instance(), std::bind(&SessionManager::onSystemSignal, this, std::placeholders::_1)); /* 需要监听SIGTERM信号,否则在maybeRestartUserBus函数中重置dbus.service时会发送SIGTERM信号, 导致程序直接退出进入登录界面,如果此时是重启请求,则重启功能失效。*/ SignalHandler::get_default()->addSignal(SIGTERM); } void SessionManager::quitSession() { KLOG_DEBUG("Quit Session."); this->m_power->doPowerAction(this->m_powerAction); QCoreApplication::instance()->quit(); } void SessionManager::onAppStartupFinished(App *app) { RETURN_IF_FALSE(app); auto iter = std::remove_if(this->m_waitingApps.begin(), this->m_waitingApps.end(), [app](App *item) -> bool { return item->getAppID() == app->getAppID(); }); this->m_waitingApps.erase(iter, this->m_waitingApps.end()); if (this->m_waitingApps.size() == 0 && this->m_currentPhase < KSMPhase::KSM_PHASE_APPLICATION) { if (this->m_waitingAppsTimeoutID->isActive()) { this->m_waitingAppsTimeoutID->stop(); } this->startNextPhase(); } } } // namespace Kiran kiran-session-manager-2.5.0/src/core/power.h0000664000175000017500000000224614417211336022367 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QObject> #include "ksm-i.h" namespace Kiran { class Power : public QObject { Q_OBJECT public: Power(QObject *parent); virtual ~Power(){}; void init(); // 是否可以执行该电源行为 bool canPowerAction(PowerAction powerAction); // 执行电源行为 bool doPowerAction(PowerAction powerAction); private: // 切换用户 bool switchUser(); // 挂起 bool suspend(); // 休眠 bool hibernate(); // 关机 bool shutdown(); // 重启 bool reboot(); }; } // namespace Kirankiran-session-manager-2.5.0/src/core/power.cpp0000664000175000017500000000627414417211336022727 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/power.h" #include "lib/base/base.h" #include "lib/dbus/display-manager.h" #include "lib/dbus/screensaver.h" #include "lib/dbus/systemd-login1.h" namespace Kiran { Power::Power(QObject *parent) : QObject(parent) { } void Power::init() { } bool Power::canPowerAction(PowerAction powerAction) { KLOG_DEBUG() << "Power action: " << powerAction; switch (powerAction) { case PowerAction::POWER_ACTION_SWITCH_USER: return DisplayManager::getDefault()->canSwitchUser(); case PowerAction::POWER_ACTION_LOGOUT: return true; case PowerAction::POWER_ACTION_SUSPEND: return SystemdLogin1::getDefault()->canSuspend(); case PowerAction::POWER_ACTION_HIBERNATE: return SystemdLogin1::getDefault()->canHibernate(); case PowerAction::POWER_ACTION_SHUTDOWN: return SystemdLogin1::getDefault()->canShutdown(); case PowerAction::POWER_ACTION_REBOOT: return SystemdLogin1::getDefault()->canReboot(); default: break; } return true; } bool Power::doPowerAction(PowerAction powerAction) { KLOG_DEBUG() << "Power action: " << powerAction; switch (powerAction) { case PowerAction::POWER_ACTION_SWITCH_USER: return this->switchUser(); case PowerAction::POWER_ACTION_LOGOUT: break; case PowerAction::POWER_ACTION_SUSPEND: return this->suspend(); case PowerAction::POWER_ACTION_HIBERNATE: return this->hibernate(); case PowerAction::POWER_ACTION_SHUTDOWN: return this->shutdown(); case PowerAction::POWER_ACTION_REBOOT: return this->reboot(); default: break; } return true; } bool Power::switchUser() { RETURN_VAL_IF_TRUE(!DisplayManager::getDefault()->canSwitchUser(), false); return DisplayManager::getDefault()->switchUser(); } bool Power::suspend() { RETURN_VAL_IF_TRUE(!SystemdLogin1::getDefault()->canSuspend(), false); // 这里忽略锁屏失败的情况 ScreenSaver::getDefault()->lock(); return SystemdLogin1::getDefault()->suspend(); } bool Power::hibernate() { RETURN_VAL_IF_TRUE(!SystemdLogin1::getDefault()->canHibernate(), false); // 这里忽略锁屏失败的情况 ScreenSaver::getDefault()->lock(); return SystemdLogin1::getDefault()->hibernate(); } bool Power::shutdown() { RETURN_VAL_IF_TRUE(!SystemdLogin1::getDefault()->canShutdown(), false); return SystemdLogin1::getDefault()->shutdown(); } bool Power::reboot() { RETURN_VAL_IF_TRUE(!SystemdLogin1::getDefault()->canReboot(), false); return SystemdLogin1::getDefault()->reboot(); } } // namespace Kirankiran-session-manager-2.5.0/src/core/utils.cpp0000664000175000017500000001230314417211336022721 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/utils.h" #include <stdlib.h> #include <sys/time.h> #include <unistd.h> #include <QDBusConnection> #include <QDBusMessage> #include <QDBusMetaType> #include <QStandardPaths> #include "lib/base/base.h" namespace Kiran { /* The XSMP spec defines the ID as: * * Version: "1" * Address type and address: * "1" + an IPv4 address as 8 hex digits * "2" + a DECNET address as 12 hex digits * "6" + an IPv6 address as 32 hex digits * Time stamp: milliseconds since UNIX epoch as 13 decimal digits * Process-ID type and process-ID: * "1" + POSIX PID as 10 decimal digits * Sequence number as 4 decimal digits * * XSMP client IDs are supposed to be globally unique: if * SmsGenerateClientID() is unable to determine a network * address for the machine, it gives up and returns %NULL. * MATE and KDE have traditionally used a fourth address * format in this case: * "0" + 16 random hex digits * * We don't even bother trying SmsGenerateClientID(), since the * user's IP address is probably "192.168.1.*" anyway, so a random * number is actually more likely to be globally unique. */ Utils::Utils() : m_useCustomAutostartDirs(false) { qDBusRegisterMetaType<QMap<QString, QString>>(); } QSharedPointer<Utils> Utils::m_instance = nullptr; QSharedPointer<Utils> Utils::getDefault() { if (!m_instance) { m_instance = QSharedPointer<Utils>::create(); } return m_instance; } QString Utils::generateStartupID() { static int sequence = -1; static uint32_t rand1 = 0; static uint32_t rand2 = 0; static pid_t pid = 0; struct timeval tv; if (!rand1) { rand1 = rand(); rand2 = rand(); pid = getpid(); } sequence = (sequence + 1) % 10000; gettimeofday(&tv, NULL); return QString::asprintf("10%.04x%.04x%.10lu%.3u%.10lu%.4d", rand1, rand2, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec, (unsigned long)pid, sequence); } void Utils::setAutostartDirs(const QString &autostartDirs) { this->m_customAutostartDirs = autostartDirs.split(';'); this->m_useCustomAutostartDirs = true; } QStringList Utils::getAutostartDirs() { if (this->m_useCustomAutostartDirs) { return this->m_customAutostartDirs; } QStringList autostartDirs; auto configDirs = QStandardPaths::standardLocations(QStandardPaths::StandardLocation::ConfigLocation); for (auto &iter : configDirs) { autostartDirs.push_back(iter + "/autostart"); } return autostartDirs; } void Utils::setEnv(const QString &name, const QString &value) { KLOG_DEBUG() << "Name: " << name << ", value: " << value; qputenv(name.toStdString().c_str(), value.toUtf8()); QMap<QString, QString> envs{{name, value}}; this->setEnvs(envs); } void Utils::setEnvs(const QMap<QString, QString> &envs) { QStringList listEnv; for (const auto &key : envs.keys()) { auto env = QString("%1=%2").arg(key).arg(envs.value(key)); listEnv.push_back(env); } KLOG_DEBUG() << "Set environments: " << listEnv.join(QStringLiteral(";")); { auto sendMessage = QDBusMessage::createMethodCall(DAEMON_DBUS_NAME, DAEMON_DBUS_OBJECT_PATH, DAEMON_DBUS_INTERFACE_NAME, "UpdateActivationEnvironment"); sendMessage << QVariant::fromValue(envs); auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call UpdateActivationEnvironment failed: " << replyMessage.errorMessage(); } } { auto sendMessage = QDBusMessage::createMethodCall(SYSTEMD_DBUS_NAME, SYSTEMD_DBUS_OBJECT_PATH, SYSTEMD_DBUS_INTERFACE_NAME, "SetEnvironment"); sendMessage << QVariant::fromValue(listEnv); auto replyMessage = QDBusConnection::sessionBus().call(sendMessage, QDBus::Block, DBUS_TIMEOUT_MS); if (replyMessage.type() == QDBusMessage::ErrorMessage) { KLOG_WARNING() << "Call SetEnvironment failed: " << replyMessage.errorMessage(); } } } uint32_t Utils::generateCookie() { return rand(); } } // namespace Kirankiran-session-manager-2.5.0/src/core/signal-handler.h0000664000175000017500000000223414417211336024120 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QObject> #include <QSet> #include <QSocketNotifier> namespace Kiran { class SignalHandler : public QObject { Q_OBJECT public: virtual ~SignalHandler(); static SignalHandler *get_default(); void addSignal(int signal); Q_SIGNALS: void signalReceived(int signal); private: SignalHandler(); void handleSignal(); static void signalHandler(int signal); private: static SignalHandler *m_instance; QSocketNotifier *m_handler; QSet<int> m_signos; static int signalFD[2]; }; } // namespace Kirankiran-session-manager-2.5.0/src/core/CMakeLists.txt0000664000175000017500000000432514417211336023622 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.0) file(GLOB_RECURSE SRC_H_FILES ./*.h) file(GLOB_RECURSE SRC_CPP_FILES ./*.cpp) qt5_add_dbus_adaptor( SESSION_MANAGER_SRCS ${CMAKE_SOURCE_DIR}/data/org.gnome.SessionManager.xml ${CMAKE_SOURCE_DIR}/src/core/session-manager.h Kiran::SessionManager session_manager_adaptor SessionManagerAdaptor) qt5_add_dbus_adaptor( CLIENT_PRIVATE_SRCS ${CMAKE_SOURCE_DIR}/data/org.gnome.SessionManager.ClientPrivate.xml ${CMAKE_SOURCE_DIR}/src/core/client/client-dbus.h Kiran::ClientDBus client_dbus_adaptor ClientDBusAdaptor) qt5_add_dbus_adaptor( PRESENCE_SRCS ${CMAKE_SOURCE_DIR}/data/org.gnome.SessionManager.Presence.xml ${CMAKE_SOURCE_DIR}/src/core/presence.h Kiran::Presence presence_adaptor PresenceAdaptor) set_source_files_properties( ${CMAKE_SOURCE_DIR}/data/com.kylinsec.Kiran.SessionManager.IdleMonitor.xml PROPERTIES CLASSNAME IdleMonitorProxy NO_NAMESPACE true) qt5_add_dbus_interface( IDLE_MONITOR_SRCS ${CMAKE_SOURCE_DIR}/data/com.kylinsec.Kiran.SessionManager.IdleMonitor.xml idle_monitor_proxy) set(TARGET_NAME kiran-session-manager) file(GLOB TS_FILES "${PROJECT_SOURCE_DIR}/translations/${TARGET_NAME}.*.ts") qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) add_executable( ${TARGET_NAME} ${SRC_H_FILES} ${SRC_CPP_FILES} ${SESSION_MANAGER_SRCS} ${CLIENT_PRIVATE_SRCS} ${PRESENCE_SRCS} ${IDLE_MONITOR_SRCS} ${QM_FILES}) target_include_directories( ${TARGET_NAME} PRIVATE ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${GLIB2_INCLUDE_DIRS} ${X11_ICE_INCLUDE_DIRS} ${X11_SM_INCLUDE_DIRS} ${XEXT_INCLUDE_DIRS} ${XTRANS_INCLUDE_DIRS} ${GSETTINGS_QT_INCLUDE_DIRS}) target_link_libraries( ${TARGET_NAME} PRIVATE ${GLIB2_LIBRARIES} ${X11_ICE_LIBRARIES} ${X11_SM_LIBRARIES} ${XEXT_LIBRARIES} ${XTRANS_LIBRARIES} ${GSETTINGS_QT_LIBRARIES} Qt5::Core KF5::ConfigCore KF5::KIOCore lib-base lib-dbus) install(FILES ${QM_FILES} DESTINATION ${KSM_INSTALL_TRANSLATIONDIR}) install(TARGETS ${TARGET_NAME} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}) kiran-session-manager-2.5.0/src/core/signal-handler.cpp0000664000175000017500000000374414417211336024462 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "signal-handler.h" #include <signal.h> #include <sys/socket.h> #include <unistd.h> #include "lib/base/base.h" namespace Kiran { int SignalHandler::signalFD[2]; SignalHandler::SignalHandler() : m_handler(nullptr) { if (::socketpair(AF_UNIX, SOCK_STREAM, 0, signalFD)) { KLOG_WARNING() << "Couldn't create a socketpair"; return; } this->m_handler = new QSocketNotifier(signalFD[1], QSocketNotifier::Read, this); connect(this->m_handler, &QSocketNotifier::activated, this, &SignalHandler::handleSignal); } SignalHandler::~SignalHandler() { for (auto signo : this->m_signos) { signal(signo, nullptr); } close(signalFD[0]); close(signalFD[1]); } SignalHandler* SignalHandler::m_instance = nullptr; SignalHandler* SignalHandler::get_default() { if (!m_instance) { m_instance = new SignalHandler(); } return m_instance; } void SignalHandler::addSignal(int signalToTrack) { this->m_signos.insert(signalToTrack); signal(signalToTrack, signalHandler); } void SignalHandler::signalHandler(int signal) { ::write(signalFD[0], &signal, sizeof(signal)); } void SignalHandler::handleSignal() { int signal = 0; this->m_handler->setEnabled(false); ::read(signalFD[1], &signal, sizeof(signal)); this->m_handler->setEnabled(true); Q_EMIT signalReceived(signal); } } // namespace Kirankiran-session-manager-2.5.0/src/core/inhibitor-manager.cpp0000664000175000017500000001174414417211336025170 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/inhibitor-manager.h" #include "lib/base/base.h" #include "src/core/presence.h" #include "src/core/session-manager.h" #include "src/core/utils.h" namespace Kiran { InhibitorManager::InhibitorManager() : QObject(nullptr) { this->m_presence = new Presence(this); } InhibitorManager *InhibitorManager::m_instance = nullptr; void InhibitorManager::globalInit() { m_instance = new InhibitorManager(); m_instance->init(); } KSMInhibitorVec InhibitorManager::getInhibitorsByFlag(KSMInhibitorFlag flag) { KSMInhibitorVec inhibitors; for (auto &iter : this->m_inhibitors) { if ((iter->flags & flag) == flag) { inhibitors.push_back(iter); } } return inhibitors; } QSharedPointer<Inhibitor> InhibitorManager::addInhibitor(const QString &appID, uint32_t toplevelXID, const QString &reason, uint32_t flags, const QString &startupID) { // 生成一个不冲突的cookie,最多尝试10次。 const static int32_t COOKIE_MAX_RETRY_COUNT = 10; uint32_t cookie = 0; int32_t i = 0; for (i = 0; i < COOKIE_MAX_RETRY_COUNT; ++i) { cookie = Utils::getDefault()->generateCookie(); auto inhibitor = this->getInhibitor(cookie); if (!inhibitor) { break; } } RETURN_VAL_IF_TRUE(i == COOKIE_MAX_RETRY_COUNT, nullptr); auto inhibitor = QSharedPointer<Inhibitor>(new Inhibitor{.cookie = cookie, .appID = appID, .toplevelXID = toplevelXID, .reason = reason, .flags = flags, .startupID = startupID}); RETURN_VAL_IF_FALSE(this->addInhibitor(inhibitor), nullptr); return inhibitor; } void InhibitorManager::deleteInhibitor(uint32_t cookie) { KLOG_DEBUG("cookie: %d.", cookie); auto iter = this->m_inhibitors.find(cookie); if (iter != this->m_inhibitors.end()) { auto inhibitor = iter.value(); this->m_inhibitors.erase(iter); this->updatePresence(); Q_EMIT this->inhibitorDeleted(inhibitor); } } void InhibitorManager::deleteInhibitorByStartupID(const QString &startupID) { std::vector<uint32_t> deletedCookies; for (const auto &iter : this->m_inhibitors) { if (iter->startupID == startupID) { deletedCookies.push_back(iter->cookie); } } for (auto deletedCookie : deletedCookies) { this->deleteInhibitor(deletedCookie); } } void InhibitorManager::deleteInhibitorsWithStartupID() { std::vector<uint32_t> deletedCookies; for (const auto &iter : this->m_inhibitors) { if (!iter->startupID.isEmpty()) { deletedCookies.push_back(iter->cookie); } } for (auto deleted_cookie : deletedCookies) { this->deleteInhibitor(deleted_cookie); } } bool InhibitorManager::hasInhibitor(uint32_t flags) { auto iter = std::find_if(this->m_inhibitors.begin(), this->m_inhibitors.end(), [flags](QSharedPointer<Inhibitor> iter) { return ((flags & iter->flags) == flags); }); return (iter != this->m_inhibitors.end()); } void InhibitorManager::init() { this->m_presence->init(); } bool InhibitorManager::addInhibitor(QSharedPointer<Inhibitor> inhibitor) { RETURN_VAL_IF_FALSE(inhibitor, false); KLOG_DEBUG() << "Cookie: " << inhibitor->cookie; if (this->m_inhibitors.find(inhibitor->cookie) != this->m_inhibitors.end()) { KLOG_WARNING() << "The inhibitor " << inhibitor->cookie << " already exist."; return false; } this->m_inhibitors.insert(inhibitor->cookie, inhibitor); this->updatePresence(); Q_EMIT this->inhibitorAdded(inhibitor); return true; } void InhibitorManager::updatePresence() { if (this->hasInhibitor(KSMInhibitorFlag::KSM_INHIBITOR_FLAG_IDLE)) { this->m_presence->enableIdleTimeout(false); } else { this->m_presence->enableIdleTimeout(true); } } } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/0000775000175000017500000000000014417211336022334 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/src/core/client/client-dbus.h0000664000175000017500000000360014417211336024715 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QDBusObjectPath> #include "src/core/client/client.h" class ClientDBusAdaptor; namespace Kiran { class ClientDBus : public Client { Q_OBJECT public: ClientDBus(const QString &startupID, const QString &dbusName, const QString &appID, QObject *parent); virtual ~ClientDBus(); ClientType getType() { return ClientType::CLIENT_TYPE_DBUS; }; QDBusObjectPath getObjectPath() { return this->m_objectPath; }; QString getDBusName() { return this->m_dbusName; }; virtual QString getAppID() override; virtual bool cancelEndSession() override; virtual bool queryEndSession(bool interact) override; virtual bool endSession(bool save_data) override; virtual bool endSessionPhase2() override; virtual bool stop() override; Q_SIGNALS: void endSessionResponse(bool); public Q_SLOTS: void EndSessionResponse(bool is_ok, const QString &reason); Q_SIGNALS: void CancelEndSession(bool placeholder); void EndSession(uint flags); void QueryEndSession(uint flags); void Stop(bool placeholder); private: QString m_dbusName; QString m_appID; static int32_t m_clientCount; QDBusObjectPath m_objectPath; ClientDBusAdaptor *m_dbusAdaptor; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client-dbus.cpp0000664000175000017500000000510314417211336025250 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/client/client-dbus.h" #include "lib/base/base.h" #include "src/core/client_dbus_adaptor.h" namespace Kiran { #define KSM_CLIENT_DBUS_OBJECT_PATH "/org/gnome/SessionManager/Client" #define KSM_CLIENT_DBUS_INTERFACE "org.gnome.SessionManager.ClientPrivate" int32_t ClientDBus::m_clientCount = 0; ClientDBus::ClientDBus(const QString &startupID, const QString &dbusName, const QString &appID, QObject *parent) : Client(startupID, parent), m_dbusName(dbusName), m_appID(appID) { this->m_objectPath = QDBusObjectPath(QString("%1/%2").arg(KSM_CLIENT_DBUS_OBJECT_PATH).arg(++ClientDBus::m_clientCount)); this->m_dbusAdaptor = new ClientDBusAdaptor(this); if (!this->m_appID.endsWith(".desktop")) { this->m_appID += ".desktop"; } auto sessionConnection = QDBusConnection::sessionBus(); if (!sessionConnection.registerObject(this->m_objectPath.path(), KSM_CLIENT_DBUS_INTERFACE, this)) { KLOG_ERROR() << "Can't register object:" << sessionConnection.lastError(); } } ClientDBus::~ClientDBus() { KLOG_DEBUG() << "client " << this->getID() << " is destroyed."; } QString ClientDBus::getAppID() { RETURN_VAL_IF_TRUE(this->m_appID.length() > 0, this->m_appID); return this->Client::getAppID(); } bool ClientDBus::cancelEndSession() { Q_EMIT this->CancelEndSession(false); return true; } bool ClientDBus::queryEndSession(bool interact) { Q_EMIT this->QueryEndSession(0); return true; } bool ClientDBus::endSession(bool save_data) { Q_EMIT this->EndSession(0); return true; } bool ClientDBus::endSessionPhase2() { // dbus不存在第二阶段 return true; } bool ClientDBus::stop() { return true; } void ClientDBus::EndSessionResponse(bool is_ok, const QString &reason) { Q_EMIT this->endSessionResponse(is_ok); } } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client-manager.h0000664000175000017500000001330114417211336025371 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QMap> #include <QObject> #include "src/core/client/client-dbus.h" #include "src/core/client/client-xsmp.h" struct _SmsConn; typedef struct _SmsConn *SmsConn; struct _IceConn; typedef struct _IceConn *IceConn; class QDBusServiceWatcher; namespace Kiran { /* 基于XSMP协议的交互逻辑: 1. 请求会话结束阶段(query end session): 1.1 服务器向所有客户端调用SmsSaveYourself。 1.2 如果SmsSaveYourself携带的interact_style参数是允许与用户交互,则: 1.2.1 客户端可以调用SmsInteractRequest告知会话管理客户准备与用户交互,服务端回复SmsInteract表示同意, 此时客户端可以通过弹出对话框等方式与用户交互,交互结束后调用SmcInteractDone告知会话管理交互已经结束。 1.2.2 如果SmcInteractDone中携带的cancel_shutdown是True,则会话管理调用SmsShutdownCancelled告知所有客户端取消结束会话。 1.3 客户端需要调用SmcSaveYourselfDone来响应前面的SmsSaveYourself,参数success按照如下情况设置: 1.3.1 如果此时收到了取消结束会话的消息,那客户端可以选择不保存数据,然后将参数success设为False; 1.3.2 客户端选择保存数据,数据保存成功后将success设置为True,否则设置为False。 1.4 当收到所有客户端的"Save Yourself Done"消息后,且会话为被取消,则进入会话结束阶段。 2.会话结束阶段 (end session): 2.1 服务器向所有客户端调用SmsSaveYourself,参数interact_style设置为False不再允许客户端与用户交互。 2.1.1 对于普通的客户端,在保存好数据后调用SmcSaveYourselfDone函数即可。 2.1.2 对于部分特殊客户端(例如窗口管理器)希望在其他客户端结束后再进行一些操作时,则进行如下处理: 2.1.2.1 这些客户端应该调用SmcRequestSaveYourselfPhase2函数请求会话管理在其他客户端都执行完SmcSaveYourselfDone后再进行第二阶段的数据保存, 随后特殊客户端应该进行数据保存操作,然后调用SmcSaveYourselfDone函数来响应会话管理的第一次"Save Yourself"消息。 2.1.2.2 当收到所有客户端第一阶段的"Save Yourself Done"消息后,会话管理会向特殊客户端调用SmsSaveYourselfPhase2。 2.1.2.3 特殊客户端在进行数据保存和一系列操作后,调用SmcSaveYourselfDone函数来响应会话管理的第二次"Save Yourself"消息。 2.2 当收到所有客户端的第一阶段和第二阶段的"Save Yourself Done"消息后,会话管理进入真正的退出阶段。 3. 会话管理退出阶段 (quit) 进程退出 */ class XsmpServer; class ClientManager : public QObject { Q_OBJECT public: ClientManager(XsmpServer *xsmp_server); virtual ~ClientManager(){}; static ClientManager *getInstance() { return m_instance; }; static void globalInit(XsmpServer *xsmp_server); static void globalDeinit() { delete m_instance; }; Client *getClient(const QString &startupID) { return this->m_clients.value(startupID, nullptr); } ClientDBus *getClientByDBusName(const QString &dbusName); QList<Client *> getClients() { return this->m_clients.values(); } // 添加客户端 ClientXsmp *addClientXsmp(const QString &startupID, SmsConn smsConn); ClientDBus *addClientDBus(const QString &startupID, const QString &dbusName, const QString &appID); // 删除客户端 bool deleteClient(const QString &startupID); // 通过sms连接获取对应的KSMClient对象 ClientXsmp *getClientBySmsConn(SmsConn smsConn); ClientXsmp *getClientByIceConn(IceConn iceConn); Q_SIGNALS: // 客户端被添加信号 void clientAdded(Client *client); // 客户端属性变化 void clientChanged(Client *client); // 客户端被删除信号 void clientDeleted(Client *client); // 客户端请求与用户进行交互 void interactRequesting(Client *client); // 客户端与用户交互完毕 void interactDone(Client *client); // 客户端申请退出会话 void shutdownRequesting(Client *client); // 客户端申请取消退出会话 void shutdownCanceled(Client *client); // 客户端请求"Save Yourself Phase2" void endSessionPhase2Requesting(Client *client); // 客户端响应退出会话请求,这里无法区分是响应的第一阶段请求还是第二阶段,所以应该在请求的时候自己缓存状态 void endSessionResponse(Client *client); private Q_SLOTS: void onNameLost(const QString &dbusName); private: void init(); // 添加客户端 bool addClient(Client *client); private slots: void onNewXsmpClientConnected(unsigned long *maskRet, void *callbacks); void onIceConnStatusChanged(int32_t status, IceConn iceConn); void onDBusClientEndSessionResponse(bool isOK, QString startupID); private: static ClientManager *m_instance; XsmpServer *m_xsmpServer; QDBusServiceWatcher *m_serviceWatcher; // 维护客户端对象 <startup_id, KSMClient> QMap<QString, Client *> m_clients; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client.h0000664000175000017500000000265014417211336023766 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QObject> namespace Kiran { enum ClientEndSessionFlag { // 客户端在结束会话时保存必要的信息 CLIENT_END_SESSION_FLAG_SAVE = 1 << 1, // 会话结束第二阶段 CLIENT_END_SESSION_FLAG_LAST = 1 << 2 }; enum ClientType { CLIENT_TYPE_XSMP, CLIENT_TYPE_DBUS }; class Client : public QObject { Q_OBJECT public: Client(const QString &id, QObject *parent); virtual ~Client(){}; QString getID() { return this->m_id; }; virtual QString getAppID(); virtual ClientType getType() = 0; virtual bool cancelEndSession() = 0; virtual bool queryEndSession(bool interact) = 0; virtual bool endSession(bool save_data) = 0; virtual bool endSessionPhase2() = 0; virtual bool stop() = 0; private: QString m_id; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client-xsmp.cpp0000664000175000017500000001377214417211336025315 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/client/client-xsmp.h" #include "lib/base/base.h" #include <X11/SM/SMlib.h> #include <QFileInfo> namespace Kiran { ClientXsmp::ClientXsmp(const QString &startupID, SmsConn sms_connection, QObject *parent) : Client(startupID, parent), m_smsConnection(sms_connection), m_currentSaveYourself(-1), m_nextSaveYourself(-1), m_nextSaveYourselfAllowInteract(false) { } ClientXsmp::~ClientXsmp() { for (auto props : this->m_props) { SmFreeProperty((SmProp *)props); } } QString ClientXsmp::getAppID() { auto appID = this->Client::getAppID(); RETURN_VAL_IF_TRUE(appID.length() > 0, appID); return QFileInfo(this->getProgramName()).fileName() + ".desktop"; } bool ClientXsmp::cancelEndSession() { SmsShutdownCancelled(this->m_smsConnection); return true; } bool ClientXsmp::queryEndSession(bool interact) { /* SmsConn/SaveType/shutdown/interact style/fast */ SmsSaveYourself(this->m_smsConnection, SmSaveGlobal, True, interact ? SmInteractStyleAny : SmInteractStyleNone, False); return true; } bool ClientXsmp::endSession(bool saveData) { SmsSaveYourself(this->m_smsConnection, saveData ? SmSaveBoth : SmSaveGlobal, True, SmInteractStyleNone, True); return true; } bool ClientXsmp::endSessionPhase2() { SmsSaveYourselfPhase2(this->m_smsConnection); return true; } bool ClientXsmp::stop() { SmsDie(this->m_smsConnection); return true; } void ClientXsmp::updateProperty(void *property) { RETURN_IF_FALSE(property != NULL); SmProp *smProperty = (SmProp *)property; KLOG_DEBUG("property name: %s.", smProperty->name); this->deleteProperty(POINTER_TO_STRING(smProperty->name)); this->m_props.push_back(property); switch (shash(smProperty->name)) { case CONNECT(SmDiscardCommand, _hash): { auto discardCommand = this->propToCommand(smProperty); KLOG_DEBUG() << "Property value: " << discardCommand; break; } case CONNECT(SmProcessID, _hash): { auto procesID = POINTER_TO_STRING((const char *)smProperty->vals[0].value).toULong(); KLOG_DEBUG() << "Property value: " << procesID; break; } case CONNECT(SmProgram, _hash): { auto programName = QString::fromUtf8((const char *)smProperty->vals[0].value, smProperty->vals[0].length); KLOG_DEBUG() << "Property value: " << programName; break; } case CONNECT(SmRestartCommand, _hash): { auto restartCommand = this->propToCommand(smProperty); KLOG_DEBUG() << "Property value: " << restartCommand; break; } case CONNECT(SmRestartStyleHint, _hash): { auto restartStyleHint = ((unsigned char *)smProperty->vals[0].value)[0]; KLOG_DEBUG() << "Property value: " << restartStyleHint; break; } default: break; } } void ClientXsmp::deleteProperty(const QString &propertyName) { KLOG_DEBUG() << "Delete Property " << propertyName; auto index = this->getPropertyIndex(propertyName); if (index >= 0) { SmFreeProperty((SmProp *)this->m_props[index]); this->m_props.remove(index); } } void *ClientXsmp::getProperty(const QString &propertyName) { auto index = this->getPropertyIndex(propertyName); RETURN_VAL_IF_TRUE(index < 0, NULL); return this->m_props[index]; } QString ClientXsmp::getProgramName() { auto property = this->getProperty(SmProgram); RETURN_VAL_IF_TRUE(property == NULL, QString()); SmProp *sm_property = (SmProp *)property; return QString::fromUtf8((const char *)sm_property->vals[0].value, sm_property->vals[0].length); } int32_t ClientXsmp::getPropertyIndex(const QString &propertyName) { for (int32_t i = 0; i < this->m_props.size(); ++i) { auto prop = (SmProp *)(this->m_props[i]); RETURN_VAL_IF_TRUE(propertyName == POINTER_TO_STRING(prop->name), i); } return -1; } QString ClientXsmp::propToCommand(void *property) { QString retval; SmProp *sm_property = (SmProp *)property; for (int32_t i = 0; i < sm_property->num_vals; i++) { const char *str = (char *)sm_property->vals[i].value; int32_t strlen = sm_property->vals[i].length; auto need_quotes = false; for (int32_t j = 0; j < strlen; j++) { if (!isalnum(str[j]) && !strchr("-_=:./", str[j])) { need_quotes = true; break; } } if (i > 0) { retval.push_back(' '); } if (!need_quotes) { retval += QString::fromUtf8(str, strlen); } else { retval.push_back('\''); while (str < (char *)sm_property->vals[i].value + strlen) { if (*str == '\'') { retval.append("'\''"); } else { retval.push_back(*str); } str++; } retval.push_back('\''); } } return retval; } } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client.cpp0000664000175000017500000000177114417211336024324 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/client/client.h" #include "src/core/app/app-manager.h" namespace Kiran { Client::Client(const QString &id, QObject *parent) : QObject(parent), m_id(id) { } QString Client::getAppID() { auto app = AppManager::getInstance()->getAppByStartupID(this->m_id); return app ? app->getAppID() : QString(); } } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client-manager.cpp0000664000175000017500000003605314417211336025735 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/client/client-manager.h" #include <QDBusConnection> #include <QDBusServiceWatcher> #include "lib/base/base.h" #include "src/core/client/client-dbus.h" #include "src/core/client/client-xsmp.h" #include "src/core/utils.h" #include "src/core/xsmp-server.h" #include <X11/ICE/ICEconn.h> #include <X11/ICE/ICElib.h> #include <X11/ICE/ICEutil.h> #include <X11/SM/SMlib.h> namespace Kiran { static Status onRegisterClient(SmsConn smsConn, SmPointer managerData, char *previousID) { KLOG_DEBUG() << "Receive register client message."; /* SMS协议规范: 1. 如果应用程序第一次加入会话,则previouse_id为NULL,这时需要会话管理负责生成一个唯一的id, 如果应用程序根据上一次的会话重启,则previouse_id记录的是上一次会话管理生成的id。 2. 会话管理需要通过SmsRegisterClientReply函数告知客户端注册已经成功, 2.1 如果previous_id不为NULL,则携带的client_id参数应该跟previous_id相同; 2.2 如果previous_id为NULL,则使用会话管理生成的唯一id并需要向客户端发送"Save Yourself"消息, 该消息携带的参数为type=Local, shutdown=False,interact-style=None, fast=False。*/ auto clientManager = (ClientManager *)(managerData); auto newPreviousID = POINTER_TO_STRING(previousID); SCOPE_EXIT( { if (previousID) { free(previousID); } }); auto client = clientManager->addClientXsmp(POINTER_TO_STRING(previousID), smsConn); RETURN_VAL_IF_FALSE(client, False); KLOG_DEBUG() << "Startup id: " << client->getID() << ", previous_id: " << POINTER_TO_STRING(previousID); auto clientID = client->getID().toUtf8(); SmsRegisterClientReply(smsConn, clientID.data()); if (!previousID) { SmsSaveYourself(smsConn, SmSaveLocal, False, SmInteractStyleNone, False); } return True; } static void onInteractRequest(SmsConn smsConn, SmPointer managerData, int dialogType) { KLOG_DEBUG() << "Receive interact request message."; auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); Q_EMIT clientManager->interactRequesting(client); KLOG_DEBUG() << "Startup id: " << client->getID() << ", dialog type: " << dialogType; SmsInteract(smsConn); } static void onInteractDone(SmsConn smsConn, SmPointer managerData, Bool cancelShutdown) { KLOG_DEBUG() << "Receive interact done message."; auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); KLOG_DEBUG() << "Startup id: " << client->getID() << ", cancel shutdown: " << cancelShutdown; if (cancelShutdown) { Q_EMIT clientManager->shutdownCanceled(client); } /* 取消关闭(shutdown_canceled)信号应该要先于interact_done信号,否则如果先收到interact_done信号的话, SessinManager会移除交互时添加的抑制器,当没有抑制器时,SessinManager会进入下一个阶段。此时再收到取消关闭信号 可能回被SessinManager忽略。*/ Q_EMIT clientManager->interactDone(client); } static void onSaveYourselfRequest(SmsConn smsConn, SmPointer managerData, int saveType, Bool shutdown, int interactStyle, Bool fast, Bool global) { KLOG_DEBUG() << "Receive save yourself request message."; /* 如果global为False,则会话管理应该只向请求的客户端发送"Save Yourself"消息;如果global为True, 则会话管理应该向所有客户端发送"Save Yourself"消息。当global为True时,我们只在shutdown为True 的情况向所有客户端发送"Save Yourself"消息,对应的shutdown设置为True,其他情况忽略处理*/ auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); KLOG_DEBUG() << "Startup id: " << client->getID() << ", save type: " << saveType << ", shutdown: " << shutdown << ", interact style: " << interactStyle << ", fast: " << fast << ", global: " << global; if (shutdown && global) { Q_EMIT clientManager->shutdownRequesting(client); } else if (!shutdown && !global) { SmsSaveYourself(smsConn, SmSaveLocal, False, SmInteractStyleAny, False); } } static void onSaveYourselfPhase2Request(SmsConn smsConn, SmPointer managerData) { KLOG_DEBUG() << "Receive save yourself phase2 request message."; auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); Q_EMIT clientManager->endSessionPhase2Requesting(client); } static void onSaveYourselfDone(SmsConn smsConn, SmPointer managerData, Bool success) { auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); KLOG_DEBUG() << "Receive save yourself done message. Startup id: " << client->getID() << ", success: " << success; SmsSaveComplete(smsConn); Q_EMIT clientManager->endSessionResponse(client); } static void onCloseConnection(SmsConn smsConn, SmPointer managerData, int count, char **reasonMsgs) { auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); KLOG_DEBUG() << "Receive client " << client->getID() << " closed connection message."; for (int32_t i = 0; i < count; i++) { KLOG_DEBUG() << "Close reason: " << reasonMsgs[i]; } SmFreeReasons(count, reasonMsgs); clientManager->deleteClient(client->getID()); } static void onSetProperties(SmsConn smsConn, SmPointer managerData, int numProps, SmProp **props) { auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); for (int32_t i = 0; i < numProps; ++i) { client->updateProperty(props[i]); } free(props); Q_EMIT clientManager->clientChanged(client); } static void onDeleteProperties(SmsConn smsConn, SmPointer managerData, int numProps, char **propNames) { auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); for (int32_t i = 0; i < numProps; ++i) { client->deleteProperty(propNames[i]); } // 文档中没有提到需要释放该变量 free(propNames); Q_EMIT clientManager->clientChanged(client); } static void onGetProperties(SmsConn smsConn, SmPointer managerData) { auto clientManager = (ClientManager *)(managerData); auto client = clientManager->getClientBySmsConn(smsConn); RETURN_IF_FALSE(client); auto props = client->get_properties(); SmsReturnProperties(smsConn, props.length(), (SmProp **)props.data()); } ClientManager::ClientManager(XsmpServer *xsmp_server) : m_xsmpServer(xsmp_server) { this->m_serviceWatcher = new QDBusServiceWatcher(this); } ClientManager *ClientManager::m_instance = nullptr; void ClientManager::globalInit(XsmpServer *xsmp_server) { m_instance = new ClientManager(xsmp_server); m_instance->init(); } ClientDBus *ClientManager::getClientByDBusName(const QString &dbusName) { for (auto iter : this->m_clients) { CONTINUE_IF_TRUE(iter->getType() != CLIENT_TYPE_DBUS); auto dbus_client = (ClientDBus *)iter; RETURN_VAL_IF_TRUE(dbus_client->getDBusName() == dbusName, dbus_client); } return nullptr; } void ClientManager::init() { KLOG_DEBUG() << "Init client manager."; this->m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); this->m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); connect(this->m_serviceWatcher, SIGNAL(serviceUnregistered(const QString &)), this, SLOT(onNameLost(const QString &))); connect(this->m_xsmpServer, SIGNAL(newClientConnected(unsigned long *, void *)), this, SLOT(onNewXsmpClientConnected(unsigned long *, void *))); connect(this->m_xsmpServer, SIGNAL(iceConnStatusChanged(int32_t, IceConn)), this, SLOT(onIceConnStatusChanged(int32_t, IceConn))); } ClientXsmp *ClientManager::addClientXsmp(const QString &startupID, SmsConn smsConn) { auto newStartupID = startupID; if (newStartupID.length() == 0) { newStartupID = Utils::getDefault()->generateStartupID(); } auto client = new ClientXsmp(newStartupID, smsConn, this); if (!this->addClient(client)) { delete client; return nullptr; } return client; } ClientDBus *ClientManager::addClientDBus(const QString &startupID, const QString &dbusName, const QString &appID) { KLOG_DEBUG() << "Add dbus client. StartupID: " << startupID << ", DBusName: " << dbusName << ", appID: " << appID; auto newStartupID = startupID; if (newStartupID.length() == 0) { newStartupID = Utils::getDefault()->generateStartupID(); } auto client = new ClientDBus(newStartupID, dbusName, appID, this); if (!this->addClient(client)) { delete client; return nullptr; } this->m_serviceWatcher->addWatchedService(dbusName); connect(client, &ClientDBus::endSessionResponse, this, std::bind(&ClientManager::onDBusClientEndSessionResponse, this, std::placeholders::_1, client->getID())); return client; } bool ClientManager::deleteClient(const QString &startupID) { auto client = this->getClient(startupID); RETURN_VAL_IF_FALSE(client, false); this->m_clients.remove(startupID); Q_EMIT this->clientDeleted(client); return true; } bool ClientManager::addClient(Client *client) { RETURN_VAL_IF_FALSE(client, false); if (this->m_clients.find(client->getID()) != this->m_clients.end()) { KLOG_WARNING() << "The client " << client->getID() << " already exist."; return false; } else { this->m_clients.insert(client->getID(), client); Q_EMIT this->clientAdded(client); } return true; } ClientXsmp *ClientManager::getClientBySmsConn(SmsConn smsConn) { auto id = SmsClientID(smsConn); auto client = this->getClient(POINTER_TO_STRING(id)); if (!client) { KLOG_WARNING() << "The client isn't found. startup_id: " << POINTER_TO_STRING(id); return nullptr; } if (client->getType() != ClientType::CLIENT_TYPE_XSMP) { KLOG_WARNING() << "The client type isn't xsmp. startup_id: " << client->getID(); return nullptr; } return (ClientXsmp *)client; } ClientXsmp *ClientManager::getClientByIceConn(IceConn iceConn) { for (auto iter : this->m_clients) { CONTINUE_IF_TRUE(iter->getType() != ClientType::CLIENT_TYPE_XSMP); auto xsmp_client = (ClientXsmp *)iter; if (SmsGetIceConnection(xsmp_client->get_sms_connection()) == iceConn) { return xsmp_client; } } return nullptr; } void ClientManager::onNameLost(const QString &dbusName) { auto dbusClient = this->getClientByDBusName(dbusName); if (dbusClient) { KLOG_DEBUG() << "Remove client " << dbusClient->getID() << " which dbus name is " << dbusName; this->deleteClient(dbusClient->getID()); } } void ClientManager::onNewXsmpClientConnected(unsigned long *mask_ret, void *callbacks) { SmsCallbacks *callbacks_ret = (SmsCallbacks *)callbacks; *mask_ret = 0; *mask_ret |= SmsRegisterClientProcMask; callbacks_ret->register_client.callback = onRegisterClient; callbacks_ret->register_client.manager_data = this; *mask_ret |= SmsInteractRequestProcMask; callbacks_ret->interact_request.callback = onInteractRequest; callbacks_ret->interact_request.manager_data = this; *mask_ret |= SmsInteractDoneProcMask; callbacks_ret->interact_done.callback = onInteractDone; callbacks_ret->interact_done.manager_data = this; *mask_ret |= SmsSaveYourselfRequestProcMask; callbacks_ret->save_yourself_request.callback = onSaveYourselfRequest; callbacks_ret->save_yourself_request.manager_data = this; *mask_ret |= SmsSaveYourselfP2RequestProcMask; callbacks_ret->save_yourself_phase2_request.callback = onSaveYourselfPhase2Request; callbacks_ret->save_yourself_phase2_request.manager_data = this; *mask_ret |= SmsSaveYourselfDoneProcMask; callbacks_ret->save_yourself_done.callback = onSaveYourselfDone; callbacks_ret->save_yourself_done.manager_data = this; *mask_ret |= SmsCloseConnectionProcMask; callbacks_ret->close_connection.callback = onCloseConnection; callbacks_ret->close_connection.manager_data = this; *mask_ret |= SmsSetPropertiesProcMask; callbacks_ret->set_properties.callback = onSetProperties; callbacks_ret->set_properties.manager_data = this; *mask_ret |= SmsDeletePropertiesProcMask; callbacks_ret->delete_properties.callback = onDeleteProperties; callbacks_ret->delete_properties.manager_data = this; *mask_ret |= SmsGetPropertiesProcMask; callbacks_ret->get_properties.callback = onGetProperties; callbacks_ret->get_properties.manager_data = this; } void ClientManager::onIceConnStatusChanged(int32_t status, IceConn iceConn) { auto client = this->getClientByIceConn(iceConn); RETURN_IF_FALSE(client); switch (IceProcessMessagesStatus(status)) { case IceProcessMessagesIOError: KLOG_WARNING() << "The client " << client->getID() << " Receive IceProcessMessagesIOError message. program name: " << client->getProgramName(); this->deleteClient(client->getID()); break; case IceProcessMessagesConnectionClosed: KLOG_DEBUG() << "The client " << client->getID() << " Receive IceProcessMessagesConnectionClosed message. program name: " << client->getProgramName(); break; default: break; } } void ClientManager::onDBusClientEndSessionResponse(bool isOK, QString startupID) { auto client = this->getClient(startupID); RETURN_IF_FALSE(client); if (isOK) { Q_EMIT this->endSessionResponse(client); } else { KLOG_WARNING() << "The Client " << client->getID() << " save failed."; } } } // namespace Kiran kiran-session-manager-2.5.0/src/core/client/client-xsmp.h0000664000175000017500000000425214417211336024753 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include "src/core/client/client.h" #include <QVector> struct _SmsConn; typedef struct _SmsConn *SmsConn; namespace Kiran { class ClientXsmp : public Client { Q_OBJECT public: ClientXsmp(const QString &startupID, SmsConn smsConnection, QObject *parent); virtual ~ClientXsmp(); ClientType getType() { return ClientType::CLIENT_TYPE_XSMP; }; SmsConn get_sms_connection() { return this->m_smsConnection; }; virtual QString getAppID() override; virtual bool cancelEndSession() override; virtual bool queryEndSession(bool interact) override; virtual bool endSession(bool save_data) override; virtual bool endSessionPhase2() override; virtual bool stop() override; // 添加/更新/删除/查找属性 void updateProperty(void *property); void deleteProperty(const QString &property_name); void *getProperty(const QString &property_name); QVector<void *> get_properties() { return this->m_props; }; // 获取程序名 QString getProgramName(); signals: void registerRequest(); void logoutRequest(); private: int32_t getPropertyIndex(const QString &property_name); QString propToCommand(void *prop); private: SmsConn m_smsConnection; QString m_appID; uint32_t m_status; // XsmpClientProps props_; // XSMP的SmsGetPropertiesProcMask回调处理需要返回SmProp指针数组,因此这里用GPtrArray比较方便 QVector<void *> m_props; int32_t m_currentSaveYourself; int32_t m_nextSaveYourself; bool m_nextSaveYourselfAllowInteract; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/xsmp-server.cpp0000664000175000017500000003071414417211336024062 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/xsmp-server.h" #include "lib/base/base.h" #include <X11/ICE/ICEconn.h> #include <X11/ICE/ICElib.h> #include <X11/ICE/ICEutil.h> #include <X11/SM/SMlib.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <QTimer> #include "src/core/utils.h" extern "C" { #define ICE_t #define TRANS_SERVER #include <X11/Xtrans/Xtrans.h> #undef ICE_t #undef TRANS_SERVER } namespace Kiran { #define KSM_ICE_MAGIC_COOKIE_AUTH_NAME "MIT-MAGIC-COOKIE-1" #define KSM_ICE_MAGIC_COOKIE_LEN 16 // 重试次数 #define KSM_ICE_AUTH_RETRIES 6 // 重试前等待的时间(秒) #define KSM_ICE_AUTH_INTERVAL 4 // 如果锁已经存在,则超过该时间(秒)后之前的锁强制释放,如果设置为0则直接解除之前的锁 #define KSM_ICE_AUTH_LOCK_TIMEOUT 16 struct ConnectionWatch { uint32_t watchID; QTimer protocolTimeout; QMetaObject::Connection connection; }; static void onSmsErrorHandler(SmsConn smsConn, Bool swap, int offendingMinorOpcode, unsigned long offendingSequenceNum, int errorClass, int severity, IcePointer values) { // 将错误信息重定向输出 KLOG_WARNING() << "Swap: " << swap << ", offending_minor_opcode: " << offendingMinorOpcode << ", offending_sequence_num: " << offendingSequenceNum << ", error_class: " << errorClass << ", severity: " << severity; RETURN_IF_TRUE(severity == IceCanContinue); // 协议错误,让客户端关闭连接 KLOG_WARNING("Send die message to client."); SmsDie(smsConn); } static void onIceIoErrorHandler(IceConn iceConnection) { KLOG_WARNING() << "Receive io error message. connection: " << iceConnection; /* 这里不错任何处理,仅仅打印日志方便定位,当出现该IO错误时, 在下一次调用IceProcessMessages函数时会收到IceProcessMessagesIOError错误 */ } static Status onNewClientConnection(SmsConn smsConn, SmPointer managerData, unsigned long *maskRet, SmsCallbacks *callbacksRet, char **failureReasonRet) { XsmpServer *server = (XsmpServer *)(managerData); auto iceConn = SmsGetIceConnection(smsConn); KLOG_DEBUG("New client connection: %p.", iceConn); // 如果连接成功,则取消超时检测 auto watch = (ConnectionWatch *)(iceConn->context); watch->protocolTimeout.stop(); Q_EMIT server->newClientConnected(maskRet, callbacksRet); return True; } static void freeConnectionWatch(ConnectionWatch *watch) { if (watch->watchID) { g_source_remove(watch->watchID); watch->watchID = 0; } watch->protocolTimeout.stop(); QObject::disconnect(watch->connection); delete watch; } static void disconnectIceConnection(IceConn ice_conn) { IceSetShutdownNegotiation(ice_conn, FALSE); IceCloseConnection(ice_conn); } static bool onIceProtocolTimeout(IceConn ice_conn) { KLOG_DEBUG("Ice protocol timeout."); auto watch = (ConnectionWatch *)(ice_conn->context); freeConnectionWatch(watch); disconnectIceConnection(ice_conn); return false; } XsmpServer::XsmpServer() : QObject(nullptr), m_numListenSockets(0), m_numLocalListenSockets(0), m_listenSockets(NULL) { } XsmpServer::~XsmpServer() { } XsmpServer *XsmpServer::m_instance = nullptr; void XsmpServer::globalInit() { m_instance = new XsmpServer(); m_instance->init(); } void XsmpServer::init() { KLOG_DEBUG() << "Xsmp server init."; char error_string[BUFSIZ]; SmsSetErrorHandler(onSmsErrorHandler); IceSetIOErrorHandler(onIceIoErrorHandler); // 服务器初始化,这里会调用IceRegisterForProtocolReply函数 if (!SmsInitialize(PROJECT_NAME, PROJECT_VERSION, onNewClientConnection, this, NULL, BUFSIZ, error_string)) { KLOG_WARNING("Init libSM failed: %s.", error_string); return; } this->listenSocket(); } void XsmpServer::listenSocket() { char errorString[BUFSIZ]; _IceTransNoListen("tcp"); /* Create the XSMP socket. Older versions of IceListenForConnections * have a bug which causes the umask to be set to 0 on certain types * of failures. Probably not an issue on any modern systems, but * we'll play it safe. */ auto savedUmask = umask(0); umask(savedUmask); // 监听网络连接,该函数会对每种socket类型(例如:unix/tcp/DECnet)返回一个地址 if (!IceListenForConnections(&this->m_numListenSockets, &this->m_listenSockets, BUFSIZ, errorString)) { KLOG_WARNING("Listen connections failed: %s.", errorString); return; } umask(savedUmask); // 仅支持本机客户端连接 for (int i = 0; i < this->m_numListenSockets; i++) { auto pSocketAddr = IceGetListenConnectionString(this->m_listenSockets[i]); CONTINUE_IF_FALSE(pSocketAddr); auto socketAddr = QString(pSocketAddr); if (socketAddr.startsWith("local/") || socketAddr.startsWith("unix/")) { std::swap(this->m_listenSockets[i], this->m_listenSockets[this->m_numLocalListenSockets]); ++this->m_numLocalListenSockets; } free(pSocketAddr); } if (this->m_numLocalListenSockets <= 0) { KLOG_WARNING("Not exists local listen socket."); return; } // 更新认证文件 this->updateIceAuthority(); // 如果客户端未设置socket地址,则会从SESSION_MANAGER环境变量中读取。所以这里将服务器监听的地址写入该环境变量中 auto networkIds = IceComposeNetworkIdList(this->m_numLocalListenSockets, this->m_listenSockets); Utils::getDefault()->setEnv("SESSION_MANAGER", networkIds); free(networkIds); for (int32_t i = 0; i < this->m_numLocalListenSockets; i++) { auto channel = g_io_channel_unix_new(IceGetListenConnectionNumber(this->m_listenSockets[i])); g_io_add_watch(channel, GIOCondition(G_IO_IN | G_IO_HUP | G_IO_ERR), &XsmpServer::onAcceptIceConnection, this->m_listenSockets[i]); g_io_channel_unref(channel); } } void XsmpServer::updateIceAuthority() { std::vector<IceAuthFileEntry *> authEntries; auto fileName = IceAuthFileName(); if (IceLockAuthFile(fileName, KSM_ICE_AUTH_RETRIES, KSM_ICE_AUTH_INTERVAL, KSM_ICE_AUTH_LOCK_TIMEOUT) != IceAuthLockSuccess) { KLOG_WARNING("Failed to lock file: %s.", fileName); return; } SCOPE_EXIT({ IceUnlockAuthFile(fileName); }); std::vector<std::string> networkIds; for (int32_t i = 0; i < this->m_numLocalListenSockets; i++) { auto networkID = IceGetListenConnectionString(this->m_listenSockets[i]); networkIds.push_back(networkID); free(networkID); } // 删除认证文件中包含network_ids的认证信息,然后重新设置新的认证信息 auto fp = fopen(fileName, "r+"); SCOPE_EXIT( { if (fp) { fclose(fp); } }); if (fp) { IceAuthFileEntry *authEntry = NULL; while ((authEntry = IceReadAuthFileEntry(fp)) != NULL) { if (!authEntry->network_id) { IceFreeAuthFileEntry(authEntry); continue; } if (std::find(networkIds.begin(), networkIds.end(), std::string(authEntry->network_id)) != networkIds.end()) { IceFreeAuthFileEntry(authEntry); continue; } authEntries.push_back(authEntry); } rewind(fp); } else { auto fd = open(fileName, O_CREAT | O_WRONLY, 0600); fp = fdopen(fd, "w"); if (!fp) { KLOG_WARNING("Failed to create file: %s", fileName); return; } } for (int32_t i = 0; i < this->m_numLocalListenSockets; i++) { authEntries.push_back((IceAuthFileEntry *)this->createAndStoreAuthEntry("ICE", networkIds[i])); authEntries.push_back((IceAuthFileEntry *)this->createAndStoreAuthEntry("XSMP", networkIds[i])); } for (auto authEntry : authEntries) { IceWriteAuthFileEntry(fp, authEntry); IceFreeAuthFileEntry(authEntry); } } void *XsmpServer::createAndStoreAuthEntry(const std::string &protocolName, const std::string &networkID) { IceAuthFileEntry *fileEntry = (IceAuthFileEntry *)malloc(sizeof(IceAuthFileEntry)); fileEntry->protocol_name = strdup(protocolName.c_str()); fileEntry->protocol_data = NULL; fileEntry->protocol_data_length = 0; fileEntry->network_id = strdup(networkID.c_str()); fileEntry->auth_name = strdup(KSM_ICE_MAGIC_COOKIE_AUTH_NAME); fileEntry->auth_data = IceGenerateMagicCookie(KSM_ICE_MAGIC_COOKIE_LEN); fileEntry->auth_data_length = KSM_ICE_MAGIC_COOKIE_LEN; IceAuthDataEntry authDataEntry; authDataEntry.protocol_name = fileEntry->protocol_name; authDataEntry.network_id = fileEntry->network_id; authDataEntry.auth_name = fileEntry->auth_name; authDataEntry.auth_data = fileEntry->auth_data; authDataEntry.auth_data_length = fileEntry->auth_data_length; IceSetPaAuthData(1, &authDataEntry); return fileEntry; } gboolean XsmpServer::onAcceptIceConnection(GIOChannel *source, GIOCondition condition, gpointer data) { IceAcceptStatus status; IceListenObj listener = (IceListenObj)data; auto ice_conn = IceAcceptConnection(listener, &status); if (status != IceAcceptSuccess) { KLOG_DEBUG("Accept ice connection with error status. status: %d", status); return TRUE; } auto fd = IceConnectionNumber(ice_conn); fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); auto channel = g_io_channel_unix_new(fd); auto watch = new ConnectionWatch(); ice_conn->context = watch; watch->connection = QObject::connect(&watch->protocolTimeout, &QTimer::timeout, std::bind(&onIceProtocolTimeout, ice_conn)); watch->protocolTimeout.start(5000); watch->watchID = g_io_add_watch(channel, GIOCondition(G_IO_IN | G_IO_ERR), &XsmpServer::onAuthIochannelWatch, ice_conn); g_io_channel_unref(channel); return TRUE; } gboolean XsmpServer::onAuthIochannelWatch(GIOChannel *source, GIOCondition condition, gpointer userData) { auto iceConn = (IceConn)(userData); auto watch = (ConnectionWatch *)(iceConn->context); auto status = IceProcessMessages(iceConn, NULL, NULL); RETURN_VAL_IF_TRUE(status == IceProcessMessagesSuccess, TRUE); KLOG_DEBUG() << "Receive io event: " << condition << " status: " << status; switch (status) { case IceProcessMessagesIOError: freeConnectionWatch(watch); disconnectIceConnection(iceConn); break; case IceProcessMessagesConnectionClosed: freeConnectionWatch(watch); break; default: break; } Q_EMIT XsmpServer::getInstance()->iceConnStatusChanged(status, iceConn); return FALSE; } } // namespace Kiran kiran-session-manager-2.5.0/src/core/presence.h0000664000175000017500000000454214417211336023040 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QDBusContext> class QGSettings; class PresenceAdaptor; class IdleMonitorProxy; class QDBusServiceWatcher; namespace Kiran { class Presence : public QObject, protected QDBusContext { Q_OBJECT Q_PROPERTY(uint status READ status WRITE setStatus NOTIFY statusChanged) Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged) public: Presence(QObject *parent); virtual ~Presence(){}; void init(); // 空闲超时是否开启,如果添加了抑制器则不应该触发空闲超时信号 void enableIdleTimeout(bool enabled); uint status() { return this->m_status; } void setStatus(uint status); QString statusText() { return this->m_statusText; } void setStatusText(const QString &statusText); public Q_SLOTS: // METHODS void SetStatus(uint status); void SetStatusText(const QString &status_text); Q_SIGNALS: // SIGNALS void statusChanged(); void statusTextChanged(); void StatusChanged(uint status); void StatusTextChanged(const QString &status_text); private: void updateIdleXlarm(); private Q_SLOTS: void onSettingsChanged(const QString &key); void onNameAcquired(const QString &dbusName); void onNameLost(const QString &dbusName); void onResumingFromIdle(); void onTimeoutReached(int id, qulonglong interval); private: QGSettings *m_settings; IdleMonitorProxy *m_idleMonitorProxy; QDBusServiceWatcher *m_serviceWatcher; // 空闲超时被开启 bool m_enabledIdleTimeout; // 空闲超时时间(分钟) int32_t m_idleTimeout; int32_t m_idleTimeoutIdentifier; uint m_status; QString m_statusText; PresenceAdaptor *m_dbusAdaptor; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/inhibitor-manager.h0000664000175000017500000000510414417211336024626 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <ksm-i.h> #include <QMap> #include <QObject> #include <QSharedPointer> namespace Kiran { struct Inhibitor { public: Inhibitor() = default; uint32_t cookie; QString appID; uint32_t toplevelXID; QString reason; uint32_t flags; QString startupID; }; using KSMInhibitorVec = QList<QSharedPointer<Inhibitor>>; class Presence; class InhibitorManager : public QObject { Q_OBJECT public: InhibitorManager(); virtual ~InhibitorManager(){}; static InhibitorManager *getInstance() { return m_instance; }; static void globalInit(); static void globalDeinit() { delete m_instance; }; // 获取抑制器 QSharedPointer<Inhibitor> getInhibitor(uint32_t cookie) { return this->m_inhibitors.value(cookie, QSharedPointer<Inhibitor>()); }; KSMInhibitorVec getInhibitors() { return this->m_inhibitors.values(); }; KSMInhibitorVec getInhibitorsByFlag(KSMInhibitorFlag flag); // 添加抑制器 QSharedPointer<Inhibitor> addInhibitor(const QString &appID, uint32_t toplevelXID, const QString &reason, uint32_t flags, const QString &startupID = QString()); // 删除抑制器 void deleteInhibitor(uint32_t cookie); void deleteInhibitorByStartupID(const QString &startupID); void deleteInhibitorsWithStartupID(); // 存在指定类型的抑制器 bool hasInhibitor(uint32_t flags); Q_SIGNALS: void inhibitorAdded(QSharedPointer<Inhibitor> inhibitor); void inhibitorDeleted(QSharedPointer<Inhibitor> inhibitor); private: void init(); bool addInhibitor(QSharedPointer<Inhibitor> inhibitor); void updatePresence(); private: static InhibitorManager *m_instance; Presence *m_presence; // 抑制器 <cookie, Inhibitor> QMap<uint32_t, QSharedPointer<Inhibitor>> m_inhibitors; }; } // namespace Kirankiran-session-manager-2.5.0/src/core/utils.h0000664000175000017500000000257114417211336022374 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QSharedPointer> namespace Kiran { class Utils { public: Utils(); virtual ~Utils(){}; static QSharedPointer<Utils> getDefault(); // 生成随机的startup id QString generateStartupID(); // 设置自定义的自启动目录,覆盖默认加载目录 void setAutostartDirs(const QString &autostartDirs); // 获取自动启动程序的目录列表 QStringList getAutostartDirs(); // 设置环境变量 void setEnv(const QString &name, const QString &value); void setEnvs(const QMap<QString, QString> &envs); // 生成cookie uint32_t generateCookie(); private: static QSharedPointer<Utils> m_instance; QStringList m_customAutostartDirs; bool m_useCustomAutostartDirs; }; } // namespace Kirankiran-session-manager-2.5.0/src/core/presence.cpp0000664000175000017500000001415414417211336023373 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/presence.h" #include <QDBusServiceWatcher> #include <QGSettings> #include "ksm-i.h" #include "lib/base/base.h" #include "src/core/idle_monitor_proxy.h" #include "src/core/presence_adaptor.h" namespace Kiran { #define KSM_SCHEMA_ID "com.kylinsec.kiran.session-manager" #define KSM_SCHEMA_KEY_IDLE_DELAY "idleDelay" Presence::Presence(QObject *parent) : QObject(parent), m_idleMonitorProxy(nullptr), m_enabledIdleTimeout(true), m_idleTimeout(0), m_idleTimeoutIdentifier(0), m_status(KSMPresenceStatus::KSM_PRESENCE_STATUS_AVAILABLE) { this->m_settings = new QGSettings(KSM_SCHEMA_ID, "", this); this->m_dbusAdaptor = new PresenceAdaptor(this); this->m_serviceWatcher = new QDBusServiceWatcher(this); } void Presence::init() { this->m_idleTimeout = this->m_settings->get(KSM_SCHEMA_KEY_IDLE_DELAY).toInt(); this->updateIdleXlarm(); if (!connect(this->m_settings, SIGNAL(changed(const QString &)), this, SLOT(onSettingsChanged(const QString &)))) { KLOG_WARNING() << "Can't connect session manager settings changed signal"; } auto sessionConnection = QDBusConnection::sessionBus(); if (!sessionConnection.registerObject(KSM_PRESENCE_DBUS_OBJECT_PATH, this)) { KLOG_WARNING() << "Can't register object:" << sessionConnection.lastError(); } this->m_serviceWatcher->setConnection(sessionConnection); this->m_serviceWatcher->setWatchedServices(QStringList(KSM_IDLE_DBUS_NAME)); this->m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration); connect(this->m_serviceWatcher, SIGNAL(serviceRegistered(const QString &)), this, SLOT(onNameAcquired(const QString &))); connect(this->m_serviceWatcher, SIGNAL(serviceUnregistered(const QString &)), this, SLOT(onNameLost(const QString &))); } void Presence::enableIdleTimeout(bool enabled) { KLOG_DEBUG() << "Enabled/Disable idle time: " << enabled; RETURN_IF_TRUE(this->m_enabledIdleTimeout == enabled); this->m_enabledIdleTimeout = enabled; this->updateIdleXlarm(); } void Presence::setStatus(uint status) { RETURN_IF_TRUE(this->m_status == status); this->m_status = status; Q_EMIT this->statusChanged(); Q_EMIT this->StatusChanged(this->m_status); } void Presence::setStatusText(const QString &statusText) { RETURN_IF_TRUE(this->m_statusText == statusText); this->m_statusText = statusText; Q_EMIT this->statusTextChanged(); Q_EMIT this->StatusTextChanged(this->m_statusText); } void Presence::SetStatus(uint status) { if (status >= KSM_PRESENCE_STATUS_LAST) { DBUS_ERROR_REPLY_AND_RET(QDBusError::InvalidArgs, KSMErrorCode::ERROR_PRESENCE_STATUS_INVALID); } this->setStatus(status); } void Presence::SetStatusText(const QString &status_text) { this->setStatusText(status_text); } void Presence::updateIdleXlarm() { KLOG_DEBUG() << "Enabled: " << this->m_enabledIdleTimeout << ", idle timeout: " << this->m_idleTimeout; if (!this->m_idleMonitorProxy) { KLOG_DEBUG() << "The idle monitor proxy hasn't exist."; return; } if (this->m_idleTimeoutIdentifier > 0) { auto reply = this->m_idleMonitorProxy->RemoveIdleTimeout(this->m_idleTimeoutIdentifier); reply.waitForFinished(); this->m_idleTimeoutIdentifier = 0; } if (this->m_idleTimeout > 0) { auto reply = this->m_idleMonitorProxy->AddIdleTimeout(this->m_idleTimeout * 60000); reply.waitForFinished(); if (reply.isError()) { KLOG_WARNING() << "Failed to add idle time: " << reply.error().message(); } else { this->m_idleTimeoutIdentifier = reply.value(); } } } void Presence::onSettingsChanged(const QString &key) { if (key == KSM_SCHEMA_KEY_IDLE_DELAY) { auto idleTimeout = this->m_settings->get(key).toInt(); if (idleTimeout != this->m_idleTimeout) { this->m_idleTimeout = idleTimeout; this->updateIdleXlarm(); } } } void Presence::onNameAcquired(const QString &dbusName) { KLOG_DEBUG() << "Receive name acquired: " << dbusName; this->m_idleMonitorProxy = new IdleMonitorProxy(KSM_IDLE_DBUS_NAME, KSM_IDLE_DBUS_OBJECT_PATH, QDBusConnection::sessionBus(), this); connect(this->m_idleMonitorProxy, SIGNAL(ResumingFromIdle()), this, SLOT(onResumingFromIdle())); connect(this->m_idleMonitorProxy, SIGNAL(TimeoutReached(int, qulonglong)), this, SLOT(onTimeoutReached(int, qulonglong))); this->updateIdleXlarm(); } void Presence::onNameLost(const QString &dbusName) { KLOG_DEBUG() << "Receive name lost: " << dbusName; if (this->m_idleMonitorProxy) { delete this->m_idleMonitorProxy; this->m_idleMonitorProxy = nullptr; } } void Presence::onResumingFromIdle() { KLOG_DEBUG() << "Receive alarm signal."; this->setStatus(KSMPresenceStatus::KSM_PRESENCE_STATUS_AVAILABLE); } void Presence::onTimeoutReached(int id, qulonglong interval) { KLOG_DEBUG() << "Receive alarm triggered signal."; if (id == this->m_idleTimeoutIdentifier) { this->setStatus(KSMPresenceStatus::KSM_PRESENCE_STATUS_IDLE); } } } // namespace Kiran kiran-session-manager-2.5.0/src/core/app/0000775000175000017500000000000014417211336021636 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/src/core/app/app.h0000664000175000017500000000535414417211336022576 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <KDesktopFile> #include <QEnableSharedFromThis> #include <QProcess> namespace Kiran { enum KSMPhase { // 未开始 KSM_PHASE_IDLE = 0, // 启动显示服务器(xserver/wayland-server) KSM_PHASE_DISPLAY_SERVER, // (IdleMonitor) KSM_PHASE_POST_DISPLAY_SERVER, // 启动控制中心会话后端 KSM_PHASE_INITIALIZATION, // 启动窗口管理器 KSM_PHASE_WINDOW_MANAGER, // 启动底部面板 KSM_PHASE_PANEL, // 启动文件管理器 KSM_PHASE_DESKTOP, // 启动其他应用程序 KSM_PHASE_APPLICATION, // 会话运行阶段 KSM_PHASE_RUNNING, // 会话结束阶段 KSM_PHASE_QUERY_END_SESSION, // 会话结束第一阶段 KSM_PHASE_END_SESSION_PHASE1, // 会话结束第二阶段 KSM_PHASE_END_SESSION_PHASE2, // 会话结束第二阶段 KSM_PHASE_EXIT }; class App : public QObject { Q_OBJECT public: App(const QString &filePath, QObject *parent); virtual ~App(); bool start(); bool restart(); bool stop(); bool isRunning(); bool canLaunched(); // static int32_t phaseStr2enum(const QString &phase_str); static QString phaseEnum2str(int32_t phase); QString getAppID() { return this->m_appID; }; int32_t getPhase() { return this->m_phase; }; QString getStartupID() { return this->m_startupID; }; bool getAutoRestart() { return this->m_autoRestart; }; int32_t getDelay() { return this->m_delay; }; Q_SIGNALS: void AppExited(); private: void loadAppInfo(); // void startup_notification(); private Q_SLOTS: void onFinished(int exitCode, QProcess::ExitStatus exitStatus); // static void on_launch_cb(GDesktopAppInfo *appinfo, GPid pid, gpointer user_data); // static void on_app_exited_cb(GPid pid, gint status, gpointer user_data); private: QString m_appID; int32_t m_phase; QString m_startupID; // 正常退出后是否自动重启 bool m_autoRestart; // 延时运行时间 int32_t m_delay; QSharedPointer<KDesktopFile> m_appInfo; QProcess *m_process; // sigc::signal<void> m_appExited; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/app/app-manager.cpp0000664000175000017500000001432514417211336024537 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/core/app/app-manager.h" #include <KConfig> #include <KConfigGroup> #include <QDir> #include <QTimer> #include <fstream> #include "lib/base/base.h" #include "src/core/app/app.h" #include "src/core/utils.h" namespace Kiran { #define BLACKLIST_APPS_PATH KSM_INSTALL_DATADIR "/blacklist_autostart_apps.txt" #define SESSIONS_DIR KSM_INSTALL_DATADIR "/sessions" #define SESSION_GROUP_NAME "Kiran Session" #define SESSION_KEY_REQUIRED_COMPONENTS "RequiredComponents" AppManager::AppManager(const QString &sessionName) : QObject(nullptr), m_sessionName(sessionName) { } AppManager *AppManager::m_instance = nullptr; void AppManager::globalInit(const QString &sessionName) { m_instance = new AppManager(sessionName); m_instance->init(); } App *AppManager::getAppByStartupID(const QString &startupID) { KLOG_DEBUG() << "Startup id: " << startupID; for (auto iter : this->m_apps) { if (iter->getStartupID() == startupID) { return iter; } } return nullptr; } QList<App *> AppManager::startApps(int32_t phase) { QList<App *> apps; for (auto app : this->getAppsByPhase(phase)) { if (!app->canLaunched()) { KLOG_DEBUG() << "The app " << app->getAppID() << " cannot be launched."; continue; } // 如果应用由设置延时执行,则添加定时器延时启动应用 auto delay = app->getDelay() * 1000; /* 由于kiran-session-daemon和mate-session-daemon的部分插件不能同时启动, 因此需要等到kiran-session-daemon启动并调用RegisterClient接口后才能启动mate-settings-daemon, 在此阶段kiran-session-daemon会调用gsettings把与mate-session-daemon冲突的插件关闭掉, 当回话管理收到kiran-session-daemon的RegisterClient调用后再启动mate-settings-daemon*/ KLOG_DEBUG() << "DESKTOP ID: " << app->getAppID(); if (app->getAppID() == "mate-settings-daemon.desktop") { KLOG_DEBUG() << "The boot of mate-settings-daemon need be delayed until the kiran-session-daemon calls RegisterClient."; apps.push_back(app); continue; } if (delay > 0) { QTimer::singleShot(delay, [app]() { if (app->canLaunched()) { app->start(); } }); KLOG_DEBUG() << "The app " << app->getAppID() << " is scheduled to start after " << delay << " milliseconds."; } else { CONTINUE_IF_FALSE(app->start()); KLOG_DEBUG() << "The app " << app->getAppID() << " is started."; } apps.push_back(app); } return apps; } void AppManager::init() { this->loadApps(); } void AppManager::loadApps() { this->loadBlacklistAutostartApps(); this->loadAutostartApps(); this->loadRequiredApps(); } void AppManager::loadRequiredApps() { auto sessionFilePath = QString("%1/%2.session").arg(SESSIONS_DIR).arg(this->m_sessionName); KConfig keyFile(sessionFilePath, KConfig::SimpleConfig); auto sessionGroup = keyFile.group(SESSION_GROUP_NAME); auto requiredComponents = sessionGroup.readXdgListEntry(SESSION_KEY_REQUIRED_COMPONENTS); KLOG_DEBUG() << "Load required components: " << requiredComponents.join(",") << " from " << sessionFilePath; for (auto &iter : requiredComponents) { this->addApp(iter + ".desktop"); } } void AppManager::loadBlacklistAutostartApps() { static const int DESKTOP_ID_MAX_LEN = 256; this->m_blacklistApps.clear(); std::ifstream ifs(BLACKLIST_APPS_PATH, std::ifstream::in); if (ifs.is_open()) { while (ifs.good()) { char desktop_id[DESKTOP_ID_MAX_LEN] = {0}; ifs.getline(desktop_id, DESKTOP_ID_MAX_LEN); this->m_blacklistApps.insert(desktop_id); } } } void AppManager::loadAutostartApps() { for (auto autostartDir : Utils::getDefault()->getAutostartDirs()) { QDir dir(autostartDir); KLOG_DEBUG() << "Load autostart app from " << autostartDir; for (auto &fileName : dir.entryList(QDir::Files)) { auto filePath = QString("%1/%2").arg(autostartDir).arg(fileName); if (!filePath.endsWith(".desktop")) { continue; } if (this->m_blacklistApps.find(fileName) != this->m_blacklistApps.end()) { KLOG_DEBUG() << "The app " << fileName << " is in black list, so it isn't loaded."; } else { this->addApp(filePath); } } } } bool AppManager::addApp(const QString &fileName) { auto app = new App(fileName, this); auto appID = app->getAppID(); if (this->m_apps.find(appID) != this->m_apps.end()) { KLOG_DEBUG() << "The app " << appID << " already exist."; delete app; return false; } KLOG_DEBUG() << "Add app " << appID << " with location " << fileName << " to AppManager."; this->m_apps.insert(appID, app); connect(app, &App::AppExited, [this, app]() { emit this->AppExited(app); }); return true; } QList<App *> AppManager::getAppsByPhase(int32_t phase) { QList<App *> apps; for (auto iter : this->m_apps) { if (iter->getPhase() == phase) { apps.push_back(iter); } } return apps; } } // namespace Kiran kiran-session-manager-2.5.0/src/core/app/app-manager.h0000664000175000017500000000361314417211336024202 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QMap> #include <QObject> #include <QSet> #include "src/core/app/app.h" class QGSettings; namespace Kiran { class AppManager : public QObject { Q_OBJECT public: AppManager(const QString& sessionName); virtual ~AppManager(){}; static AppManager* getInstance() { return m_instance; }; static void globalInit(const QString& sessionName); static void globalDeinit() { delete m_instance; }; // 获取APP App* getApp(const QString& appID) { return this->m_apps.value(appID, nullptr); } App* getAppByStartupID(const QString& startupID); // 启动特定阶段的app,并返回启动成功或者延时启动的app列表 QList<App*> startApps(int32_t phase); Q_SIGNALS: void AppExited(App* app); private: void init(); void loadApps(); void loadRequiredApps(); void loadBlacklistAutostartApps(); void loadAutostartApps(); // 根据desktopinfo添加app bool addApp(const QString& fileName); // 获取在特定阶段启动的app QList<App*> getAppsByPhase(int32_t phase); private: static AppManager* m_instance; QString m_sessionName; // 需要排除的自动启动应用程序 QSet<QString> m_blacklistApps; // 开机启动应用 QMap<QString, App*> m_apps; }; } // namespace Kiran kiran-session-manager-2.5.0/src/core/app/app.cpp0000664000175000017500000002214414417211336023125 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include <KConfigGroup> #include <KDesktopFile> #include <KIO/DesktopExecParser> #include <KService> #include <QFileInfo> #include <QProcess> #include <QUrl> #include "lib/base/base.h" #include "src/core/app/app-manager.h" #include "src/core/app/app.h" #include "src/core/utils.h" namespace Kiran { #define KSM_AUTOSTART_APP_ENABLED_KEY "X-KIRAN-Autostart-enabled" #define KSM_AUTOSTART_APP_PHASE_KEY "X-KIRAN-Autostart-Phase" #define KSM_AUTOSTART_APP_AUTORESTART_KEY "X-KIRAN-AutoRestart" #define KSM_AUTOSTART_APP_DELAY_KEY "X-KIRAN-Autostart-Delay" // 暂时兼容MATE应用 #define GSM_AUTOSTART_APP_ENABLED_KEY "X-MATE-Autostart-enabled" #define GSM_AUTOSTART_APP_AUTORESTART_KEY "X-MATE-AutoRestart" #define GSM_AUTOSTART_APP_PHASE_KEY "X-MATE-Autostart-Phase" #define DESKTOP_KEY_DBUS_ACTIVATABLE "DBusActivatable" #define DESKTOP_KEY_STARTUP_NOTIFY "StartupNotify" App::App(const QString &filePath, QObject *parent = nullptr) : QObject(parent), m_phase(KSMPhase::KSM_PHASE_APPLICATION), m_autoRestart(false), m_delay(0), m_process(new QProcess(this)) { this->m_appInfo = QSharedPointer<KDesktopFile>(new KDesktopFile(filePath)); connect(this->m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus))); this->loadAppInfo(); } App::~App() { KLOG_DEBUG() << "App " << this->m_appID << " is destroyed."; } bool App::start() { /* DesktopAppInfo的接口不太完善,如果通过DBUS激活应用则拿不到进程ID,需要自己去DBUS总线获取,但是 DesktopAppInfo又未暴露应用的dbus name,所以暂时先不支持DBUS启动。*/ KLOG_DEBUG() << "Start app " << this->m_appInfo->fileName(); if (this->m_process->state() != QProcess::ProcessState::NotRunning) { KLOG_WARNING() << "The process already exists."; return false; } if (this->m_appInfo->desktopGroup().readEntry(DESKTOP_KEY_DBUS_ACTIVATABLE, false)) { KLOG_WARNING() << "DBus startup mode is not supported at present."; return false; } KService service(this->m_appInfo->fileName()); auto arguments = KIO::DesktopExecParser(service, QList<QUrl>()).resultingArguments(); if (arguments.isEmpty()) { KLOG_WARNING() << "Failed to parse arguments for " << this->m_appInfo->fileName(); return false; } auto env = QProcessEnvironment::systemEnvironment(); env.insert("DESKTOP_AUTOSTART_ID", this->m_startupID); this->m_process->setProcessEnvironment(env); auto program = arguments.takeFirst(); this->m_process->start(program, arguments); return true; } bool App::restart() { KLOG_DEBUG() << "Restart app " << this->m_appInfo->fileName(); this->stop(); return this->start(); } bool App::stop() { KLOG_DEBUG() << "Stop app " << this->m_appInfo->fileName(); if (this->m_process->state() == QProcess::ProcessState::NotRunning) { KLOG_WARNING() << "The app " << this->m_appInfo->fileName() << " is not running."; return false; } this->m_process->terminate(); return true; } bool App::canLaunched() { if (!this->m_appInfo->desktopGroup().readEntry(KSM_AUTOSTART_APP_ENABLED_KEY, true)) { KLOG_DEBUG() << "The app " << this->m_appInfo->fileName() << " is disabled."; return false; } if (!this->m_appInfo->desktopGroup().readEntry(GSM_AUTOSTART_APP_ENABLED_KEY, true)) { KLOG_DEBUG() << "The app " << this->m_appInfo->fileName() << " is disabled."; return false; } if (this->m_appInfo->desktopGroup().readEntry("Hidden", false)) { KLOG_DEBUG() << "The app " << this->m_appInfo->fileName() << " is hidden."; return false; } auto showList = this->m_appInfo->desktopGroup().readXdgListEntry("OnlyShowIn"); if (showList.length() > 0 && !showList.contains(DESKTOP_ENVIRONMENT) && !showList.contains("MATE")) { KLOG_DEBUG() << "The app " << this->m_appInfo->fileName() << " doesn't display in the desktop environment."; return false; } return true; } int32_t App::phaseStr2enum(const QString &phase_str) { switch (shash(phase_str.toStdString().c_str())) { case "DisplayServer"_hash: return KSMPhase::KSM_PHASE_DISPLAY_SERVER; case "PostDisplayServer"_hash: return KSMPhase::KSM_PHASE_POST_DISPLAY_SERVER; case "Initialization"_hash: return KSMPhase::KSM_PHASE_INITIALIZATION; case "WindowManager"_hash: return KSMPhase::KSM_PHASE_WINDOW_MANAGER; case "Panel"_hash: return KSMPhase::KSM_PHASE_PANEL; case "Desktop"_hash: return KSMPhase::KSM_PHASE_DESKTOP; default: return KSMPhase::KSM_PHASE_APPLICATION; } return KSMPhase::KSM_PHASE_APPLICATION; } QString App::phaseEnum2str(int32_t phase) { switch (phase) { case KSMPhase::KSM_PHASE_IDLE: return "Idle"; case KSMPhase::KSM_PHASE_DISPLAY_SERVER: return "DisplayServer"; case KSMPhase::KSM_PHASE_POST_DISPLAY_SERVER: return "PostDisplayServer"; case KSMPhase::KSM_PHASE_INITIALIZATION: return "Initialization"; case KSMPhase::KSM_PHASE_WINDOW_MANAGER: return "WindowManager"; case KSMPhase::KSM_PHASE_PANEL: return "Panel"; case KSMPhase::KSM_PHASE_DESKTOP: return "Desktop"; case KSMPhase::KSM_PHASE_APPLICATION: return "Application"; case KSMPhase::KSM_PHASE_RUNNING: return "Running"; case KSMPhase::KSM_PHASE_QUERY_END_SESSION: return "QueryEndSession"; case KSMPhase::KSM_PHASE_END_SESSION_PHASE1: return "EndSessionPhase1"; case KSMPhase::KSM_PHASE_END_SESSION_PHASE2: return "EndSessionPhase2"; case KSMPhase::KSM_PHASE_EXIT: return "Exit"; default: KLOG_WARNING("The phase %d is invalid.", phase); return QString(); } return QString(); } void App::loadAppInfo() { RETURN_IF_FALSE(this->m_appInfo); this->m_startupID = Utils::getDefault()->generateStartupID(); // Desktop ID this->m_appID = QFileInfo(this->m_appInfo->fileName()).fileName(); // Phase auto phase = this->m_appInfo->desktopGroup().readEntry(KSM_AUTOSTART_APP_PHASE_KEY); if (phase.isEmpty()) { phase = this->m_appInfo->desktopGroup().readEntry(GSM_AUTOSTART_APP_PHASE_KEY); } this->m_phase = App::phaseStr2enum(phase); // Auto restart if (this->m_appInfo->desktopGroup().hasKey(KSM_AUTOSTART_APP_AUTORESTART_KEY)) { this->m_autoRestart = this->m_appInfo->desktopGroup().readEntry(KSM_AUTOSTART_APP_AUTORESTART_KEY, false); } else { this->m_autoRestart = this->m_appInfo->desktopGroup().readEntry(GSM_AUTOSTART_APP_AUTORESTART_KEY, false); } // Delay auto delay = this->m_appInfo->desktopGroup().readEntry(KSM_AUTOSTART_APP_DELAY_KEY); if (!delay.isEmpty()) { /* 由于在APPLICATION阶段之前会话管理会设置一个超时定时器在应用程序启动时等待一段时间, 如果此时设置的延时启动时间大于这个定时器等待的时间,可能会发生一些不可预知的后果, 因此在APPLICATION阶段之前启动的应用程序暂时不运行设置延时启动。如果一定要设置,那 这个时间应该要小于会话管理设置的超时定时器的时间。*/ if (this->m_phase == KSMPhase::KSM_PHASE_APPLICATION) { this->m_delay = delay.toInt(); } else { KLOG_WARNING() << "Only accept an delay in KSM_PHASE_APPLICATION phase."; } } KLOG_DEBUG() << "The info of app " << this->m_appID << "is loaded. StartupID: " << this->m_startupID << ", Phase: " << App::phaseEnum2str(this->m_phase) << ", AutoRestart: " << this->m_autoRestart << ", Delay: " << this->m_delay; } void App::onFinished(int exitCode, QProcess::ExitStatus exitStatus) { switch (exitStatus) { case QProcess::ExitStatus::NormalExit: KLOG_DEBUG() << "The app " << this->m_appInfo->fileName() << " normal exits."; break; case QProcess::ExitStatus::CrashExit: KLOG_DEBUG() << "The app " << this->m_appInfo->fileName() << " abnormal normal exits, exit code " << exitCode; break; default: break; } Q_EMIT this->AppExited(); } } // namespace Kiran kiran-session-manager-2.5.0/src/ui/0000775000175000017500000000000014417211336020543 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/src/ui/inhibitor-row.cpp0000664000175000017500000000374414417211336024053 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/ui/inhibitor-row.h" #include <KDesktopFile> #include <QScopedPointer> #include "lib/base/base.h" #include "src/ui/ui_inhibitor-row.h" namespace Kiran { InhibitorRow::InhibitorRow(const QJsonObject &inhibitor, QWidget *parent) : QWidget(parent), m_ui(new Ui::InhibitorRow), m_inhibitor(inhibitor) { this->m_ui->setupUi(this); this->initUI(); } void InhibitorRow::initUI() { auto appID = this->m_inhibitor.value(KSM_INHIBITOR_JK_APP_ID).toString(); auto reason = this->m_inhibitor.value(KSM_INHIBITOR_JK_REASON).toString(); KLOG_DEBUG() << "Init inhibitor row for app: " << appID; QScopedPointer<KDesktopFile> desktopFile(new KDesktopFile(appID)); if (desktopFile) { auto appIcon = QIcon::fromTheme(desktopFile->readIcon()); if (appIcon.isNull()) { this->m_ui->m_appIcon->setIcon(QIcon(":/app-missing.svg")); } else { this->m_ui->m_appIcon->setIcon(appIcon); } this->m_ui->m_appName->setText(desktopFile->readName()); } else { this->m_ui->m_appIcon->setIcon(QIcon(":/app-missing.svg")); this->m_ui->m_appName->setText(tr("Unknown application")); } this->m_ui->m_appDesc->setText(reason); } } // namespace Kiran kiran-session-manager-2.5.0/src/ui/inhibitor-row.ui0000664000175000017500000000532014417211336023676 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>InhibitorRow</class> <widget class="QWidget" name="InhibitorRow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>400</width> <height>48</height> </rect> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>0</width> <height>48</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>48</height> </size> </property> <property name="windowTitle"> <string>Form</string> </property> <layout class="QHBoxLayout" name="horizontalLayout"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <widget class="QPushButton" name="m_appIcon"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="maximumSize"> <size> <width>48</width> <height>48</height> </size> </property> <property name="text"> <string/> </property> <property name="iconSize"> <size> <width>48</width> <height>48</height> </size> </property> <property name="flat"> <bool>true</bool> </property> </widget> </item> <item> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>16</number> </property> <item> <widget class="QLabel" name="m_appName"> <property name="text"> <string>TextLabel</string> </property> </widget> </item> <item> <widget class="QLabel" name="m_appDesc"> <property name="text"> <string>TextLabel</string> </property> </widget> </item> </layout> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> <resources/> <connections/> </ui> kiran-session-manager-2.5.0/src/ui/inhibitor-row.h0000664000175000017500000000201114417211336023502 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QJsonObject> #include <QWidget> namespace Ui { class InhibitorRow; } // namespace Ui namespace Kiran { class InhibitorRow : public QWidget { Q_OBJECT public: InhibitorRow(const QJsonObject &inhibitor, QWidget *parent = nullptr); virtual ~InhibitorRow(){}; private: void initUI(); private: Ui::InhibitorRow *m_ui; QJsonObject m_inhibitor; }; } // namespace Kiran kiran-session-manager-2.5.0/src/ui/main.cpp0000664000175000017500000000442614417211336022201 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include <QApplication> #include <QCommandLineParser> #include <QFileInfo> #include <QTranslator> #include "config.h" #include "lib/base/base.h" #include "src/ui/exit-query-window.h" using namespace Kiran; #define DEFAULT_STYLE_FILE ":/styles/kiran-session-window.qss" int main(int argc, char *argv[]) { auto argv0 = QFileInfo(argv[0]); auto programName = argv0.baseName(); if (klog_qt5_init(QString(), "kylinsec-session", PROJECT_NAME, programName) < 0) { fprintf(stderr, "Failed to init kiran-log."); } QApplication app(argc, argv); app.setApplicationName(programName); app.setApplicationVersion(PROJECT_VERSION); QTranslator translator; if (!translator.load(QLocale(), qAppName(), ".", KSM_INSTALL_TRANSLATIONDIR, ".qm")) { KLOG_WARNING() << "Load translator failed!"; } else { app.installTranslator(&translator); } ///加载样式表 QFile file(DEFAULT_STYLE_FILE); if (file.open(QIODevice::ReadOnly)) { app.setStyleSheet(file.readAll()); } else { KLOG_WARNING("Failed to load style sheet."); } QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); parser.addOption(QCommandLineOption(QStringList({"p", "power-action"}), app.translate("main", "Power action."), app.translate("main", "power action"), QString("%1").arg(POWER_ACTION_NONE))); parser.process(app); auto exitQueryWindow = new ExitQueryWindow(parser.value("power-action").toInt()); exitQueryWindow->show(); return app.exec(); } kiran-session-manager-2.5.0/src/ui/exit-query-window.ui0000664000175000017500000002372114417211336024530 0ustar wangyuchengwangyucheng<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>ExitQueryWindow</class> <widget class="QWidget" name="ExitQueryWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <layout class="QVBoxLayout" name="verticalLayout_4"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <widget class="QWidget" name="m_mask" native="true"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <layout class="QGridLayout" name="m_maskLayout"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <property name="spacing"> <number>0</number> </property> <item row="1" column="0"> <spacer name="m_leftSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item row="1" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter"> <widget class="QWidget" name="m_content" native="true"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>400</width> <height>300</height> </size> </property> <property name="maximumSize"> <size> <width>600</width> <height>400</height> </size> </property> <layout class="QVBoxLayout" name="m_contentLayout"> <property name="spacing"> <number>0</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>2</number> </property> <property name="bottomMargin"> <number>24</number> </property> <item> <widget class="QLabel" name="m_title"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string>Closing apps</string> </property> </widget> </item> <item> <widget class="QLabel" name="m_titleDesc"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string>If you want to go back and save your work, click 'cancel' and finish what you want to do</string> </property> </widget> </item> </layout> </item> <item> <widget class="QScrollArea" name="m_inhibitorsScrollArea"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>0</width> <height>216</height> </size> </property> <property name="maximumSize"> <size> <width>16777215</width> <height>216</height> </size> </property> <property name="verticalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOn</enum> </property> <property name="horizontalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOff</enum> </property> <property name="sizeAdjustPolicy"> <enum>QAbstractScrollArea::AdjustIgnored</enum> </property> <property name="widgetResizable"> <bool>true</bool> </property> <widget class="QWidget" name="m_inhibitors"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>510</width> <height>204</height> </rect> </property> <property name="minimumSize"> <size> <width>0</width> <height>0</height> </size> </property> <layout class="QVBoxLayout" name="m_inhibitorsLayout"> <property name="spacing"> <number>36</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> </layout> </widget> </widget> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <property name="spacing"> <number>36</number> </property> <property name="topMargin"> <number>24</number> </property> <item> <widget class="QPushButton" name="m_ok"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>92</width> <height>40</height> </size> </property> <property name="text"> <string>Forced shutdown</string> </property> </widget> </item> <item> <widget class="QPushButton" name="m_cancel"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>92</width> <height>40</height> </size> </property> <property name="text"> <string>Cancel</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </item> </layout> </widget> </item> <item row="2" column="1"> <spacer name="m_bottomSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> <item row="0" column="1"> <spacer name="m_topSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeType"> <enum>QSizePolicy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> <item row="1" column="2"> <spacer name="m_rightSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </widget> </item> </layout> </widget> <resources/> <connections/> </ui> kiran-session-manager-2.5.0/src/ui/CMakeLists.txt0000664000175000017500000000257414417211336023313 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.0) file(GLOB_RECURSE UI_H_FILES ./*.h) file(GLOB_RECURSE UI_CPP_FILES ./*.cpp) # file(GLOB_RECURSE UI_FILES2 ./*.ui) set_source_files_properties( ${CMAKE_SOURCE_DIR}/data/org.gnome.SessionManager.xml PROPERTIES CLASSNAME SessionManagerProxy NO_NAMESPACE true) qt5_add_dbus_interface( SESSION_MANAGER_SRCS ${CMAKE_SOURCE_DIR}/data/org.gnome.SessionManager.xml session_manager_interface) set(TARGET_NAME kiran-session-window) qt5_wrap_ui(UI_FILES ${CMAKE_CURRENT_SOURCE_DIR}/exit-query-window.ui ${CMAKE_CURRENT_SOURCE_DIR}/inhibitor-row.ui) file(GLOB TS_FILES "${PROJECT_SOURCE_DIR}/translations/${TARGET_NAME}.*.ts") qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) add_executable( ${TARGET_NAME} ${UI_H_FILES} ${UI_CPP_FILES} ${UI_FILES} ${SESSION_MANAGER_SRCS} ${QM_FILES} "${PROJECT_SOURCE_DIR}/resources/resources.qrc") target_include_directories( ${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${KIRAN_STYLE_INCLUDE_DIRS}) target_link_libraries( ${TARGET_NAME} PRIVATE ${KIRAN_STYLE_LIBRARIES} Qt5::Widgets Qt5::DBus KF5::ConfigCore lib-base) install(FILES ${QM_FILES} DESTINATION ${KSM_INSTALL_TRANSLATIONDIR}) install(TARGETS ${TARGET_NAME} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}) kiran-session-manager-2.5.0/src/ui/exit-query-window.h0000664000175000017500000000272314417211336024341 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include <QWidget> class SessionManagerProxy; namespace Ui { class ExitQueryWindow; } // namespace Ui namespace Kiran { enum ExitQueryResponse { EXIT_QUERY_RESPONSE_OK, EXIT_QUERY_RESPONSE_CANCEL, }; class ExitQueryWindow : public QWidget { Q_OBJECT public: ExitQueryWindow(int32_t powerAction, QWidget *parent = nullptr); virtual ~ExitQueryWindow(){}; private: void initUI(); void initInhibitors(); void onResultClicked(bool checked, const QString &result); private: // virtual void resizeEvent(QResizeEvent *event) override; virtual void paintEvent(QPaintEvent *event) override; private Q_SLOTS: void onVirtualGeometryChanged(const QRect &rect); private: Ui::ExitQueryWindow *m_ui; SessionManagerProxy *m_sessionManagerProxy; int32_t m_powerAction; QPixmap m_backgroundPixmap; }; } // namespace Kiran kiran-session-manager-2.5.0/src/ui/exit-query-window.cpp0000664000175000017500000001471714417211336024702 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/ui/exit-query-window.h" #include <style-property.h> #include <KDesktopFile> #include <QApplication> #include <QDesktopWidget> #include <QJsonDocument> #include <QJsonObject> #include <QJsonValue> #include <QPainter> #include <QResizeEvent> #include <QScreen> #include <iostream> #include "lib/base/base.h" #include "src/ui/inhibitor-row.h" #include "src/ui/session_manager_interface.h" #include "src/ui/ui_exit-query-window.h" QT_BEGIN_NAMESPACE Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); QT_END_NAMESPACE namespace Kiran { #define BLUR_RADIUS 10 ExitQueryWindow::ExitQueryWindow(int32_t powerAction, QWidget *parent) : QWidget(parent, Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint | Qt::Widget), m_ui(new Ui::ExitQueryWindow), m_powerAction(powerAction) { this->m_ui->setupUi(this); this->m_sessionManagerProxy = new SessionManagerProxy(KSM_DBUS_NAME, KSM_DBUS_OBJECT_PATH, QDBusConnection::sessionBus(), this); this->initUI(); } void ExitQueryWindow::initUI() { auto primaryScreen = QApplication::primaryScreen(); auto desktopRect = primaryScreen->virtualGeometry(); this->m_ui->m_inhibitorsScrollArea->setStyleSheet("QScrollArea {background-color:transparent;}"); this->m_ui->m_inhibitorsScrollArea->setFrameStyle(QFrame::NoFrame); this->m_ui->m_inhibitorsScrollArea->viewport()->setStyleSheet("background-color:transparent;"); StylePropertyHelper::setButtonType(this->m_ui->m_ok, Kiran::ButtonType::BUTTON_Default); this->initInhibitors(); this->onVirtualGeometryChanged(desktopRect); connect(primaryScreen, SIGNAL(virtualGeometryChanged(const QRect &)), this, SLOT(onVirtualGeometryChanged(const QRect &))); connect(this->m_ui->m_ok, &QPushButton::clicked, std::bind(&ExitQueryWindow::onResultClicked, this, std::placeholders::_1, "ok")); connect(this->m_ui->m_cancel, &QPushButton::clicked, std::bind(&ExitQueryWindow::onResultClicked, this, std::placeholders::_1, "cancel")); } void ExitQueryWindow::initInhibitors() { QJsonParseError jsonError; auto reply = this->m_sessionManagerProxy->GetInhibitors(); reply.waitForFinished(); if (reply.isError()) { KLOG_WARNING() << "Failed to get inhibitors: " << reply.error().message(); return; } auto inhibitors = reply.value(); auto jsonDoc = QJsonDocument::fromJson(inhibitors.toUtf8(), &jsonError); if (jsonDoc.isNull()) { KLOG_WARNING() << "Parser inhibitors failed: " << jsonError.errorString(); return; } auto jsonRoot = jsonDoc.array(); this->m_ui->m_title->setText(tr("Closing %1 apps").arg(jsonRoot.size())); this->m_ui->m_titleDesc->setText(tr("If you want to go back and save your work, click 'cancel' and finish what you want to do")); for (auto iter : jsonRoot) { auto jsonInhibitor = iter.toObject(); if (jsonInhibitor.contains(KSM_INHIBITOR_JK_FLAGS) && jsonInhibitor.take(KSM_INHIBITOR_JK_FLAGS).toInt() == KSMInhibitorFlag::KSM_INHIBITOR_FLAG_QUIT) { this->m_ui->m_inhibitorsLayout->addWidget(new InhibitorRow(jsonInhibitor)); } } this->m_ui->m_inhibitorsLayout->addStretch(); switch (this->m_powerAction) { case PowerAction::POWER_ACTION_LOGOUT: this->m_ui->m_ok->setText(tr("Forced logout")); break; case PowerAction::POWER_ACTION_SHUTDOWN: this->m_ui->m_ok->setText(tr("Forced shutdown")); break; case PowerAction::POWER_ACTION_REBOOT: this->m_ui->m_ok->setText(tr("Forced reboot")); break; default: KLOG_WARNING() << "The power action is unsupported. action: " << this->m_powerAction; break; } } void ExitQueryWindow::onResultClicked(bool checked, const QString &result) { QJsonObject jsonObj; jsonObj.insert("response_id", result); QJsonDocument jsonDoc(jsonObj); std::cout << jsonDoc.toJson().data(); QApplication::quit(); } // void ExitQueryWindow::resizeEvent(QResizeEvent *event) // { // KLOG_WARNING() << "cur height: " << event->size().height() << " old height: " << event->oldSize().height(); // QWidget::resizeEvent(event); // } void ExitQueryWindow::paintEvent(QPaintEvent *event) { QPainter painter(this); auto screen = QApplication::primaryScreen(); auto desktopRect = screen->virtualGeometry(); // 只加载一次 if (this->m_backgroundPixmap.isNull()) { auto image = screen->grabWindow(QApplication::desktop()->winId(), desktopRect.x(), desktopRect.y(), desktopRect.width(), desktopRect.height()) .toImage(); qt_blurImage(image, BLUR_RADIUS, true); this->m_backgroundPixmap = QPixmap::fromImage(image); } painter.drawPixmap(desktopRect.x(), desktopRect.y(), this->m_backgroundPixmap); QWidget::paintEvent(event); } void ExitQueryWindow::onVirtualGeometryChanged(const QRect &rect) { this->move(rect.topLeft()); this->resize(QSize(rect.width(), rect.height())); auto primaryScreen = QApplication::primaryScreen(); auto primaryRect = primaryScreen->geometry(); auto x = primaryRect.x() + (primaryRect.width() - this->m_ui->m_content->width()) / 2; auto y = primaryRect.y() + (primaryRect.height() - this->m_ui->m_content->height()) / 2; this->m_ui->m_leftSpacer->changeSize(x, 1); this->m_ui->m_topSpacer->changeSize(1, y); } } // namespace Kiran kiran-session-manager-2.5.0/src/CMakeLists.txt0000664000175000017500000000010314417211336022660 0ustar wangyuchengwangyuchengadd_subdirectory(core) add_subdirectory(idle) add_subdirectory(ui) kiran-session-manager-2.5.0/src/idle/0000775000175000017500000000000014417211336021043 5ustar wangyuchengwangyuchengkiran-session-manager-2.5.0/src/idle/main.cpp0000664000175000017500000000237214417211336022477 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include <QFileInfo> #include <QGuiApplication> #include <QTranslator> #include <QtGlobal> #include "lib/base/base.h" #include "src/idle/idle-monitor.h" int main(int argc, char *argv[]) { auto argv0 = QFileInfo(argv[0]); auto programName = argv0.baseName(); if (klog_qt5_init(QString(), "kylinsec-session", PROJECT_NAME, programName) < 0) { fprintf(stderr, "Failed to init kiran-log."); } QGuiApplication app(argc, argv); QGuiApplication::setApplicationName(programName); QGuiApplication::setApplicationVersion(PROJECT_VERSION); Kiran::IdleMonitor idleMonitor; idleMonitor.init(); return app.exec(); } kiran-session-manager-2.5.0/src/idle/idle-monitor.h0000664000175000017500000000231114417211336023613 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #pragma once #include <QObject> class IdleMonitorAdaptor; namespace Kiran { class IdleMonitor : public QObject { Q_OBJECT public: IdleMonitor(QObject *parent = nullptr); virtual ~IdleMonitor(){}; void init(); public Q_SLOTS: // METHODS int AddIdleTimeout(qulonglong interval); qulonglong GetIdletime(); void RemoveIdleTimeout(int id); void SimulateUserActivity(); Q_SIGNALS: // SIGNALS void ResumingFromIdle(); void TimeoutReached(int id, qulonglong interval); private: IdleMonitorAdaptor *m_dbusAdaptor; QString m_clientID; }; } // namespace Kiran kiran-session-manager-2.5.0/src/idle/CMakeLists.txt0000664000175000017500000000160514417211336023605 0ustar wangyuchengwangyuchengcmake_minimum_required(VERSION 3.0) file(GLOB_RECURSE IDLE_H_FILES ./*.h) file(GLOB_RECURSE IDLE_CPP_FILES ./*.cpp) qt5_add_dbus_adaptor( IDLE_MONITOR_SRCS ${CMAKE_SOURCE_DIR}/data/com.kylinsec.Kiran.SessionManager.IdleMonitor.xml ${CMAKE_SOURCE_DIR}/src/idle/idle-monitor.h Kiran::IdleMonitor idle_monitor_adaptor IdleMonitorAdaptor) set(TARGET_NAME kiran-session-idlemonitor) add_executable(${TARGET_NAME} ${IDLE_H_FILES} ${IDLE_CPP_FILES} ${IDLE_MONITOR_SRCS}) target_include_directories( ${TARGET_NAME} PRIVATE ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${GSETTINGS_QT_INCLUDE_DIRS}) target_link_libraries( ${TARGET_NAME} PRIVATE ${GSETTINGS_QT_LIBRARIES} Qt5::Widgets Qt5::DBus KF5::IdleTime lib-base) install(TARGETS ${TARGET_NAME} DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}) kiran-session-manager-2.5.0/src/idle/idle-monitor.cpp0000664000175000017500000000432114417211336024151 0ustar wangyuchengwangyucheng/** * Copyright (c) 2020 ~ 2021 KylinSec Co., Ltd. * kiran-session-manager is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. * * Author: tangjie02 <tangjie02@kylinos.com.cn> */ #include "src/idle/idle-monitor.h" #include <KIdleTime> #include <QDBusConnection> #include <QGuiApplication> #include "lib/base/base.h" #include "src/idle/idle_monitor_adaptor.h" namespace Kiran { IdleMonitor::IdleMonitor(QObject* parent) : QObject(parent) { this->m_dbusAdaptor = new IdleMonitorAdaptor(this); } void IdleMonitor::init() { connect(KIdleTime::instance(), &KIdleTime::resumingFromIdle, [this]() { Q_EMIT this->ResumingFromIdle(); }); connect(KIdleTime::instance(), static_cast<void (KIdleTime::*)(int, int)>(&KIdleTime::timeoutReached), [this](int identifier, int msec) { Q_EMIT this->TimeoutReached(identifier, msec); KIdleTime::instance()->catchNextResumeEvent(); }); KIdleTime::instance()->catchNextResumeEvent(); auto sessionConnection = QDBusConnection::sessionBus(); if (!sessionConnection.registerService(KSM_IDLE_DBUS_NAME)) { KLOG_WARNING() << "Failed to register dbus name: " << KSM_IDLE_DBUS_NAME; } if (!sessionConnection.registerObject(KSM_IDLE_DBUS_OBJECT_PATH, this)) { KLOG_WARNING() << "Can't register object:" << sessionConnection.lastError(); } } int IdleMonitor::AddIdleTimeout(qulonglong interval) { return KIdleTime::instance()->addIdleTimeout(interval); } qulonglong IdleMonitor::GetIdletime() { return KIdleTime::instance()->idleTime(); } void IdleMonitor::RemoveIdleTimeout(int id) { KIdleTime::instance()->removeIdleTimeout(id); } void IdleMonitor::SimulateUserActivity() { KIdleTime::instance()->simulateUserActivity(); } } // namespace Kiran 0707010000000B000081A400000000000000000000000165AE3CE400001425000000000000000000000000000000000000004400000000kiran-session-manager-1705917668.255d400/kiran-session-manager.specName: kiran-session-manager Version: 2.5.0 Release: 12 Summary: Session manager for KIRAN desktop environment License: MulanPSL-2.0 Source0: %{name}-%{version}.tar.gz Patch1000: 0001-feature-lockscreen-Add-LockScreenWhenHibernate-and-L.patch Patch1001: 0001-feature-session-Add-always-show-exit-window-flag.patch Patch1002: 0001-Add-Type-Application-in-kiran-session-idlemonitor.de.patch Patch1003: 0001-fix-boot-Fix-fork-other-session-program-failed-by-ad.patch Patch1004: 0001-fix-kiran-session-manager-fixes-link-Qt5DBus-error.patch Patch1005: 0001-fix-xsmp-Ignore-the-cancel-shutdown-request.patch Patch1006: 0001-feature-blacklist_autostart_apps-Add-mate-volume-con.patch Patch1007: 0001-fix-blacklist-autostart-add-polkit-mate-authenticati.patch BuildRequires: cmake >= 3.2 BuildRequires: pkgconfig(gio-unix-2.0) BuildRequires: gcc-c++ BuildRequires: gettext BuildRequires: kiran-log-qt5-devel BuildRequires: gtest-devel BuildRequires: fmt-devel BuildRequires: libICE-devel BuildRequires: libSM-devel BuildRequires: libXext-devel BuildRequires: xorg-x11-xtrans-devel BuildRequires: gsettings-qt-devel BuildRequires: kiran-qt5-integration-devel BuildRequires: qt5-qtbase-devel BuildRequires: qt5-linguist BuildRequires: kf5-kconfig-devel BuildRequires: kf5-kidletime-devel BuildRequires: kf5-kio-devel Requires: systemd %if 0%{?rhel} > 7 || 0%{?openEuler} Requires: dbus-daemon %else Requires: dbus %endif %description Session manager for KIRAN desktop environment %prep %autosetup -p1 %build %cmake make %{?_smp_mflags} %install %make_install %post if [ "%{ks_custom_name}" = "GC" ] && [ -f "%{_datadir}/kiran-session-manager/blacklist_autostart_apps.txt" ]; then sed -i '$ d' "%{_datadir}/kiran-session-manager/blacklist_autostart_apps.txt" fi %files %{_datadir}/glib-2.0/schemas/com.kylinsec.kiran.session-manager.gschema.xml %{_datadir}/lightdm/lightdm.conf.d/90-lightdm-kiran-greeter.conf %{_datadir}/xsessions/kiran.desktop %{_datadir}/wayland-sessions/kiran-wayland.desktop %{_datadir}/xgreeters/kiran-greeter.desktop %{_datadir}/applications/kiran-session-idlemonitor.desktop %dir %{_datadir}/kiran-session-manager %{_datadir}/kiran-session-manager/blacklist_autostart_apps.txt %dir %{_datadir}/kiran-session-manager/sessions %{_datadir}/kiran-session-manager/sessions/* %{_datadir}/kiran-session-manager/translations/kiran-session-manager.zh_CN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-manager.bo_CN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-manager.kk_KG.qm %{_datadir}/kiran-session-manager/translations/kiran-session-manager.kk_KZ.qm %{_datadir}/kiran-session-manager/translations/kiran-session-manager.mn_MN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-manager.ug_CN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-window.zh_CN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-window.bo_CN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-window.kk_KG.qm %{_datadir}/kiran-session-manager/translations/kiran-session-window.kk_KZ.qm %{_datadir}/kiran-session-manager/translations/kiran-session-window.mn_MN.qm %{_datadir}/kiran-session-manager/translations/kiran-session-window.ug_CN.qm %{_bindir}/kiran-session-manager %{_bindir}/kiran-session-idlemonitor %{_bindir}/kiran-session-window %{_bindir}/kiran-session-kwayland %{_bindir}/kiran-session-wayland %changelog * Sat Jan 20 2024 liuxinhao <liuxinhao@kylinsec.com.cn> - 2.5.0-12 - KYOS-B: add polkit-mate-authentication-agent-1 to blacklist * Sun Oct 08 2023 luoqing <luoqing@kylinsec.com.cn> - 2.5.0-11 - KYOS-F: Add mate-volume-control-status-icon.desktop to the autostart blacklist * Tue Sep 12 2023 tangjie02 <tangjie02@kylinsec.com.cn> - 2.5.0-10 - KYOS-F: 0001-fix-xsmp-Ignore-the-cancel-shutdown-request.patch. * Mon Sep 11 2023 longcheng <longcheng@kylinsec.com.cn> - 2.5.0-9 - KYOS-B: change BuildRequires in redhat 7 (#14460) * Thu Sep 7 2023 yinhongchang <yinhongchang@kylinsec.com.cn> - 2.5.0-8 - KYOS-F: fixes link Qt5DBus error * Fri Jun 16 2023 tangjie02 <tangjie02@kylinsec.com.cn> - 2.5.0-7 - KYOS-B: Fix fork other session program failed by adding GDK_BACKEND and QT_QPA_FLATFORM environment variables. * Fri Jun 02 2023 huangjiawen <huangjiawen@kylinsec.com.cn> - 2.5.0-6 - KYOS-F: Add Type=Application in kiran-session-idlemonitor.desktop.in * Wed May 31 2023 huangjiawen <huangjiawen@kylinsec.com.cn> - 2.5.0-5 - KYOS-F: Add always show exit window flag. * Wed May 10 2023 tangjie02 <tangjie02@kylinsec.com.cn> - 2.5.0-4 - KYOS-F: Add LockScreenWhenHibernate and LockScreenWhenSuspend functions. * Tue May 09 2023 yinhongchang <yinhongchang.kylinsec.com.cn> - 2.5.0-3.kb1 - KYOS-F: resolve network-settings cant autostart * Wed Apr 19 2023 kpkg <kpkg.kylinsec.com.cn> - 2.5.0-3 - rebuild for KY3.4-5-GC-KiranUI-2.5 * Tue Apr 18 2023 kpkg <kpkg.kylinsec.com.cn> - 2.5.0-2 - rebuild for KiranUI-2.5-next * Tue Apr 18 2023 wangyucheng <wangyucheng@kylinsec.om.cn> - 2.5.0-1 - KYOS-F: Fix version number errors 0707010000000C000081A400000000000000000000000165AE3CE400000061000000000000000000000000000000000000004400000000kiran-session-manager-1705917668.255d400/kiran-session-manager.yamlversion_control: gitee src_repo: openeuler/kiran-session-manager tag_prefix: "^v" separator: "." 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!952 blocks
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2