File indexing completed on 2024-04-28 13:32:00

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, const QVariantList &args)
0032     : KQuickAddons::ManagedConfigModule(parent, metaData, args)
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 
0184     // send values and paths to helper, debug if it fails
0185     QVariantMap args;
0186 
0187     args[QStringLiteral("kde_settings.conf")] = QString{QLatin1String(SDDM_CONFIG_DIR "/") + QStringLiteral("kde_settings.conf")};
0188 
0189     args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE);
0190 
0191     if (!cursorTheme.isNull()) {
0192         args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = cursorTheme;
0193     } else {
0194         qDebug() << "Cannot find cursor theme value.";
0195     }
0196     if (!cursorSize.isNull()) {
0197         args[QStringLiteral("kde_settings.conf/Theme/CursorSize")] = cursorSize;
0198     } else {
0199         qDebug() << "Cannot find cursor size value.";
0200     }
0201 
0202     if (!dpiValue.isEmpty()) {
0203         args[QStringLiteral("kde_settings.conf/X11/ServerArguments")] = dpiArgument;
0204     } else {
0205         qDebug() << "Cannot find scaling DPI value.";
0206     }
0207 
0208     if (!numLock.isEmpty()) {
0209         if (numLock == QStringLiteral("0")) {
0210             args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("on");
0211         } else if (numLock == QStringLiteral("1")) {
0212             args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("off");
0213         } else if (numLock == QStringLiteral("2")) {
0214             args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("none");
0215         }
0216     } else {
0217         qDebug() << "Cannot find NumLock value.";
0218     }
0219 
0220     if (!plasmaFont.isEmpty()) {
0221         args[QStringLiteral("kde_settings.conf/Theme/Font")] = plasmaFont;
0222     }
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     auto path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kscreen/", QStandardPaths::LocateDirectory);
0246     if (!path.isEmpty()) {
0247         args[QStringLiteral("kscreen-config")] = path;
0248     }
0249 
0250     KAuth::Action syncAction(QStringLiteral("org.kde.kcontrol.kcmsddm.sync"));
0251     syncAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0252     syncAction.setArguments(args);
0253 
0254     auto job = syncAction.execute();
0255     connect(job, &KJob::result, this, [this, job] {
0256         if (job->error()) {
0257             qDebug() << "Synchronization failed";
0258             qDebug() << job->errorString();
0259             qDebug() << job->errorText();
0260             if (!job->errorText().isEmpty()) {
0261                 Q_EMIT errorOccured(job->errorText());
0262             }
0263         } else {
0264             qDebug() << "Synchronization successful";
0265             Q_EMIT syncSuccessful();
0266         }
0267     });
0268     job->start();
0269 }
0270 
0271 void SddmKcm::resetSyncronizedSettings()
0272 {
0273     // initial check for sddm user; abort if user not present
0274     // we have to check with QString and isEmpty() instead of QDir and exists() because
0275     // QDir returns "." and true for exists() in the case of a non-existent user
0276     QString sddmHomeDirPath = KUser("sddm").homeDir();
0277     if (sddmHomeDirPath.isEmpty()) {
0278         Q_EMIT errorOccured(kli18n("Cannot proceed, user 'sddm' does not exist. Please check your SDDM install.").untranslatedText());
0279         return;
0280     }
0281 
0282     // send paths to helper
0283     QVariantMap args;
0284 
0285     args[QStringLiteral("kde_settings.conf")] = QStringLiteral(SDDM_CONFIG_DIR "/kde_settings.conf");
0286 
0287     args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE);
0288 
0289     args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = QVariant();
0290 
0291     args[QStringLiteral("kde_settings.conf/Theme/CursorSize")] = QVariant();
0292 
0293     args[QStringLiteral("kde_settings.conf/X11/ServerArguments")] = QVariant();
0294 
0295     args[QStringLiteral("kde_settings.conf/General/Numlock")] = QVariant();
0296 
0297     args[QStringLiteral("kde_settings.conf/Theme/Font")] = QVariant();
0298 
0299     KAuth::Action resetAction(QStringLiteral("org.kde.kcontrol.kcmsddm.reset"));
0300     resetAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm"));
0301     resetAction.setArguments(args);
0302 
0303     auto job = resetAction.execute();
0304 
0305     connect(job, &KJob::result, this, [this, job] {
0306         if (job->error()) {
0307             qDebug() << "Reset failed";
0308             qDebug() << job->errorString();
0309             qDebug() << job->errorText();
0310             if (!job->errorText().isEmpty()) {
0311                 Q_EMIT errorOccured(job->errorText());
0312             }
0313         } else {
0314             qDebug() << "Reset successful";
0315             Q_EMIT resetSyncedDataSuccessful();
0316         }
0317     });
0318     job->start();
0319 }
0320 
0321 bool SddmKcm::KDEWalletAvailable()
0322 {
0323     return !QStandardPaths::findExecutable(QLatin1String("kwalletmanager5")).isEmpty();
0324 }
0325 
0326 void SddmKcm::openKDEWallet()
0327 {
0328     KService::Ptr kwalletmanagerService = KService::serviceByDesktopName(QStringLiteral("org.kde.kwalletmanager5"));
0329     auto *job = new KIO::ApplicationLauncherJob(kwalletmanagerService);
0330     job->start();
0331 }
0332 
0333 #include "sddmkcm.moc"