diff --git a/sddmauthhelper.cpp b/sddmauthhelper.cpp index 0b66958..8f2e3f1 100644 --- a/sddmauthhelper.cpp +++ b/sddmauthhelper.cpp @@ -1,378 +1,378 @@ /* Copyright 2013 by Reza Fatahilah Shah Copyright 2011, 2012 David Edmundson This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sddmauthhelper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QSharedPointer openConfig(const QString &filePath) { QFile file(filePath); if(!file.exists()) { // If we are creating the config file, ensure it is world-readable: if // we don't do that, KConfig will create a file which is only readable // by root file.open(QIODevice::WriteOnly); file.close(); file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); } return QSharedPointer(new KConfig(file.fileName(), KConfig::SimpleConfig)); } void SddmAuthHelper::copyFile(const QString &source, const QString &destination) { KUser sddmUser(QStringLiteral("sddm")); if (QFile::exists(destination)) { QFile::remove(destination); } QFile::copy(source, destination); const char* destinationConverted = destination.toLocal8Bit().data(); if (chown(destinationConverted, sddmUser.userId().nativeId(), sddmUser.groupId().nativeId())) { return; } } ActionReply SddmAuthHelper::sync(const QVariantMap &args) { QDir sddmConfigLocation(args[QStringLiteral("sddmUserConfig")].toString()); if (!sddmConfigLocation.exists()) { QDir().mkpath(sddmConfigLocation.path()); } // copy fontconfig (font, font rendering) if (!args[QStringLiteral("fontconfig")].isNull()) { QDir fontconfigSource(args[QStringLiteral("fontconfig")].toString()); QStringList sourceFileEntries = fontconfigSource.entryList (QDir::Files); QStringList sourceDirEntries = fontconfigSource.entryList (QDir::AllDirs); QDir fontconfigDestination(sddmConfigLocation.path() + QStringLiteral("/fontconfig")); if (!fontconfigDestination.exists()) { QDir().mkpath(fontconfigDestination.path()); } if (sourceDirEntries.count() != 0) { for (int i = 0; i sddmConfig = openConfig(args[QStringLiteral("kde_settings.conf")].toString()); QSharedPointer sddmOldConfig = openConfig(args[QStringLiteral("sddm.conf")].toString()); QMap::const_iterator iterator; for (iterator = args.constBegin() ; iterator != args.constEnd() ; ++iterator) { if (iterator.key() == QLatin1String("kde_settings.conf")) continue; QStringList configFields = iterator.key().split(QLatin1Char('/')); if (configFields.size() != 3) { continue; } QSharedPointer config; QString fileName = configFields[0]; QString groupName = configFields[1]; QString keyName = configFields[2]; if (fileName == QLatin1String("kde_settings.conf") && iterator.value().isValid()) { sddmConfig->group(groupName).writeEntry(keyName, iterator.value()); sddmOldConfig->group(groupName).deleteEntry(keyName); } } sddmOldConfig->sync(); sddmConfig->sync(); return ActionReply::SuccessReply(); } ActionReply SddmAuthHelper::reset(const QVariantMap &args) { QDir sddmConfigLocation(args[QStringLiteral("sddmUserConfig")].toString()); QDir fontconfigDir(args[QStringLiteral("sddmUserConfig")].toString() + QStringLiteral("/fontconfig")); fontconfigDir.removeRecursively(); QFile::remove(sddmConfigLocation.path() + QStringLiteral("/kdeglobals")); QFile::remove(sddmConfigLocation.path() + QStringLiteral("/plasmarc")); - // remove cursor theme and NumLock preference from config file + // remove cursor theme, scaling DPI, and NumLock preference from config file ActionReply reply = ActionReply::HelperErrorReply(); QSharedPointer sddmConfig = openConfig(args[QStringLiteral("kde_settings.conf")].toString()); QSharedPointer sddmOldConfig = openConfig(args[QStringLiteral("sddm.conf")].toString()); QMap::const_iterator iterator; for (iterator = args.constBegin() ; iterator != args.constEnd() ; ++iterator) { if (iterator.key() == QLatin1String("kde_settings.conf")) continue; QStringList configFields = iterator.key().split(QLatin1Char('/')); if (configFields.size() != 3) { continue; } QSharedPointer config; QString fileName = configFields[0]; QString groupName = configFields[1]; QString keyName = configFields[2]; if (fileName == QLatin1String("kde_settings.conf")) { sddmConfig->group(groupName).deleteEntry(keyName); sddmOldConfig->group(groupName).deleteEntry(keyName); } } sddmOldConfig->sync(); sddmConfig->sync(); return ActionReply::SuccessReply(); } ActionReply SddmAuthHelper::save(const QVariantMap &args) { ActionReply reply = ActionReply::HelperErrorReply(); QSharedPointer sddmConfig = openConfig(args[QStringLiteral("kde_settings.conf")].toString()); QSharedPointer sddmOldConfig = openConfig(args[QStringLiteral("sddm.conf")].toString()); QSharedPointer themeConfig; QString themeConfigFile = args[QStringLiteral("theme.conf.user")].toString(); if (!themeConfigFile.isEmpty()) { themeConfig = openConfig(themeConfigFile); } QMap::const_iterator iterator; for (iterator = args.constBegin() ; iterator != args.constEnd() ; ++iterator) { if (iterator.key() == QLatin1String("kde_settings.conf") || iterator.key() == QLatin1String("theme.conf.user")) continue; QStringList configFields = iterator.key().split(QLatin1Char('/')); if (configFields.size() != 3) { continue; } QSharedPointer config; QString fileName = configFields[0]; QString groupName = configFields[1]; QString keyName = configFields[2]; // if there is an identical keyName in "sddm.conf" we want to delete it so SDDM doesn't read from the old file // hierarchically SDDM prefers "etc/sddm.conf" to "/etc/sddm.conf.d/some_file.conf" if (fileName == QLatin1String("kde_settings.conf")) { sddmConfig->group(groupName).writeEntry(keyName, iterator.value()); sddmOldConfig->group(groupName).deleteEntry(keyName); } else if (fileName == QLatin1String("theme.conf.user") && !themeConfig.isNull()) { QFileInfo themeConfigFileInfo(themeConfigFile); QDir configRootDirectory = themeConfigFileInfo.absoluteDir(); if (keyName == QLatin1String("background")) { QFileInfo newBackgroundFileInfo(iterator.value().toString()); QString previousBackground = themeConfig->group(groupName).readEntry(keyName); bool backgroundChanged = newBackgroundFileInfo.fileName() != previousBackground; if (backgroundChanged) { if (!previousBackground.isEmpty()) { QString previousBackgroundPath = configRootDirectory.filePath(previousBackground); if (QFile::remove(previousBackgroundPath)) { qDebug() << "Removed previous background " << previousBackgroundPath; } } if (newBackgroundFileInfo.exists()) { QString newBackgroundPath = configRootDirectory.filePath(newBackgroundFileInfo.fileName()); qDebug() << "Copying background from " << newBackgroundFileInfo.absoluteFilePath() << " to " << newBackgroundPath; if (QFile::copy(newBackgroundFileInfo.absoluteFilePath(), newBackgroundPath)) { QFile::setPermissions(newBackgroundPath, QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); themeConfig->group(groupName).writeEntry(keyName, newBackgroundFileInfo.fileName()); } } else { themeConfig->group(groupName).deleteEntry(keyName); } } } else { themeConfig->group(groupName).writeEntry(keyName, iterator.value()); } } } sddmOldConfig->sync(); sddmConfig->sync(); if (!themeConfig.isNull()) themeConfig->sync(); return ActionReply::SuccessReply(); } ActionReply SddmAuthHelper::installtheme(const QVariantMap &args) { const QString filePath = args[QStringLiteral("filePath")].toString(); if (filePath.isEmpty()) { return ActionReply::HelperErrorReply(); } const QString themesBaseDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("sddm/themes"), QStandardPaths::LocateDirectory); QDir dir(themesBaseDir); if (!dir.exists()) { return ActionReply::HelperErrorReply(); } qDebug() << "Installing " << filePath << " into " << themesBaseDir; if (!QFile::exists(filePath)) { return ActionReply::HelperErrorReply(); } QMimeDatabase db; QMimeType mimeType = db.mimeTypeForFile(filePath); qWarning() << "Postinstallation: uncompress the file"; QScopedPointer archive; //there must be a better way to do this? If not, make a static bool KZip::supportsMimeType(const QMimeType &type); ? //or even a factory class in KArchive if (mimeType.inherits(QStringLiteral("application/zip"))) { archive.reset(new KZip(filePath)); } else if (mimeType.inherits(QStringLiteral("application/tar")) || mimeType.inherits(QStringLiteral("application/x-gzip")) || mimeType.inherits(QStringLiteral("application/x-bzip")) || mimeType.inherits(QStringLiteral("application/x-lzma")) || mimeType.inherits(QStringLiteral("application/x-xz")) || mimeType.inherits(QStringLiteral("application/x-bzip-compressed-tar")) || mimeType.inherits(QStringLiteral("application/x-compressed-tar"))) { archive.reset(new KTar(filePath)); } else { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Invalid theme package")); return e; } if (!archive->open(QIODevice::ReadOnly)) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Could not open file")); return e; } auto directory = archive->directory(); QStringList installedPaths; //some basic validation //the top level should only have folders, and those folders should contain a valid metadata.desktop file //if we get anything else, abort everything before copying for(const QString &name: directory->entries()) { auto entry = directory->entry(name); if (!entry->isDirectory()) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Invalid theme package")); return e; } auto subDirectory = static_cast(entry); auto metadataFile = subDirectory->file(QStringLiteral("metadata.desktop")); if(!metadataFile || !metadataFile->data().contains("[SddmGreeterTheme]")) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Invalid theme package")); return e; } installedPaths.append(themesBaseDir + QLatin1Char('/') + name); } if (!directory->copyTo(themesBaseDir)) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Could not decompress archive")); return e; } auto rc = ActionReply::SuccessReply(); rc.addData(QStringLiteral("installedPaths"), installedPaths); return rc; } ActionReply SddmAuthHelper::uninstalltheme(const QVariantMap &args) { const QString themePath = args[QStringLiteral("filePath")].toString(); const QString themesBaseDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("sddm/themes"), QStandardPaths::LocateDirectory); QDir dir(themePath); if (!dir.exists()) { return ActionReply::HelperErrorReply(); } //validate the themePath is directly inside the themesBaseDir QDir baseDir(themesBaseDir); if(baseDir.absoluteFilePath(dir.dirName()) != dir.absolutePath()) { return ActionReply::HelperErrorReply(); } if (!dir.removeRecursively()) { return ActionReply::HelperErrorReply(); } return ActionReply::SuccessReply(); } KAUTH_HELPER_MAIN("org.kde.kcontrol.kcmsddm", SddmAuthHelper) #include "moc_sddmauthhelper.cpp" diff --git a/src/advanceconfig.cpp b/src/advanceconfig.cpp index 61b86db..cf10895 100644 --- a/src/advanceconfig.cpp +++ b/src/advanceconfig.cpp @@ -1,239 +1,245 @@ /* Copyright 2013 by Reza Fatahilah Shah This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "advanceconfig.h" #include "ui_advanceconfig.h" #include "config.h" #include "sessionmodel.h" #include "usersmodel.h" #include #include #include #include #include #include #include #include #include const int MIN_UID = 1000; const int MAX_UID = 60000; AdvanceConfig::AdvanceConfig(const KSharedConfigPtr &config, QWidget *parent) : QWidget(parent), mConfig(config) { configUi = new Ui::AdvanceConfig(); configUi->setupUi(this); configUi->syncExplanation->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); load(); connect(configUi->userList, SIGNAL(activated(int)), SIGNAL(changed())); connect(configUi->sessionList, SIGNAL(activated(int)), SIGNAL(changed())); connect(configUi->haltCommand, SIGNAL(textChanged(QString)), SIGNAL(changed())); connect(configUi->rebootCommand, SIGNAL(textChanged(QString)), SIGNAL(changed())); connect(configUi->minimumUid, SIGNAL(textChanged(QString)), SIGNAL(changed())); connect(configUi->minimumUid, &QLineEdit::textChanged, this, &AdvanceConfig::slotUidRangeChanged); connect(configUi->maximumUid, SIGNAL(textChanged(QString)), SIGNAL(changed())); connect(configUi->maximumUid, &QLineEdit::textChanged, this, &AdvanceConfig::slotUidRangeChanged); // manually emit changed signal since QCheckBox::clicked will pass false to changed() when unchecked connect(configUi->autoLogin, &QCheckBox::clicked, this, [this] { emit changed(); }); connect(configUi->reloginAfterQuit, &QAbstractButton::clicked, this, [this] { emit changed(); }); connect(configUi->syncSettings, &QPushButton::clicked, this, &AdvanceConfig::syncSettingsChanged); connect(configUi->resetSettings, &QPushButton::clicked, this, &AdvanceConfig::resetSettingsChanged); } AdvanceConfig::~AdvanceConfig() { delete configUi; } void AdvanceConfig::load() { //User list int minUid, maxUid; minUid = mConfig->group("Users").readEntry("MinimumUid", MIN_UID); maxUid = mConfig->group("Users").readEntry("MaximumUid", MAX_UID); userModel = new UsersModel(this); configUi->userList->setModel(userModel); userModel->populate( minUid, maxUid ); sessionModel = new SessionModel(this); configUi->sessionList->setModel(sessionModel); const QString currentUser = mConfig->group("Autologin").readEntry("User", ""); configUi->userList->setCurrentIndex(userModel->indexOf(currentUser)); const QString autologinSession = mConfig->group("Autologin").readEntry("Session", ""); configUi->sessionList->setCurrentIndex(sessionModel->indexOf(autologinSession)); configUi->autoLogin->setChecked(!currentUser.isEmpty()); configUi->reloginAfterQuit->setChecked(mConfig->group("Autologin").readEntry("Relogin", false)); QValidator *uidValidator = new QIntValidator(MIN_UID, MAX_UID, configUi->minimumUid); configUi->minimumUid->setValidator(uidValidator); configUi->minimumUid->setText(QString::number(minUid)); configUi->maximumUid->setValidator(uidValidator); configUi->maximumUid->setText(QString::number(maxUid)); //Commands configUi->haltCommand->setUrl(QUrl::fromLocalFile(mConfig->group("General").readEntry("HaltCommand"))); configUi->rebootCommand->setUrl(QUrl::fromLocalFile(mConfig->group("General").readEntry("RebootCommand"))); } QVariantMap AdvanceConfig::save() { QVariantMap args; args[QStringLiteral("kde_settings.conf/Autologin/User")] = ( configUi->autoLogin->isChecked() ) ? configUi->userList->currentText() : QString(); args[QStringLiteral("kde_settings.conf/Autologin/Session")] = ( configUi->autoLogin->isChecked() ) ? configUi->sessionList->currentData() : QString(); args[QStringLiteral("kde_settings.conf/Autologin/Relogin")] = configUi->reloginAfterQuit->isChecked(); //TODO session int minUid = configUi->minimumUid->text().toInt(); int maxUid = configUi->maximumUid->text().toInt(); if (isUidRangeValid(minUid, maxUid)) { args[QStringLiteral("kde_settings.conf/Users/MinimumUid")] = configUi->minimumUid->text(); args[QStringLiteral("kde_settings.conf/Users/MaximumUid")] = configUi->maximumUid->text(); } args[QStringLiteral("kde_settings.conf/General/HaltCommand")] = configUi->haltCommand->url().toLocalFile(); args[QStringLiteral("kde_settings.conf/General/RebootCommand")] = configUi->rebootCommand->url().toLocalFile(); return args; } void AdvanceConfig::slotUidRangeChanged() { int minUid = configUi->minimumUid->text().toInt(); int maxUid = configUi->maximumUid->text().toInt(); if (!isUidRangeValid(minUid, maxUid)) { return; } userModel->populate(minUid, maxUid); } bool AdvanceConfig::isUidRangeValid(int minUid, int maxUid) const { if (minUid < 0 || minUid > maxUid) return false; return true; } void AdvanceConfig::syncSettingsChanged() { KConfig cursorConfig(QStringLiteral("kcminputrc")); KConfigGroup cursorConfigGroup(&cursorConfig, "Mouse"); QVariant cursorTheme = cursorConfigGroup.readEntry("cursorTheme", QString()); + KConfig dpiConfig(QStringLiteral("kcmfonts")); + KConfigGroup dpiConfigGroup(&dpiConfig, "General"); + QString dpiValue = QStringLiteral("-dpi ") + dpiConfigGroup.readEntry("forceFontDPI"); + KConfig numLockConfig(QStringLiteral("kcminputrc")); KConfigGroup numLockConfigGroup(&numLockConfig, "Keyboard"); QString numLock = numLockConfigGroup.readEntry("NumLock"); const QString fontconfigPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("fontconfig"), QStandardPaths::LocateDirectory); const QString kdeglobalsPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("kdeglobals")); const QString plasmarcPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("plasmarc")); const QString sddmUserConfigPath = KUser("sddm").homeDir() + QStringLiteral("/.config"); if (fontconfigPath.isEmpty()) { qDebug() << "fontconfig folder not found"; } if (kdeglobalsPath.isEmpty()) { qDebug() << "kdeglobals file not found"; } if (plasmarcPath.isEmpty()) { qDebug() << "plasmarc file not found"; } QVariantMap args; args[QStringLiteral("kde_settings.conf")] = QString {QLatin1String(SDDM_CONFIG_DIR "/") + QStringLiteral("kde_settings.conf")}; args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE); args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = cursorTheme; + args[QStringLiteral("kde_settings.conf/X11/ServerArguments")] = dpiValue; if (!numLock.isEmpty()) { if (numLock == QStringLiteral("0")) { args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("on"); } else if (numLock == QStringLiteral("1")) { args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("off"); } else { args[QStringLiteral("kde_settings.conf/General/Numlock")] = QStringLiteral("none"); } } args[QStringLiteral("fontconfig")] = fontconfigPath; args[QStringLiteral("kdeglobals")] = kdeglobalsPath; args[QStringLiteral("plasmarc")] = plasmarcPath; args[QStringLiteral("sddmUserConfig")] = sddmUserConfigPath; KAuth::Action syncAction(QStringLiteral("org.kde.kcontrol.kcmsddm.sync")); syncAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm")); syncAction.setArguments(args); auto job = syncAction.execute(); job->exec(); if (job->error()){ qDebug() << "Synchronization failed"; qDebug() << job->errorString(); qDebug() << job->errorText(); KMessageBox::error(this, job->errorText()); } else { changed(false); qDebug() << "Synchronization successful"; } } void AdvanceConfig::resetSettingsChanged() { const QString sddmUserConfigPath = KUser("sddm").homeDir() + QStringLiteral("/.config"); QVariantMap args; args[QStringLiteral("sddmUserConfig")] = sddmUserConfigPath; args[QStringLiteral("kde_settings.conf")] = QString {QLatin1String(SDDM_CONFIG_DIR "/") + QStringLiteral("kde_settings.conf")}; args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE); args[QStringLiteral("sddmUserConfig")] = sddmUserConfigPath; args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = QVariant(); + args[QStringLiteral("kde_settings.conf/X11/ServerArguments")] = QVariant(); args[QStringLiteral("kde_settings.conf/General/Numlock")] = QVariant(); KAuth::Action resetAction(QStringLiteral("org.kde.kcontrol.kcmsddm.reset")); resetAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm")); resetAction.setArguments(args); auto job = resetAction.execute(); job->exec(); if (job->error()){ qDebug() << "Reset failed"; qDebug() << job->errorString(); qDebug() << job->errorText(); KMessageBox::error(this, job->errorText()); } else { changed(false); qDebug() << "Reset successful"; } } diff --git a/src/ui/advanceconfig.ui b/src/ui/advanceconfig.ui index c4b0da1..537d932 100644 --- a/src/ui/advanceconfig.ui +++ b/src/ui/advanceconfig.ui @@ -1,328 +1,328 @@ AdvanceConfig 0 0 547 - 391 + 409 QFormLayout::FieldsStayAtSizeHint Qt::AlignHCenter|Qt::AlignTop Automatically log in: as user: false false with session: false false 0 0 Log in again immediately after logging off Qt::Vertical 8 8 Minimum user UID: 0 0 6 Maximum user UID: 0 0 6 Qt::Vertical 8 8 Halt command: 250 0 Reboot command: 250 0 Qt::Vertical 8 8 Settings synchronization: Sync Reset 0 0 320 - 70 + 90 - Settings synchronization allows you to transfer your theme customization (color scheme, font, font rendering, icon and Plasma theme) to SDDM. + Settings synchronization allows you to transfer the following Plasma settings to SDDM: color scheme, cursor theme, font, font rendering, NumLock preference, Plasma theme, and scaling DPI. false true KUrlRequester QWidget
kurlrequester.h
1
autoLogin toggled(bool) userList setEnabled(bool) 212 37 274 32 autoLogin toggled(bool) label_4 setEnabled(bool) 207 22 363 37 autoLogin toggled(bool) sessionList setEnabled(bool) 186 21 435 25 autoLogin toggled(bool) reloginAfterQuit setEnabled(bool) 222 22 214 59