File indexing completed on 2024-04-14 05:29:59

0001 /*
0002     SPDX-FileCopyrightText: 2013 Reza Fatahilah Shah <rshah0385@kireihana.com>
0003     SPDX-FileCopyrightText: 2019 Filip Fila <filipfila.kde@gmail.com>
0004     SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "sddmkcm.h"
0010 
0011 #include "config.h"
0012 #include "sddmdata.h"
0013 
0014 #include "sessionmodel.h"
0015 
0016 #include "usersmodel.h"
0017 
0018 #include <QApplication>
0019 #include <QDir>
0020 
0021 #include <KAuth/ExecuteJob>
0022 #include <KIO/ApplicationLauncherJob>
0023 #include <KLazyLocalizedString>
0024 #include <KLocalizedString>
0025 #include <KPluginFactory>
0026 #include <KService>
0027 #include <KUser>
0028 
0029 K_PLUGIN_FACTORY_WITH_JSON(KCMSddmFactory, "kcm_sddm.json", registerPlugin<SddmKcm>(); registerPlugin<SddmData>();)
0030 
0031 SddmKcm::SddmKcm(QObject *parent, const KPluginMetaData &metaData)
0032     : KQuickManagedConfigModule(parent, metaData)
0033     , m_data(new SddmData(this))
0034     , m_themesModel(new ThemesModel(this))
0035 {
0036     setAuthActionName(QStringLiteral("org.kde.kcontrol.kcmsddm.save"));
0037 
0038     qmlRegisterUncreatableType<ThemesModel>("org.kde.private.kcms.sddm", 1, 0, "ThemesModel", QStringLiteral("Cannot create ThemesModel"));
0039     qmlRegisterType<UsersModel>("org.kde.private.kcms.sddm", 1, 0, "UsersModel");
0040     qmlRegisterType<SessionModel>("org.kde.private.kcms.sddm", 1, 0, "SessionModel");
0041     qmlRegisterAnonymousType<SddmSettings>("org.kde.private.kcms.sddm", 1);
0042 
0043     connect(m_data->sddmSettings(), &SddmSettings::CurrentChanged, this, [this] {
0044         m_themesModel->setCurrentTheme(m_data->sddmSettings()->current());
0045     });
0046     m_themesModel->setCurrentTheme(m_data->sddmSettings()->current());
0047     // Currently only emmited when background changes
0048     connect(m_themesModel, &QAbstractItemModel::dataChanged, this, [this] {
0049         this->setNeedsSave(true);
0050     });
0051 }
0052 
0053 SddmKcm::~SddmKcm()
0054 {
0055 }
0056 
0057 SddmSettings *SddmKcm::sddmSettings() const
0058 {
0059     return m_data->sddmSettings();
0060 }
0061 
0062 ThemesModel *SddmKcm::themesModel() const
0063 {
0064     return m_themesModel;
0065 }
0066 
0067 QString SddmKcm::toLocalFile(const QUrl &url)
0068 {
0069     return url.toLocalFile();
0070 }
0071 
0072 void SddmKcm::removeTheme(const QModelIndex &index)
0073 {
0074     const QString path = m_themesModel->data(index, ThemesModel::PathRole).toString();
0075     KAuth::Action saveAction(QStringLiteral("org.kde.kcontrol.kcmsddm.uninstalltheme"));
0076     saveAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0077     saveAction.addArgument(QStringLiteral("filePath"), path);
0078     auto job = saveAction.execute();
0079     connect(job, &KJob::result, this, [this, job] {
0080         if (job->error()) {
0081             Q_EMIT errorOccured(job->errorString());
0082         } else {
0083             m_themesModel->populate();
0084         }
0085     });
0086     job->start();
0087 }
0088 
0089 void SddmKcm::installTheme(const QUrl &url)
0090 {
0091     KAuth::Action saveAction(QStringLiteral("org.kde.kcontrol.kcmsddm.installtheme"));
0092     saveAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0093     saveAction.addArgument(QStringLiteral("filePath"), url.toLocalFile());
0094     auto job = saveAction.execute();
0095     connect(job, &KJob::result, this, [this, job] {
0096         if (job->error()) {
0097             Q_EMIT errorOccured(job->errorString());
0098         } else {
0099             m_themesModel->populate();
0100         }
0101     });
0102     job->start();
0103 }
0104 
0105 void SddmKcm::save()
0106 {
0107     QVariantMap args;
0108 
0109     const QModelIndex currentThemeIndex = m_themesModel->index(m_themesModel->currentIndex());
0110     const QString themeConfigPath = m_themesModel->data(currentThemeIndex, ThemesModel::PathRole).toString()
0111         + m_themesModel->data(currentThemeIndex, ThemesModel::ConfigFileRole).toString();
0112     if (!themeConfigPath.isEmpty()) {
0113         args[QStringLiteral("theme.conf.user")] = QVariant(themeConfigPath + QStringLiteral(".user"));
0114         const QString backgroundPath = m_themesModel->data(currentThemeIndex, ThemesModel::CurrentBackgroundRole).toString();
0115         if (!backgroundPath.isEmpty()) {
0116             args[QStringLiteral("theme.conf.user/General/background")] = backgroundPath;
0117             args[QStringLiteral("theme.conf.user/General/type")] = QStringLiteral("image");
0118         } else {
0119             args[QStringLiteral("theme.conf.user/General/type")] = QStringLiteral("color");
0120         }
0121     }
0122     args[QStringLiteral("kde_settings.conf/Theme/Current")] = currentThemeIndex.data(ThemesModel::IdRole);
0123     args[QStringLiteral("kde_settings.conf/Autologin/User")] = m_data->sddmSettings()->user();
0124     args[QStringLiteral("kde_settings.conf/Autologin/Session")] = m_data->sddmSettings()->session();
0125     args[QStringLiteral("kde_settings.conf/Autologin/Relogin")] = m_data->sddmSettings()->relogin();
0126     args[QStringLiteral("kde_settings.conf/Users/MinimumUid")] = m_data->sddmSettings()->minimumUid();
0127     args[QStringLiteral("kde_settings.conf/Users/MaximumUid")] = m_data->sddmSettings()->maximumUid();
0128     args[QStringLiteral("kde_settings.conf/General/HaltCommand")] = m_data->sddmSettings()->haltCommand();
0129     args[QStringLiteral("kde_settings.conf/General/RebootCommand")] = m_data->sddmSettings()->rebootCommand();
0130 
0131     KAuth::Action saveAction(authActionName());
0132     saveAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0133     saveAction.setArguments(args);
0134 
0135     auto job = saveAction.execute();
0136     connect(job, &KJob::result, this, [this, job] {
0137         if (job->error()) {
0138             Q_EMIT errorOccured(job->errorString());
0139         } else {
0140             m_data->sddmSettings()->load();
0141         }
0142         // Clarify enable or disable the Apply button.
0143         this->setNeedsSave(job->error());
0144     });
0145     job->start();
0146 }
0147 
0148 void SddmKcm::synchronizeSettings()
0149 {
0150     // initial check for sddm user; abort if user not present
0151     // we have to check with QString and isEmpty() instead of QDir and exists() because
0152     // QDir returns "." and true for exists() in the case of a non-existent user;
0153     QString sddmHomeDirPath = KUser("sddm").homeDir();
0154     if (sddmHomeDirPath.isEmpty()) {
0155         Q_EMIT errorOccured(kli18n("Cannot proceed, user 'sddm' does not exist. Please check your SDDM install.").untranslatedText());
0156         return;
0157     }
0158 
0159     // read Plasma values
0160     KConfig cursorConfig(QStringLiteral("kcminputrc"));
0161     KConfigGroup cursorConfigGroup(&cursorConfig, "Mouse");
0162     QVariant cursorTheme = cursorConfigGroup.readEntry("cursorTheme", QString());
0163     QVariant cursorSize = cursorConfigGroup.readEntry("cursorSize", QString());
0164 
0165     KConfig dpiConfig(QStringLiteral("kcmfonts"));
0166     KConfigGroup dpiConfigGroup(&dpiConfig, "General");
0167     QString dpiValue = dpiConfigGroup.readEntry("forceFontDPI");
0168     QString dpiArgument = QStringLiteral("-dpi ") + dpiValue;
0169 
0170     KConfig numLockConfig(QStringLiteral("kcminputrc"));
0171     KConfigGroup numLockConfigGroup(&numLockConfig, "Keyboard");
0172     QString numLock = numLockConfigGroup.readEntry("NumLock");
0173 
0174     // Syncing the font only works with SDDM >= 0.19, but will not have a negative effect with older versions
0175     KConfig plasmaFontConfig(QStringLiteral("kdeglobals"));
0176     KConfigGroup plasmaFontGroup(&plasmaFontConfig, "General");
0177     QString plasmaFont = plasmaFontGroup.readEntry("font", QApplication::font().toString());
0178 
0179     // define paths
0180     const QString fontconfigPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("fontconfig"), QStandardPaths::LocateDirectory);
0181     const QString kdeglobalsPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("kdeglobals"));
0182     const QString plasmarcPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("plasmarc"));
0183     const QString kcminputrcPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("kcminputrc"));
0184 
0185     // send values and paths to helper, debug if it fails
0186     QVariantMap args;
0187 
0188     args[QStringLiteral("kde_settings.conf")] = QString{QLatin1String(SDDM_CONFIG_DIR "/") + QStringLiteral("kde_settings.conf")};
0189 
0190     args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE);
0191 
0192     if (!cursorTheme.isNull()) {
0193         args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = cursorTheme;
0194     } else {
0195         qDebug() << "Cannot find cursor theme value.";
0196     }
0197     if (!cursorSize.isNull()) {
0198         args[QStringLiteral("kde_settings.conf/Theme/CursorSize")] = cursorSize;
0199     } else {
0200         qDebug() << "Cannot find cursor size value.";
0201     }
0202 
0203     if (!dpiValue.isEmpty()) {
0204         args[QStringLiteral("kde_settings.conf/X11/ServerArguments")] = dpiArgument;
0205     } else {
0206         qDebug() << "Cannot find scaling DPI value.";
0207     }
0208 
0209     if (!numLock.isEmpty()) {
0210         if (numLock == QStringLiteral("0")) {
0211             args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("on");
0212         } else if (numLock == QStringLiteral("1")) {
0213             args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("off");
0214         } else if (numLock == QStringLiteral("2")) {
0215             args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("none");
0216         }
0217     } else {
0218         qDebug() << "Cannot find NumLock value.";
0219     }
0220 
0221     if (!plasmaFont.isEmpty()) {
0222         args[QStringLiteral("kde_settings.conf/Theme/Font")] = plasmaFont;
0223     } else {
0224         qDebug() << "Cannot find Plasma font value.";
0225     }
0226 
0227     if (!fontconfigPath.isEmpty()) {
0228         args[QStringLiteral("fontconfig")] = fontconfigPath;
0229     } else {
0230         qDebug() << "Cannot find fontconfig folder.";
0231     }
0232 
0233     if (!kdeglobalsPath.isEmpty()) {
0234         args[QStringLiteral("kdeglobals")] = kdeglobalsPath;
0235     } else {
0236         qDebug() << "Cannot find kdeglobals file.";
0237     }
0238 
0239     if (!plasmarcPath.isEmpty()) {
0240         args[QStringLiteral("plasmarc")] = plasmarcPath;
0241     } else {
0242         qDebug() << "Cannot find plasmarc file.";
0243     }
0244 
0245     if (!kcminputrcPath.isEmpty()) {
0246         args[QStringLiteral("kcminputrc")] = kcminputrcPath;
0247     } else {
0248         qDebug() << "Cannot find kcminputrc file.";
0249     }
0250 
0251     auto path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kscreen/", QStandardPaths::LocateDirectory);
0252     if (!path.isEmpty()) {
0253         args[QStringLiteral("kscreen-config")] = path;
0254     }
0255 
0256     KAuth::Action syncAction(QStringLiteral("org.kde.kcontrol.kcmsddm.sync"));
0257     syncAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0258     syncAction.setArguments(args);
0259 
0260     auto job = syncAction.execute();
0261     connect(job, &KJob::result, this, [this, job] {
0262         if (job->error()) {
0263             qDebug() << "Synchronization failed";
0264             qDebug() << job->errorString();
0265             qDebug() << job->errorText();
0266             if (!job->errorText().isEmpty()) {
0267                 Q_EMIT errorOccured(job->errorText());
0268             }
0269         } else {
0270             qDebug() << "Synchronization successful";
0271             Q_EMIT syncSuccessful();
0272         }
0273     });
0274     job->start();
0275 }
0276 
0277 void SddmKcm::resetSyncronizedSettings()
0278 {
0279     // initial check for sddm user; abort if user not present
0280     // we have to check with QString and isEmpty() instead of QDir and exists() because
0281     // QDir returns "." and true for exists() in the case of a non-existent user
0282     QString sddmHomeDirPath = KUser("sddm").homeDir();
0283     if (sddmHomeDirPath.isEmpty()) {
0284         Q_EMIT errorOccured(kli18n("Cannot proceed, user 'sddm' does not exist. Please check your SDDM install.").untranslatedText());
0285         return;
0286     }
0287 
0288     // send paths to helper
0289     QVariantMap args;
0290 
0291     args[QStringLiteral("kde_settings.conf")] = QStringLiteral(SDDM_CONFIG_DIR "/kde_settings.conf");
0292 
0293     args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE);
0294 
0295     args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = QVariant();
0296 
0297     args[QStringLiteral("kde_settings.conf/Theme/CursorSize")] = QVariant();
0298 
0299     args[QStringLiteral("kde_settings.conf/X11/ServerArguments")] = QVariant();
0300 
0301     args[QStringLiteral("kde_settings.conf/General/Numlock")] = QVariant();
0302 
0303     args[QStringLiteral("kde_settings.conf/Theme/Font")] = QVariant();
0304 
0305     KAuth::Action resetAction(QStringLiteral("org.kde.kcontrol.kcmsddm.reset"));
0306     resetAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0307     resetAction.setArguments(args);
0308 
0309     auto job = resetAction.execute();
0310 
0311     connect(job, &KJob::result, this, [this, job] {
0312         if (job->error()) {
0313             qDebug() << "Reset failed";
0314             qDebug() << job->errorString();
0315             qDebug() << job->errorText();
0316             if (!job->errorText().isEmpty()) {
0317                 Q_EMIT errorOccured(job->errorText());
0318             }
0319         } else {
0320             qDebug() << "Reset successful";
0321             Q_EMIT resetSyncedDataSuccessful();
0322         }
0323     });
0324     job->start();
0325 }
0326 
0327 bool SddmKcm::KDEWalletAvailable()
0328 {
0329     return !QStandardPaths::findExecutable(QLatin1String("kwalletmanager5")).isEmpty();
0330 }
0331 
0332 void SddmKcm::openKDEWallet()
0333 {
0334     KService::Ptr kwalletmanagerService = KService::serviceByDesktopName(QStringLiteral("org.kde.kwalletmanager5"));
0335     auto *job = new KIO::ApplicationLauncherJob(kwalletmanagerService);
0336     job->start();
0337 }
0338 
0339 #include "sddmkcm.moc"