File indexing completed on 2024-05-12 17:08:56
0001 /* 0002 SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "sessionsmodel.h" 0008 0009 #include <utility> 0010 0011 #include <KAuthorized> 0012 #include <KLocalizedString> 0013 #include <KUser> 0014 0015 #include "kscreensaversettings.h" 0016 0017 #include "screensaver_interface.h" 0018 0019 SessionsModel::SessionsModel(QObject *parent) 0020 : QAbstractListModel(parent) 0021 , m_screensaverInterface( 0022 new org::freedesktop::ScreenSaver(QStringLiteral("org.freedesktop.ScreenSaver"), QStringLiteral("/ScreenSaver"), QDBusConnection::sessionBus(), this)) 0023 { 0024 reload(); 0025 0026 // wait for the screen locker to be ready before actually switching 0027 connect(m_screensaverInterface, &org::freedesktop::ScreenSaver::ActiveChanged, this, [this](bool active) { 0028 if (active) { 0029 if (m_pendingVt) { 0030 m_displayManager.switchVT(m_pendingVt); 0031 Q_EMIT switchedUser(m_pendingVt); 0032 } else if (m_pendingReserve) { 0033 m_displayManager.startReserve(); 0034 Q_EMIT startedNewSession(); 0035 } 0036 0037 m_pendingVt = 0; 0038 m_pendingReserve = false; 0039 } 0040 }); 0041 } 0042 0043 bool SessionsModel::canSwitchUser() const 0044 { 0045 return const_cast<SessionsModel *>(this)->m_displayManager.isSwitchable() && KAuthorized::authorizeAction(QStringLiteral("switch_user")); 0046 } 0047 0048 bool SessionsModel::canStartNewSession() const 0049 { 0050 return const_cast<SessionsModel *>(this)->m_displayManager.numReserve() > 0 && KAuthorized::authorizeAction(QStringLiteral("start_new_session")); 0051 } 0052 0053 bool SessionsModel::shouldLock() const 0054 { 0055 return m_shouldLock; 0056 } 0057 0058 bool SessionsModel::includeUnusedSessions() const 0059 { 0060 return m_includeUnusedSessions; 0061 } 0062 0063 void SessionsModel::setIncludeUnusedSessions(bool includeUnusedSessions) 0064 { 0065 if (m_includeUnusedSessions != includeUnusedSessions) { 0066 m_includeUnusedSessions = includeUnusedSessions; 0067 0068 reload(); 0069 0070 Q_EMIT includeUnusedSessionsChanged(); 0071 } 0072 } 0073 0074 void SessionsModel::switchUser(int vt, bool shouldLock) 0075 { 0076 if (vt < 0) { 0077 startNewSession(shouldLock); 0078 return; 0079 } 0080 0081 if (!canSwitchUser()) { 0082 return; 0083 } 0084 0085 if (!shouldLock) { 0086 m_displayManager.switchVT(vt); 0087 Q_EMIT switchedUser(vt); 0088 return; 0089 } 0090 0091 checkScreenLocked([this, vt](bool locked) { 0092 if (locked) { 0093 // already locked, switch right away 0094 m_displayManager.switchVT(vt); 0095 Q_EMIT switchedUser(vt); 0096 } else { 0097 m_pendingReserve = false; 0098 m_pendingVt = vt; 0099 0100 Q_EMIT aboutToLockScreen(); 0101 m_screensaverInterface->Lock(); 0102 } 0103 }); 0104 } 0105 0106 void SessionsModel::startNewSession(bool shouldLock) 0107 { 0108 if (!canStartNewSession()) { 0109 return; 0110 } 0111 0112 if (!shouldLock) { 0113 m_displayManager.startReserve(); 0114 Q_EMIT startedNewSession(); 0115 return; 0116 } 0117 0118 checkScreenLocked([this](bool locked) { 0119 if (locked) { 0120 // already locked, switch right away 0121 m_displayManager.startReserve(); 0122 Q_EMIT startedNewSession(); 0123 } else { 0124 m_pendingReserve = true; 0125 m_pendingVt = 0; 0126 0127 Q_EMIT aboutToLockScreen(); 0128 m_screensaverInterface->Lock(); 0129 } 0130 }); 0131 } 0132 0133 void SessionsModel::reload() 0134 { 0135 static QHash<QString, KUser> kusers; 0136 0137 const bool oldShouldLock = m_shouldLock; 0138 m_shouldLock = KAuthorized::authorizeAction(QStringLiteral("lock_screen")) && KScreenSaverSettings::autolock(); 0139 if (m_shouldLock != oldShouldLock) { 0140 Q_EMIT shouldLockChanged(); 0141 } 0142 0143 SessList sessions; 0144 m_displayManager.localSessions(sessions); 0145 0146 const int oldCount = m_data.count(); 0147 0148 beginResetModel(); 0149 0150 m_data.clear(); 0151 m_data.reserve(sessions.count()); 0152 0153 for (const SessEnt &session : std::as_const(sessions)) { 0154 if (!session.vt || session.self) { 0155 continue; 0156 } 0157 0158 if (!m_includeUnusedSessions && session.session.isEmpty()) { 0159 continue; 0160 } 0161 0162 SessionEntry entry; 0163 entry.name = session.user; 0164 entry.displayNumber = session.display; 0165 entry.vtNumber = session.vt; 0166 entry.session = session.session; 0167 entry.isTty = session.tty; 0168 0169 auto it = kusers.constFind(session.user); 0170 if (it != kusers.constEnd()) { 0171 entry.realName = it->property(KUser::FullName).toString(); 0172 entry.icon = it->faceIconPath(); 0173 } else { 0174 KUser user(session.user); 0175 entry.realName = user.property(KUser::FullName).toString(); 0176 entry.icon = user.faceIconPath(); 0177 kusers.insert(session.user, user); 0178 } 0179 0180 m_data.append(entry); 0181 } 0182 0183 endResetModel(); 0184 0185 if (oldCount != m_data.count()) { 0186 Q_EMIT countChanged(); 0187 } 0188 } 0189 0190 void SessionsModel::checkScreenLocked(const std::function<void(bool)> &cb) 0191 { 0192 auto reply = m_screensaverInterface->GetActive(); 0193 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); 0194 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [cb](QDBusPendingCallWatcher *watcher) { 0195 QDBusPendingReply<bool> reply = *watcher; 0196 if (!reply.isError()) { 0197 cb(reply.value()); 0198 } 0199 watcher->deleteLater(); 0200 }); 0201 } 0202 0203 void SessionsModel::setShowNewSessionEntry(bool showNewSessionEntry) 0204 { 0205 if (!canStartNewSession()) { 0206 return; 0207 } 0208 0209 if (showNewSessionEntry == m_showNewSessionEntry) { 0210 return; 0211 } 0212 0213 int row = m_data.size(); 0214 if (showNewSessionEntry) { 0215 beginInsertRows(QModelIndex(), row, row); 0216 m_showNewSessionEntry = showNewSessionEntry; 0217 endInsertRows(); 0218 } else { 0219 beginRemoveRows(QModelIndex(), row, row); 0220 m_showNewSessionEntry = showNewSessionEntry; 0221 endRemoveRows(); 0222 } 0223 Q_EMIT countChanged(); 0224 } 0225 0226 QVariant SessionsModel::data(const QModelIndex &index, int role) const 0227 { 0228 if (index.row() < 0 || index.row() > rowCount(QModelIndex())) { 0229 return QVariant(); 0230 } 0231 0232 if (index.row() == m_data.count()) { 0233 switch (role) { 0234 case RealNameRole: 0235 return i18n("New Session"); 0236 case IconNameRole: 0237 return QStringLiteral("system-switch-user"); 0238 case NameRole: 0239 return i18n("New Session"); 0240 case DisplayNumberRole: 0241 return 0; // NA 0242 case VtNumberRole: 0243 return -1; // an invalid VtNumber - which we'll use to indicate it's to start a new session 0244 case SessionRole: 0245 return 0; // NA 0246 case IsTtyRole: 0247 return false; // NA 0248 default: 0249 return QVariant(); 0250 } 0251 } 0252 0253 const SessionEntry &item = m_data.at(index.row()); 0254 0255 switch (role) { 0256 case RealNameRole: 0257 return item.realName; 0258 case IconRole: 0259 return item.icon; 0260 case NameRole: 0261 return item.name; 0262 case DisplayNumberRole: 0263 return item.displayNumber; 0264 case VtNumberRole: 0265 return item.vtNumber; 0266 case SessionRole: 0267 return item.session; 0268 case IsTtyRole: 0269 return item.isTty; 0270 default: 0271 return QVariant(); 0272 } 0273 } 0274 0275 int SessionsModel::rowCount(const QModelIndex &parent) const 0276 { 0277 Q_UNUSED(parent); 0278 return m_data.count() + (m_showNewSessionEntry ? 1 : 0); 0279 } 0280 0281 QHash<int, QByteArray> SessionsModel::roleNames() const 0282 { 0283 QHash<int, QByteArray> roleNames; 0284 0285 roleNames[NameRole] = QByteArrayLiteral("name"); 0286 roleNames[RealNameRole] = QByteArrayLiteral("realName"); 0287 roleNames[IconRole] = QByteArrayLiteral("icon"); 0288 roleNames[IconNameRole] = QByteArrayLiteral("iconName"); 0289 roleNames[DisplayNumberRole] = QByteArrayLiteral("displayNumber"); 0290 roleNames[VtNumberRole] = QByteArrayLiteral("vtNumber"); 0291 roleNames[SessionRole] = QByteArrayLiteral("session"); 0292 roleNames[IsTtyRole] = QByteArrayLiteral("isTty"); 0293 0294 return roleNames; 0295 }