diff --git a/sddmauthhelper.cpp b/sddmauthhelper.cpp index cc7c096..4e274bf 100644 --- a/sddmauthhelper.cpp +++ b/sddmauthhelper.cpp @@ -1,318 +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 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/CMakeLists.txt b/src/CMakeLists.txt index b145926..fad683c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,63 +1,48 @@ set(SDDM_CONFIG_FILE "${CMAKE_INSTALL_FULL_SYSCONFDIR}/sddm.conf" CACHE PATH "Path of the sddm config file") set(SDDM_CONFIG_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/sddm.conf.d" CACHE PATH "Path of the sddm config directory") set(SDDM_SYSTEM_CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/lib/sddm/sddm.conf.d" CACHE PATH "Path of the system sddm config directory") set(XSESSIONS_DIR "${CMAKE_INSTALL_PREFIX}/share/xsessions" CACHE PATH "Path of the xsessions") set(WAYLAND_SESSIONS_DIR "${CMAKE_INSTALL_PREFIX}/share/wayland-sessions" CACHE PATH "Path of the wayland sessions") configure_file(config.h.in config.h IMMEDIATE @ONLY) # add_subdirectory(configwidgets) include_directories(configwidgets) set(SDDM_KCM_SRCS sddmkcm.cpp themeconfig.cpp themesmodel.cpp thememetadata.cpp themesdelegate.cpp advanceconfig.cpp usersmodel.cpp sessionmodel.cpp - cursortheme/thememodel.cpp - cursortheme/xcursortheme.cpp - cursortheme/cursortheme.cpp - cursortheme/sortproxymodel.cpp - cursortheme/dummytheme.cpp configwidgets/selectimagebutton.cpp ) set(SDDM_KCM_UI ui/themeconfig.ui ui/advanceconfig.ui) ki18n_wrap_ui(SDDM_KCM_SRCS ${SDDM_KCM_UI}) add_library(kcm_sddm MODULE ${SDDM_KCM_SRCS}) target_compile_definitions(kcm_sddm PRIVATE -DPROJECT_VERSION="${PROJECT_VERSION}") target_link_libraries(kcm_sddm Qt5::Widgets Qt5::X11Extras Qt5::Quick Qt5::QuickWidgets KF5::I18n KF5::ConfigWidgets KF5::AuthCore KF5::KIOWidgets KF5::NewStuff - - ${X11_LIBRARIES} - XCB::XCB # For mouse cursor themes ) -if (X11_Xcursor_FOUND) - target_link_libraries(kcm_sddm ${X11_Xcursor_LIB}) -endif (X11_Xcursor_FOUND) -if (X11_Xfixes_FOUND) - target_link_libraries(kcm_sddm ${X11_Xfixes_LIB}) -endif (X11_Xfixes_FOUND) - install(TARGETS kcm_sddm DESTINATION ${CMAKE_INSTALL_PLUGINDIR}) install(FILES qml/main.qml DESTINATION ${CMAKE_INSTALL_DATADIR}/sddm-kcm) diff --git a/src/advanceconfig.cpp b/src/advanceconfig.cpp index facb3cb..cc2446b 100644 --- a/src/advanceconfig.cpp +++ b/src/advanceconfig.cpp @@ -1,237 +1,223 @@ /* 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 "cursortheme/thememodel.h" -#include "cursortheme/sortproxymodel.h" -#include "cursortheme/cursortheme.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->cursorList, SIGNAL(activated(int)), 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() { - //Cursor themes - CursorThemeModel *cursorModel = new CursorThemeModel(this); - proxyCursorModel = new SortProxyModel(this); - proxyCursorModel->setSourceModel(cursorModel); - proxyCursorModel->setFilterCaseSensitivity(Qt::CaseSensitive); - proxyCursorModel->sort(Qt::DisplayRole, Qt::AscendingOrder); - - configUi->cursorList->setModel(proxyCursorModel); - QString currentCursor = mConfig->group("Theme").readEntry("CursorTheme", ""); - QModelIndex cursorIndex = proxyCursorModel->findIndex(currentCursor); - configUi->cursorList->setCurrentIndex(cursorIndex.row() < 0 ? 0 : cursorIndex.row()); - //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; - qDebug() << "idx:" << configUi->cursorList->currentIndex(); - - QModelIndex cursorIndex = configUi->cursorList->model()->index(configUi->cursorList->currentIndex(),0); - if (cursorIndex.isValid()) { - const CursorTheme *cursorTheme = proxyCursorModel->theme(cursorIndex); - if (cursorTheme) - args[QStringLiteral("kde_settings.conf/Theme/CursorTheme")] = cursorTheme->name(); - } - 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 config(QStringLiteral("kcminputrc")); + KConfigGroup configGroup(&config, "Mouse"); + QVariant cursorTheme = configGroup.readEntry("cursorTheme", QString()); + 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("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(); 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/advanceconfig.h b/src/advanceconfig.h index 7446490..f6dd945 100644 --- a/src/advanceconfig.h +++ b/src/advanceconfig.h @@ -1,63 +1,62 @@ /* 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 . */ #ifndef ADVANCECONFIG_H #define ADVANCECONFIG_H #include #include namespace Ui { class AdvanceConfig; } class SortProxyModel; class UsersModel; class SessionModel; class AdvanceConfig : public QWidget { Q_OBJECT public: explicit AdvanceConfig(const KSharedConfigPtr &config, QWidget *parent = nullptr); ~AdvanceConfig(); QVariantMap save(); Q_SIGNALS: void changed(bool changed=true); public Q_SLOTS: void syncSettingsChanged(); void resetSettingsChanged(); private Q_SLOTS: void slotUidRangeChanged(); private: void load(); bool isUidRangeValid(int minUid, int maxUid) const; private: Ui::AdvanceConfig *configUi; KSharedConfigPtr mConfig; - SortProxyModel *proxyCursorModel; UsersModel *userModel; SessionModel *sessionModel; }; #endif // ADVANCECONFIG_H diff --git a/src/cursortheme/cursortheme.cpp b/src/cursortheme/cursortheme.cpp deleted file mode 100644 index f6fcea9..0000000 --- a/src/cursortheme/cursortheme.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright © 2006-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "cursortheme.h" -// #include - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_XFIXES -# include -# include -#endif - -CursorTheme::CursorTheme(const QString &title, const QString &description) -{ - setTitle(title); - setDescription(description); - setSample(QStringLiteral("left_ptr")); - setIsHidden(false); - setIsWritable(false); -} - - -QPixmap CursorTheme::icon() const -{ - if (m_icon.isNull()) - m_icon = createIcon(); - - return m_icon; -} - - -QImage CursorTheme::autoCropImage(const QImage &image) const -{ - // Compute an autocrop rectangle for the image - QRect r(image.rect().bottomRight(), image.rect().topLeft()); - const quint32 *pixels = reinterpret_cast(image.bits()); - - for (int y = 0; y < image.height(); y++) - { - for (int x = 0; x < image.width(); x++) - { - if (*(pixels++)) - { - if (x < r.left()) r.setLeft(x); - if (x > r.right()) r.setRight(x); - if (y < r.top()) r.setTop(y); - if (y > r.bottom()) r.setBottom(y); - } - } - } - - // Normalize the rectangle - return image.copy(r.normalized()); -} - - -QPixmap CursorTheme::loadPixmap(const QString &name, int size) const -{ - QImage image = loadImage(name, size); - if (image.isNull()) - return QPixmap(); - - return QPixmap::fromImage(image); -} - - -static int nominalCursorSize(int iconSize) -{ - for (int i = 512; i > 8; i /= 2) - { - if (i < iconSize) - return i; - - if ((i * .75) < iconSize) - return int(i * .75); - } - - return 8; -} - - -QPixmap CursorTheme::createIcon() const -{ - int iconSize = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize); - int cursorSize = nominalCursorSize(iconSize); - QSize size = QSize(iconSize, iconSize); - - QPixmap pixmap = createIcon(cursorSize); - - if (!pixmap.isNull()) - { - // Scale the pixmap if it's larger than the preferred icon size - if (pixmap.width() > size.width() || pixmap.height() > size.height()) - pixmap = pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - } - - return pixmap; -} - - -QPixmap CursorTheme::createIcon(int size) const -{ - QPixmap pixmap; - QImage image = loadImage(sample(), size); - - if (image.isNull() && sample() != QLatin1String("left_ptr")) - image = loadImage(QStringLiteral("left_ptr"), size); - - if (!image.isNull()) - { - pixmap = QPixmap::fromImage(image); - } - - return pixmap; -} - - -void CursorTheme::setCursorName(qulonglong cursor, const QString &name) const -{ -#ifdef HAVE_XFIXES - - if (haveXfixes()) - { - XFixesSetCursorName(QX11Info::display(), cursor, - QFile::encodeName(name)); - } -#else - Q_UNUSED(name); - Q_UNUSED(cursor); -#endif -} - -bool CursorTheme::haveXfixes() -{ - bool result = false; - -#ifdef HAVE_XFIXES - if (!QX11Info::isPlatformX11()) { - return result; - } - int event_base, error_base; - if (XFixesQueryExtension(QX11Info::display(), &event_base, &error_base)) - { - int major, minor; - XFixesQueryVersion(QX11Info::display(), &major, &minor); - result = (major >= 2); - } -#endif - - return result; -} diff --git a/src/cursortheme/cursortheme.h b/src/cursortheme/cursortheme.h deleted file mode 100644 index adff06d..0000000 --- a/src/cursortheme/cursortheme.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright © 2006-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifndef CURSORTHEME_H -#define CURSORTHEME_H - -#include -#include - -/** - * This is the abstract base class for all cursor themes stored in a - * CursorThemeModel and previewed in a PreviewWidget. - * - * All cursor themes have a title, a description, an icon, and an internal - * name, all of which, except for the internal name, CursorThemeModel - * supplies to item views. - * - * A cursor theme may also have a path to the directory where the theme - * is located in the filesystem. If isWritable() returns true, This directory - * may be deleted in order to remove the theme at the users request. - * - * Subclasses must reimplement loadImage() and loadCursor(), which are - * called by PreviewWidget to load cursors and cursor images. Subclasses may - * optionally reimplement loadPixmap(), which in the default implementation - * calls loadImage(), and converts the returned image to a pixmap. - * Subclasses may also reimplement the protected function createIcon(), - * which creates the icon pixmap that's supplied to item views. The default - * implementation calls loadImage() to load the sample cursor, and creates - * the icon from that. - */ -class CursorTheme -{ - public: - enum ItemDataRole { - // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) - // to define additional roles. - DisplayDetailRole = 0x24A3DAF8 - }; - - CursorTheme() {} - CursorTheme(const QString &title, const QString &description = QString()); - virtual ~CursorTheme() {} - - const QString title() const { return m_title; } - const QString description() const { return m_description; } - const QString sample() const { return m_sample; } - const QString name() const { return m_name; } - const QString path() const { return m_path; } - /** @returns A list of the available sizes in this cursor theme, - @warning This list may be empty if the engine doesn't support - the recognition of the size. */ - const QList availableSizes() const - { return m_availableSizes; } - bool isWritable() const { return m_writable; } - bool isHidden() const { return m_hidden; } - QPixmap icon() const; - - /// Hash value for the internal name - uint hash() const { return m_hash; } - - /// Loads the cursor image @p name, with the nominal size @p size. - /// The image should be autocropped to the smallest possible size. - /// If the theme doesn't have the cursor @p name, it should return a null image. - virtual QImage loadImage(const QString &name, int size = 0) const = 0; - - /// Convenience function. Default implementation calls - /// QPixmap::fromImage(loadImage()); - virtual QPixmap loadPixmap(const QString &name, int size = 0) const; - - /// Loads the cursor @p name, with the nominal size @p size. - /// If the theme doesn't have the cursor @p name, it should return - /// the default cursor from the active theme instead. - virtual qulonglong loadCursor(const QString &name, int size = 0) const = 0; - - /** Creates the icon returned by @ref icon(). Don't use this function - directly but use @ref icon() instead, because @ref icon() caches - the icon. - @returns A pixmap with a cursor (usually left_ptr) that can - be used as icon for this theme. The size is adopted to - standard icon sizes.*/ - virtual QPixmap createIcon() const; - /** @returns A pixmap with a cursor (usually left_ptr) that can - be used as icon for this theme. */ - virtual QPixmap createIcon(int size) const; - - static bool haveXfixes(); - - protected: - void setTitle( const QString &title ) { m_title = title; } - void setDescription( const QString &desc ) { m_description = desc; } - void setSample( const QString &sample ) { m_sample = sample; } - inline void setName( const QString &name ); - void setPath( const QString &path ) { m_path = path; } - void setAvailableSizes( const QList &availableSizes ) - { m_availableSizes = availableSizes; } - void setIcon( const QPixmap &icon ) { m_icon = icon; } - void setIsWritable( bool val ) { m_writable = val; } - void setIsHidden( bool val ) { m_hidden = val; } - - /// Convenience function for cropping an image. - QImage autoCropImage( const QImage &image ) const; - - // Convenience function that uses Xfixes to tag a cursor with a name - void setCursorName(qulonglong cursor, const QString &name) const; - - QString m_title; - QString m_description; - QString m_path; - QList m_availableSizes; - QString m_sample; - mutable QPixmap m_icon; - bool m_writable:1; - bool m_hidden:1; - - private: - QString m_name; - uint m_hash; - - friend class CursorThemeModel; -}; - -void CursorTheme::setName(const QString &name) -{ - m_name = name; - m_hash = qHash(name); -} - -#endif // CURSORTHEME_H - diff --git a/src/cursortheme/dummytheme.cpp b/src/cursortheme/dummytheme.cpp deleted file mode 100644 index 01626da..0000000 --- a/src/cursortheme/dummytheme.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - 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 "dummytheme.h" - -#include -#include - -#include - -DummyTheme::DummyTheme() - : CursorTheme(i18n("Default"), i18n("The default cursor theme in SDDM")) -{ -} - - -DummyTheme::~DummyTheme() -{ -} - - -QImage DummyTheme::loadImage(const QString &name, int) const -{ - Q_UNUSED(name) - - return QImage(); -} - - -qulonglong DummyTheme::loadCursor(const QString &name, int) const -{ - Q_UNUSED(name) - - return 0; -} diff --git a/src/cursortheme/dummytheme.h b/src/cursortheme/dummytheme.h deleted file mode 100644 index 106a8d5..0000000 --- a/src/cursortheme/dummytheme.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - 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 . - */ -#ifndef DUMMYTHEME_H -#define DUMMYTHEME_H - -#include "cursortheme.h" - -class DummyTheme : public CursorTheme -{ - public: - DummyTheme(); - ~DummyTheme() Q_DECL_OVERRIDE; - - QImage loadImage(const QString &name, int size = 0) const Q_DECL_OVERRIDE; - qulonglong loadCursor(const QString &name, int size = 0) const Q_DECL_OVERRIDE; - - protected: - DummyTheme(const QString &title, const QString &description = QString()) - : CursorTheme(title, description) {} - - private: - class Private; -}; - -#endif //DUMMYTHEME_H diff --git a/src/cursortheme/sortproxymodel.cpp b/src/cursortheme/sortproxymodel.cpp deleted file mode 100644 index 52e163f..0000000 --- a/src/cursortheme/sortproxymodel.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2006-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "cursortheme.h" -#include "sortproxymodel.h" - -#include - -int SortProxyModel::compare(const QModelIndex &left, const QModelIndex &right, int role) const -{ - const QAbstractItemModel *model = sourceModel(); - - QString first = model->data(left, role).toString(); - QString second = model->data(right, role).toString(); - - if (filterCaseSensitivity() == Qt::CaseSensitive) - { - first = first.toLower(); - second = second.toLower(); - } - - return QString::localeAwareCompare(first, second); -} - - -bool SortProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - const int result = compare(left, right, Qt::DisplayRole); - - if (result != 0) - return (result < 0); - else - return compare(left, right, CursorTheme::DisplayDetailRole) < 0; -} diff --git a/src/cursortheme/sortproxymodel.h b/src/cursortheme/sortproxymodel.h deleted file mode 100644 index c1fa781..0000000 --- a/src/cursortheme/sortproxymodel.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright © 2006-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifndef SORTPROXYMODEL_H -#define SORTPROXYMODEL_H - -#include "thememodel.h" - -#include - -/** - * SortProxyModel is a sorting proxy model intended to be used in combination - * with the ItemDelegate class. - * - * First it compares the Qt::DisplayRoles, and if they match it compares - * the CursorTheme::DisplayDetailRoles. - * - * The model assumes both display roles are QStrings. - */ -class SortProxyModel : public QSortFilterProxyModel -{ - public: - explicit SortProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {} - ~SortProxyModel() Q_DECL_OVERRIDE {} - inline const CursorTheme *theme(const QModelIndex &index) const; - inline QModelIndex findIndex(const QString &name) const; - inline QModelIndex defaultIndex() const; - inline void removeTheme(const QModelIndex &index); - - private: - int compare(const QModelIndex &left, const QModelIndex &right, int role) const; - - protected: - bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; -}; - - -const CursorTheme *SortProxyModel::theme(const QModelIndex &index) const -{ - CursorThemeModel *model = static_cast(sourceModel()); - return model->theme(mapToSource(index)); -} - -QModelIndex SortProxyModel::findIndex(const QString &name) const -{ - CursorThemeModel *model = static_cast(sourceModel()); - return mapFromSource(model->findIndex(name)); -} - -QModelIndex SortProxyModel::defaultIndex() const -{ - CursorThemeModel *model = static_cast(sourceModel()); - return mapFromSource(model->defaultIndex()); -} - -void SortProxyModel::removeTheme(const QModelIndex &index) -{ - CursorThemeModel *model = static_cast(sourceModel()); - model->removeTheme(mapToSource(index)); -} - -#endif // SORTPROXYMODEL_H diff --git a/src/cursortheme/thememodel.cpp b/src/cursortheme/thememodel.cpp deleted file mode 100644 index becc1bc..0000000 --- a/src/cursortheme/thememodel.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright © 2005-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 as published by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "thememodel.h" -#include "xcursortheme.h" - -#include -#include -#include - -#include -#include -#include - -#include -#include - -// Check for older version -#if !defined(XCURSOR_LIB_MAJOR) && defined(XCURSOR_MAJOR) -# define XCURSOR_LIB_MAJOR XCURSOR_MAJOR -# define XCURSOR_LIB_MINOR XCURSOR_MINOR -#endif - -CursorThemeModel::CursorThemeModel(QObject *parent) - : QAbstractTableModel(parent) -{ - insertThemes(); -} - -CursorThemeModel::~CursorThemeModel() -{ - qDeleteAll(list); - list.clear(); -} - -void CursorThemeModel::refreshList() -{ - beginResetModel(); - qDeleteAll(list); - list.clear(); - endResetModel(); - insertThemes(); -} - -QVariant CursorThemeModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - // Only provide text for the headers - if (role != Qt::DisplayRole) - return QVariant(); - - // Horizontal header labels - if (orientation == Qt::Horizontal) - { - switch (section) - { - case NameColumn: - return i18n("Name"); - - case DescColumn: - return i18n("Description"); - - default: return QVariant(); - } - } - - // Numbered vertical header lables - return QString(section); -} - - -QVariant CursorThemeModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid() || index.row() < 0 || index.row() >= list.count()) - return QVariant(); - - const CursorTheme *theme = list.at(index.row()); - - // Text label - if (role == Qt::DisplayRole) - { - switch (index.column()) - { - case NameColumn: - return theme->title(); - - case DescColumn: - return theme->description(); - - default: return QVariant(); - } - } - - // Description for the first name column - if (role == CursorTheme::DisplayDetailRole && index.column() == NameColumn) - return theme->description(); - - // Icon for the name column - if (role == Qt::DecorationRole && index.column() == NameColumn) - return theme->icon(); - - return QVariant(); -} - - -void CursorThemeModel::sort(int column, Qt::SortOrder order) -{ - Q_UNUSED(column); - Q_UNUSED(order); - - // Sorting of the model isn't implemented, as the KCM currently uses - // a sorting proxy model. -} - - -const CursorTheme *CursorThemeModel::theme(const QModelIndex &index) -{ - if (!index.isValid()) - return nullptr; - - if (index.row() < 0 || index.row() >= list.count()) - return nullptr; - - return list.at(index.row()); -} - - -QModelIndex CursorThemeModel::findIndex(const QString &name) -{ - uint hash = qHash(name); - - for (int i = 0; i < list.count(); i++) - { - const CursorTheme *theme = list.at(i); - if (theme->hash() == hash) - return index(i, 0); - } - - return QModelIndex(); -} - - -QModelIndex CursorThemeModel::defaultIndex() -{ - return findIndex(defaultName); -} - - -const QStringList CursorThemeModel::searchPaths() -{ - if (!baseDirs.isEmpty()) - return baseDirs; - -#if XCURSOR_LIB_MAJOR == 1 && XCURSOR_LIB_MINOR < 1 - // These are the default paths Xcursor will scan for cursor themes - QString path("~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons"); - - // If XCURSOR_PATH is set, use that instead of the default path - char *xcursorPath = std::getenv("XCURSOR_PATH"); - if (xcursorPath) - path = xcursorPath; -#else - // Get the search path from Xcursor - QString path = QString::fromLatin1(XcursorLibraryPath()); -#endif - - // Separate the paths - baseDirs = path.split(QLatin1Char(':'), QString::SkipEmptyParts); - - // Remove duplicates - QMutableStringListIterator i(baseDirs); - while (i.hasNext()) - { - const QString path = i.next(); - QMutableStringListIterator j(i); - while (j.hasNext()) - if (j.next() == path) - j.remove(); - } - - // Expand all occurrences of ~/ to the home dir - baseDirs.replaceInStrings(QRegExp(QLatin1String("^~\\/")), QDir::home().path() + QLatin1Char('/')); - return baseDirs; -} - - -bool CursorThemeModel::hasTheme(const QString &name) const -{ - const uint hash = qHash(name); - - foreach (const CursorTheme *theme, list) - if (theme->hash() == hash) - return true; - - return false; -} - - -bool CursorThemeModel::isCursorTheme(const QString &theme, const int depth) -{ - // Prevent infinite recursion - if (depth > 10) - return false; - - // Search each icon theme directory for 'theme' - foreach (const QString &baseDir, searchPaths()) - { - QDir dir(baseDir); - if (!dir.exists() || !dir.cd(theme)) - continue; - - // If there's a cursors subdir, we'll assume this is a cursor theme - if (dir.exists(QStringLiteral("cursors"))) - return true; - - // If the theme doesn't have an index.theme file, it can't inherit any themes. - if (!dir.exists(QStringLiteral("index.theme"))) - continue; - - // Open the index.theme file, so we can get the list of inherited themes - KConfig config(dir.path() + QStringLiteral("/index.theme"), KConfig::NoGlobals); - KConfigGroup cg(&config, "Icon Theme"); - - // Recurse through the list of inherited themes, to check if one of them - // is a cursor theme. - QStringList inherits = cg.readEntry("Inherits", QStringList()); - foreach (const QString &inherit, inherits) - { - // Avoid possible DoS - if (inherit == theme) - continue; - - if (isCursorTheme(inherit, depth + 1)) - return true; - } - } - - return false; -} - - -bool CursorThemeModel::handleDefault(const QDir &themeDir) -{ - QFileInfo info(themeDir.path()); - - // If "default" is a symlink - if (info.isSymLink()) - { - QFileInfo target(info.symLinkTarget()); - if (target.exists() && (target.isDir() || target.isSymLink())) - defaultName = target.fileName(); - - return true; - } - - // If there's no cursors subdir, or if it's empty - if (!themeDir.exists(QStringLiteral("cursors")) || QDir(themeDir.path() + QStringLiteral("/cursors")) - .entryList(QDir::Files | QDir::NoDotAndDotDot ).isEmpty()) - { - if (themeDir.exists(QStringLiteral("index.theme"))) - { - XCursorTheme theme(themeDir); - if (!theme.inherits().isEmpty()) - defaultName = theme.inherits().at(0); - } - return true; - } - - defaultName = QStringLiteral("default"); - return false; -} - - -void CursorThemeModel::processThemeDir(const QDir &themeDir) -{ - bool haveCursors = themeDir.exists(QStringLiteral("cursors")); - - // Special case handling of "default", since it's usually either a - // symlink to another theme, or an empty theme that inherits another - // theme. - if (defaultName.isNull() && themeDir.dirName() == QLatin1String("default")) - { - if (handleDefault(themeDir)) - return; - } - - // If the directory doesn't have a cursors subdir and lacks an - // index.theme file it can't be a cursor theme. - if (!themeDir.exists(QStringLiteral("index.theme")) && !haveCursors) - return; - - // Create a cursor theme object for the theme dir - XCursorTheme *theme = new XCursorTheme(themeDir); - - // Skip this theme if it's hidden. - if (theme->isHidden()) { - delete theme; - return; - } - - // If there's no cursors subdirectory we'll do a recursive scan - // to check if the theme inherits a theme with one. - if (!haveCursors) - { - bool foundCursorTheme = false; - - foreach (const QString &name, theme->inherits()) - if ((foundCursorTheme = isCursorTheme(name))) - break; - - if (!foundCursorTheme) { - delete theme; - return; - } - } - - // Append the theme to the list - beginInsertRows(QModelIndex(), list.size(), list.size()); - list.append(theme); - endInsertRows(); -} - - -void CursorThemeModel::insertThemes() -{ - // Scan each base dir for Xcursor themes and add them to the list. - foreach (const QString &baseDir, searchPaths()) - { - QDir dir(baseDir); - if (!dir.exists()) - continue; - - // Process each subdir in the directory - foreach (const QString &name, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) - { - // Don't process the theme if a theme with the same name already exists - // in the list. Xcursor will pick the first one it finds in that case, - // and since we use the same search order, the one Xcursor picks should - // be the one already in the list. - if (hasTheme(name) || !dir.cd(name)) - continue; - - processThemeDir(dir); - dir.cdUp(); // Return to the base dir - } - } - - // The theme Xcursor will end up using if no theme is configured - if (defaultName.isNull() || !hasTheme(defaultName)) - defaultName = QStringLiteral("KDE_Classic"); -} - - -bool CursorThemeModel::addTheme(const QDir &dir) -{ - XCursorTheme *theme = new XCursorTheme(dir); - - // Don't add the theme to the list if it's hidden - if (theme->isHidden()) { - delete theme; - return false; - } - - // ### If the theme is hidden, the user will probably find it strange that it - // doesn't appear in the list view. There also won't be a way for the user - // to delete the theme using the KCM. Perhaps a warning about this should - // be issued, and the user be given a chance to undo the installation. - - // If an item with the same name already exists in the list, - // we'll remove it before inserting the new one. - for (int i = 0; i < list.count(); i++) - { - if (list.at(i)->hash() == theme->hash()) { - removeTheme(index(i, 0)); - break; - } - } - - // Append the theme to the list - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - list.append(theme); - endInsertRows(); - - return true; -} - - -void CursorThemeModel::removeTheme(const QModelIndex &index) -{ - if (!index.isValid()) - return; - - beginRemoveRows(QModelIndex(), index.row(), index.row()); - delete list.takeAt(index.row()); - endRemoveRows(); -} - diff --git a/src/cursortheme/thememodel.h b/src/cursortheme/thememodel.h deleted file mode 100644 index 7654bf8..0000000 --- a/src/cursortheme/thememodel.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright © 2005-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifndef THEMEMODEL_H -#define THEMEMODEL_H - -#include -#include - -class QDir; -class CursorTheme; - -// The two TableView/TreeView columns provided by the model -enum Columns { NameColumn = 0, DescColumn }; - - -/** - * The CursorThemeModel class provides a model for all locally installed - * Xcursor themes, and the KDE/Qt legacy bitmap theme. - * - * This class automatically scans the locations in the file system from - * which Xcursor loads cursors, and creates an internal list of all - * available cursor themes. - * - * The model provides this theme list to item views in the form of a list - * of rows with two columns; the first column has the theme's descriptive - * name and its sample cursor as its icon, and the second column contains - * the theme's description. - * - * Additional Xcursor themes can be added to a model after it's been - * created, by calling addTheme(), which takes QDir as a parameter, - * with the themes location. The intention is for this function to be - * called when a new Xcursor theme has been installed, after the model - * was instantiated. - * - * The KDE legacy theme is a read-only entry, with the descriptive name - * "KDE Classic", and the internal name "#kde_legacy#". - * - * Calling defaultIndex() will return the index of the theme Xcursor - * will use if the user hasn't explicitly configured a cursor theme. - */ -class CursorThemeModel : public QAbstractTableModel -{ - Q_OBJECT - - public: - explicit CursorThemeModel(QObject *parent = nullptr); - ~CursorThemeModel() Q_DECL_OVERRIDE; - inline int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - inline int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; - void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) Q_DECL_OVERRIDE; - - /// Returns the CursorTheme at @p index. - const CursorTheme *theme(const QModelIndex &index); - - /// Returns the index for the CursorTheme with the internal name @p name, - /// or an invalid index if no matching theme can be found. - QModelIndex findIndex(const QString &name); - - /// Returns the index for the default theme. - QModelIndex defaultIndex(); - - /// Adds the theme in @p dir, and returns @a true if successful or @a false otherwise. - bool addTheme(const QDir &dir); - void removeTheme(const QModelIndex &index); - - /// Returns the list of base dirs Xcursor looks for themes in. - const QStringList searchPaths(); - - /// Refresh the list of themes by checking what's on disk. - void refreshList(); - - private: - bool handleDefault(const QDir &dir); - void processThemeDir(const QDir &dir); - void insertThemes(); - bool hasTheme(const QString &theme) const; - bool isCursorTheme(const QString &theme, const int depth = 0); - - private: - QList list; - QStringList baseDirs; - QString defaultName; -}; - -int CursorThemeModel::rowCount(const QModelIndex &) const -{ - return list.count(); -} - -int CursorThemeModel::columnCount(const QModelIndex &) const -{ - return 2; -} - -#endif // THEMEMODEL_H diff --git a/src/cursortheme/xcursortheme.cpp b/src/cursortheme/xcursortheme.cpp deleted file mode 100644 index 195c576..0000000 --- a/src/cursortheme/xcursortheme.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright © 2006-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published - * by the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "xcursortheme.h" - -// Static variable holding alternative names for some cursors -QHash XCursorTheme::alternatives; - -XCursorTheme::XCursorTheme(const QDir &themeDir) - : CursorTheme(themeDir.dirName()) -{ - // Directory information - setName(themeDir.dirName()); - setPath(themeDir.path()); - setIsWritable(QFileInfo(themeDir.path()).isWritable()); // ### perhaps this shouldn't be cached - - if (themeDir.exists(QStringLiteral("index.theme"))) - parseIndexFile(); - - QString cursorFile = path() + QStringLiteral("/cursors/left_ptr"); - QList sizeList; - XcursorImages *images = XcursorFilenameLoadAllImages(qPrintable(cursorFile)); - if (images) - { - for (int i = 0; i < images->nimage; ++i) - { - if (!sizeList.contains(images->images[i]->size)) - sizeList.append(images->images[i]->size); - }; - XcursorImagesDestroy(images); - std::sort(sizeList.begin(), sizeList.end()); - m_availableSizes = sizeList; - }; - if (!sizeList.isEmpty()) - { - QString sizeListString = QString::number(sizeList.takeFirst()); - while (!sizeList.isEmpty()) - { - sizeListString.append(QStringLiteral(", ")); - sizeListString.append(QString::number(sizeList.takeFirst())); - }; - QString tempString = i18nc( - "@info The argument is the list of available sizes (in pixel). Example: " - "'Available sizes: 24' or 'Available sizes: 24, 36, 48'", - "(Available sizes: %1)", - sizeListString); - if (m_description.isEmpty()) - m_description = tempString; - else - m_description = m_description + QLatin1Char(' ') + tempString; - }; -} - - -void XCursorTheme::parseIndexFile() -{ - KConfig config(path() + QStringLiteral("/index.theme"), KConfig::NoGlobals); - KConfigGroup cg(&config, "Icon Theme"); - - m_title = cg.readEntry("Name", m_title); - m_description = cg.readEntry("Comment", m_description); - m_sample = cg.readEntry("Example", m_sample); - m_hidden = cg.readEntry("Hidden", false); - m_inherits = cg.readEntry("Inherits", QStringList()); -} - - -QString XCursorTheme::findAlternative(const QString &name) const -{ - if (alternatives.isEmpty()) - { - alternatives.reserve(18); - - // Qt uses non-standard names for some core cursors. - // If Xcursor fails to load the cursor, Qt creates it with the correct name using the - // core protcol instead (which in turn calls Xcursor). We emulate that process here. - // Note that there's a core cursor called cross, but it's not the one Qt expects. - alternatives.insert(QStringLiteral("cross"), QStringLiteral("crosshair")); - alternatives.insert(QStringLiteral("up_arrow"), QStringLiteral("center_ptr")); - alternatives.insert(QStringLiteral("wait"), QStringLiteral("watch")); - alternatives.insert(QStringLiteral("ibeam"), QStringLiteral("xterm")); - alternatives.insert(QStringLiteral("size_all"), QStringLiteral("fleur")); - alternatives.insert(QStringLiteral("pointing_hand"), QStringLiteral("hand2")); - - // Precomputed MD5 hashes for the hardcoded bitmap cursors in Qt and KDE. - // Note that the MD5 hash for left_ptr_watch is for the KDE version of that cursor. - alternatives.insert(QStringLiteral("size_ver"), QStringLiteral("00008160000006810000408080010102")); - alternatives.insert(QStringLiteral("size_hor"), QStringLiteral("028006030e0e7ebffc7f7070c0600140")); - alternatives.insert(QStringLiteral("size_bdiag"), QStringLiteral("fcf1c3c7cd4491d801f1e1c78f100000")); - alternatives.insert(QStringLiteral("size_fdiag"), QStringLiteral("c7088f0f3e6c8088236ef8e1e3e70000")); - alternatives.insert(QStringLiteral("whats_this"), QStringLiteral("d9ce0ab605698f320427677b458ad60b")); - alternatives.insert(QStringLiteral("split_h"), QStringLiteral("14fef782d02440884392942c11205230")); - alternatives.insert(QStringLiteral("split_v"), QStringLiteral("2870a09082c103050810ffdffffe0204")); - alternatives.insert(QStringLiteral("forbidden"), QStringLiteral("03b6e0fcb3499374a867c041f52298f0")); - alternatives.insert(QStringLiteral("left_ptr_watch"), QStringLiteral("3ecb610c1bf2410f44200f48c40d3599")); - alternatives.insert(QStringLiteral("hand2"), QStringLiteral("e29285e634086352946a0e7090d73106")); - alternatives.insert(QStringLiteral("openhand"), QStringLiteral("9141b49c8149039304290b508d208c40")); - alternatives.insert(QStringLiteral("closedhand"), QStringLiteral("05e88622050804100c20044008402080")); - } - - return alternatives.value(name, QString()); -} - - -XcursorImage *XCursorTheme::xcLoadImage(const QString &image, int size) const -{ - const QByteArray cursorName = QFile::encodeName(image); - const QByteArray themeName = QFile::encodeName(name()); - - return XcursorLibraryLoadImage(cursorName.constData(), themeName.constData(), size); -} - - -XcursorImages *XCursorTheme::xcLoadImages(const QString &image, int size) const -{ - const QByteArray cursorName = QFile::encodeName(image); - const QByteArray themeName = QFile::encodeName(name()); - - return XcursorLibraryLoadImages(cursorName.constData(), themeName.constData(), size); -} - - -int XCursorTheme::autodetectCursorSize() const -{ - /* This code is basically borrowed from display.c of the XCursor library - We can't use "int XcursorGetDefaultSize(Display *dpy)" because if - previously the cursor size was set to a custom value, it would return - this custom value. */ - int size = 0; - int dpi = 0; - Display *dpy = QX11Info::display(); - // Fallback on wayland - if (!dpy) - return 24; - // The string "v" is owned and will be destroyed by Xlib - char *v = XGetDefault(dpy, "Xft", "dpi"); - if (v) - dpi = atoi(v); - if (dpi) - size = dpi * 16 / 72; - if (size == 0) - { - int dim; - if (DisplayHeight(dpy, DefaultScreen(dpy)) < - DisplayWidth(dpy, DefaultScreen(dpy))) - { - dim = DisplayHeight(dpy, DefaultScreen(dpy)); - } else { - dim = DisplayWidth(dpy, DefaultScreen(dpy)); - }; - size = dim / 48; - } - return size; -} - -qulonglong XCursorTheme::loadCursor(const QString &name, int size) const -{ - if (size <= 0) - size = autodetectCursorSize(); - - // Load the cursor images - XcursorImages *images = xcLoadImages(name, size); - - if (!images) - images = xcLoadImages(findAlternative(name), size); - - if (!images) - return None; - - // Create the cursor - Cursor handle = XcursorImagesLoadCursor(QX11Info::display(), images); - XcursorImagesDestroy(images); - - setCursorName(handle, name); - return handle; -} - - -QImage XCursorTheme::loadImage(const QString &name, int size) const -{ - if (size <= 0) - size = autodetectCursorSize(); - - // Load the image - XcursorImage *xcimage = xcLoadImage(name, size); - - if (!xcimage) - xcimage = xcLoadImage(findAlternative(name), size); - - if (!xcimage) { - return QImage(); - } - - // Convert the XcursorImage to a QImage, and auto-crop it - QImage image((uchar *)xcimage->pixels, xcimage->width, xcimage->height, - QImage::Format_ARGB32_Premultiplied ); - - image = autoCropImage(image); - XcursorImageDestroy(xcimage); - - return image; -} - diff --git a/src/cursortheme/xcursortheme.h b/src/cursortheme/xcursortheme.h deleted file mode 100644 index 63f7000..0000000 --- a/src/cursortheme/xcursortheme.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright © 2006-2007 Fredrik Höglund - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License version 2 or at your option version 3 as published by - * the Free Software Foundation. - * - * 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifndef XCURSORTHEME_H -#define XCURSORTHEME_H - -#include "cursortheme.h" - -#include - -class QDir; - -struct _XcursorImage; -struct _XcursorImages; - -typedef _XcursorImage XcursorImage; -typedef _XcursorImages XcursorImages; - -/** - * The XCursorTheme class is a CursorTheme implementation for Xcursor themes. - */ -class XCursorTheme : public CursorTheme -{ - public: - /** - * Initializes itself from the @p dir information, and parses the - * index.theme file if the dir has one. - */ - XCursorTheme(const QDir &dir); - ~XCursorTheme() Q_DECL_OVERRIDE {} - - const QStringList inherits() const { return m_inherits; } - QImage loadImage(const QString &name, int size = 0) const Q_DECL_OVERRIDE; - qulonglong loadCursor(const QString &name, int size = 0) const Q_DECL_OVERRIDE; - - protected: - XCursorTheme(const QString &title, const QString &desc) - : CursorTheme(title, desc) {} - void setInherits(const QStringList &val) { m_inherits = val; } - - private: - XcursorImage *xcLoadImage(const QString &name, int size) const; - XcursorImages *xcLoadImages(const QString &name, int size) const; - void parseIndexFile(); - QString findAlternative(const QString &name) const; - /** Returns the size that the XCursor library would use if no - cursor size is given. This depends mainly on Xft.dpi. */ - int autodetectCursorSize() const; - - QStringList m_inherits; - static QHash alternatives; -}; - -#endif // XCURSORTHEME_H - diff --git a/src/ui/advanceconfig.ui b/src/ui/advanceconfig.ui index 4535c72..c4b0da1 100644 --- a/src/ui/advanceconfig.ui +++ b/src/ui/advanceconfig.ui @@ -1,351 +1,328 @@ AdvanceConfig 0 0 547 - 435 + 391 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 - - - Cursor theme: - - - - - - - - - - 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 - - - - Settings synchronization: - - - - + Qt::Vertical 8 8 - + + + + Settings synchronization: + + + + Sync Reset - + 0 0 320 70 Settings synchronization allows you to transfer your theme customization (color scheme, font, font rendering, icon and Plasma theme) to SDDM. 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