diff --git a/kcms/icons/main.cpp b/kcms/icons/main.cpp index d07dcd758..9811d4652 100644 --- a/kcms/icons/main.cpp +++ b/kcms/icons/main.cpp @@ -1,602 +1,602 @@ /* * main.cpp * * Copyright (c) 1999 Matthias Hoelzer-Kluepfel * Copyright (c) 2000 Antonio Larrosa * Copyright (C) 2000 Geert Jansen * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell * Copyright (C) 2018 Kai Uwe Broulik * * Requires the Qt widget libraries, available at no cost at * http://www.troll.no/ * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "main.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for unlink #include "iconsmodel.h" #include "config.h" // for CMAKE_INSTALL_FULL_LIBEXECDIR static const QVector s_defaultIconSizes = { 32, 22, 22, 16, 48, 32 }; // we try to use KIconTheme::defaultThemeName() but that could be "hicolor" which isn't a "real" theme static const QString s_defaultThemeName = QStringLiteral("breeze"); K_PLUGIN_FACTORY_WITH_JSON(IconsFactory, "kcm_icons.json", registerPlugin();) IconModule::IconModule(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) , m_model(new IconsModel(this)) , m_iconGroups{ QStringLiteral("Desktop"), QStringLiteral("Toolbar"), QStringLiteral("MainToolbar"), QStringLiteral("Small"), QStringLiteral("Panel"), QStringLiteral("Dialog") } { qmlRegisterType(); // to be able to access its enums qmlRegisterUncreatableType("org.kde.private.kcms.icons", 1, 0, "KIconLoader", QString()); KAboutData* about = new KAboutData(QStringLiteral("kcm5_icons"), i18n("Icons"), QStringLiteral("1.0"), i18n("Icons Control Panel Module"), KAboutLicense::GPL, i18n("(c) 2000-2003 Geert Jansen")); about->addAuthor(i18n("Geert Jansen"), QString(), QStringLiteral("jansen@kde.org")); about->addAuthor(i18n("Antonio Larrosa Jimenez"), QString(), QStringLiteral("larrosa@kde.org")); about->addCredit(i18n("Torsten Rahn"), QString(), QStringLiteral("torsten@kde.org")); about->addAuthor(i18n("Jonathan Riddell"), QString(), QStringLiteral("jr@jriddell.org")); about->addAuthor(i18n("Kai Uwe Broulik"), QString(), QStringLiteral("kde@privat.broulik.de>")); setAboutData(about); setButtons(Apply | Default); connect(m_model, &IconsModel::selectedThemeChanged, this, [this] { m_selectedThemeDirty = true; setNeedsSave(true); }); connect(m_model, &IconsModel::pendingDeletionsChanged, this, [this] { setNeedsSave(true); }); // When user has a lot of themes installed, preview pixmaps might get evicted prematurely QPixmapCache::setCacheLimit(50 * 1024); // 50 MiB } IconModule::~IconModule() { } IconsModel *IconModule::iconsModel() const { return m_model; } QStringList IconModule::iconGroups() const { return m_iconGroups; } bool IconModule::downloadingFile() const { return m_tempCopyJob; } int IconModule::iconSize(int group) const { return m_iconSizes[group]; } void IconModule::setIconSize(int group, int size) { if (iconSize(group) == size) { return; } m_iconSizes[group] = size; setNeedsSave(true); m_iconSizesDirty = true; emit iconSizesChanged(); } QList IconModule::availableIconSizes(int group) const { return KIconLoader::global()->theme()->querySizes(static_cast(group)); } void IconModule::load() { m_model->load(); loadIconSizes(); m_model->setSelectedTheme(KIconTheme::current()); setNeedsSave(false); m_selectedThemeDirty = false; m_iconSizesDirty = false; } void IconModule::save() { if (m_selectedThemeDirty) { QProcess::startDetached(CMAKE_INSTALL_FULL_LIBEXECDIR "/plasma-changeicons", {m_model->selectedTheme()}); } if (m_iconSizesDirty || m_revertIconEffects) { auto cfg = KSharedConfig::openConfig(); for (int i = 0; i < m_iconGroups.count(); ++i) { const QString &group = m_iconGroups.at(i); KConfigGroup cg(cfg, group + QLatin1String("Icons")); cg.writeEntry("Size", m_iconSizes.at(i), KConfig::Normal | KConfig::Global); if (m_revertIconEffects) { cg.revertToDefault("Animated"); const QStringList states = { QStringLiteral("Default"), QStringLiteral("Active"), QStringLiteral("Disabled") }; const QStringList keys = { QStringLiteral("Effect"), QStringLiteral("Value"), QStringLiteral("Color"), QStringLiteral("Color2"), QStringLiteral("SemiTransparent") }; for (const QString &state : states) { for (const QString &key : keys) { cg.revertToDefault(state + key); } } } } cfg->sync(); } if (m_selectedThemeDirty || m_iconSizesDirty || m_revertIconEffects) { exportToKDE4(); } processPendingDeletions(); KIconLoader::global()->newIconLoader(); setNeedsSave(false); m_selectedThemeDirty = false; m_iconSizesDirty = false; m_revertIconEffects = false; } void IconModule::processPendingDeletions() { const QStringList pendingDeletions = m_model->pendingDeletions(); for (const QString &themeName : pendingDeletions) { Q_ASSERT(themeName != m_model->selectedTheme()); KIconTheme theme(themeName); auto *job = KIO::del(QUrl::fromLocalFile(theme.dir()), KIO::HideProgressInfo); // needs to block for it to work on "OK" where the dialog (kcmshell) closes job->exec(); } m_model->removeItemsPendingDeletion(); } void IconModule::defaults() { if (m_iconSizes != s_defaultIconSizes) { m_iconSizes = s_defaultIconSizes; emit iconSizesChanged(); } auto setThemeIfAvailable = [this](const QString &themeName) { const auto results = m_model->match(m_model->index(0, 0), ThemeNameRole, themeName); if (results.isEmpty()) { return false; } m_model->setSelectedTheme(themeName); return true; }; if (!setThemeIfAvailable(KIconTheme::defaultThemeName())) { setThemeIfAvailable(QStringLiteral("breeze")); } m_revertIconEffects = true; setNeedsSave(true); } void IconModule::loadIconSizes() { auto cfg = KSharedConfig::openConfig(); QVector iconSizes(6, 0); // why doesn't KIconLoader::LastGroup - 1 work here?! int i = KIconLoader::FirstGroup; for (const QString &group : qAsConst(m_iconGroups)) { int size = KIconLoader::global()->theme()->defaultSize(static_cast(i)); KConfigGroup iconGroup(cfg, group + QLatin1String("Icons")); size = iconGroup.readEntry("Size", size); iconSizes[i] = size; ++i; } if (m_iconSizes != iconSizes) { m_iconSizes = iconSizes; emit iconSizesChanged(); } } void IconModule::getNewStuff(QQuickItem *ctx) { if (!m_newStuffDialog) { m_newStuffDialog = new KNS3::DownloadDialog(QStringLiteral("icons.knsrc")); m_newStuffDialog->setWindowTitle(i18n("Download New Icon Themes")); m_newStuffDialog->setWindowModality(Qt::WindowModal); m_newStuffDialog->winId(); // so it creates the windowHandle(); // TODO would be lovely to scroll to and select the newly installed scheme, if any connect(m_newStuffDialog.data(), &KNS3::DownloadDialog::accepted, this, [this] { if (m_newStuffDialog->changedEntries().isEmpty()) { return; } // reload the display icontheme items KIconLoader::global()->newIconLoader(); m_model->load(); QPixmapCache::clear(); }); } if (ctx && ctx->window()) { m_newStuffDialog->windowHandle()->setTransientParent(ctx->window()); } m_newStuffDialog->show(); } void IconModule::installThemeFromFile(const QUrl &url) { if (url.isLocalFile()) { installThemeFile(url.toLocalFile()); return; } if (m_tempCopyJob) { return; } m_tempInstallFile.reset(new QTemporaryFile()); if (!m_tempInstallFile->open()) { emit showErrorMessage(i18n("Unable to create a temporary file.")); m_tempInstallFile.reset(); return; } m_tempCopyJob = KIO::file_copy(url,QUrl::fromLocalFile(m_tempInstallFile->fileName()), -1, KIO::Overwrite); m_tempCopyJob->uiDelegate()->setAutoErrorHandlingEnabled(true); emit downloadingFileChanged(); connect(m_tempCopyJob, &KIO::FileCopyJob::result, this, [this, url](KJob *job) { if (job->error() != KJob::NoError) { emit showErrorMessage(i18n("Unable to download the icon theme archive: %1", job->errorText())); return; } installThemeFile(m_tempInstallFile->fileName()); m_tempInstallFile.reset(); }); connect(m_tempCopyJob, &QObject::destroyed, this, &IconModule::downloadingFileChanged); } void IconModule::installThemeFile(const QString &path) { const QStringList themesNames = findThemeDirs(path); if (themesNames.isEmpty()) { emit showErrorMessage(i18n("The file is not a valid icon theme archive.")); return; } if (!installThemes(themesNames, path)) { emit showErrorMessage(i18n("A problem occurred during the installation process; however, most of the themes in the archive have been installed")); return; } emit showSuccessMessage(i18n("Theme installed successfully.")); KIconLoader::global()->newIconLoader(); m_model->load(); } void IconModule::exportToKDE4() { //TODO: killing the kde4 icon cache: possible? (kde4migration doesn't let access the cache folder) Kdelibs4Migration migration; QString configFilePath = migration.saveLocation("config"); if (configFilePath.isEmpty()) { return; } configFilePath += QLatin1String("kdeglobals"); KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig(QStringLiteral("kdeglobals")); KConfig kde4config(configFilePath, KConfig::SimpleConfig); KConfigGroup kde4IconGroup(&kde4config, "Icons"); kde4IconGroup.writeEntry("Theme", m_model->selectedTheme()); //Synchronize icon effects for (const QString &group : qAsConst(m_iconGroups)) { const QString groupName = group + QLatin1String("Icons"); KConfigGroup cg(kglobalcfg, groupName); KConfigGroup kde4Cg(&kde4config, groupName); // HACK copyTo only copies keys, it doesn't replace the entire group // which means if we removed the effects in our config it won't remove // them from the kde4 config, hence revert all of them prior to copying const QStringList keys = cg.keyList() + kde4Cg.keyList(); for (const QString &key : keys) { kde4Cg.revertToDefault(key); } // now copy over the new values cg.copyTo(&kde4Cg); } kde4config.sync(); QProcess *cachePathProcess = new QProcess(this); connect(cachePathProcess, QOverload::of(&QProcess::finished), this, [cachePathProcess](int exitCode, QProcess::ExitStatus status) { if (status == QProcess::NormalExit && exitCode == 0) { QString path = cachePathProcess->readAllStandardOutput().trimmed(); path.append(QLatin1String("icon-cache.kcache")); QFile::remove(path); } //message kde4 apps that icon theme is changed for (int i = 0; i < KIconLoader::LastGroup; i++) { KIconLoader::emitChange(KIconLoader::Group(i)); QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange")); message.setArguments({ 4, // KGlobalSettings::IconChanged KIconLoader::Group(i) }); QDBusConnection::sessionBus().send(message); } cachePathProcess->deleteLater(); }); cachePathProcess->start(QStringLiteral("kde4-config --path cache")); } QStringList IconModule::findThemeDirs(const QString &archiveName) { QStringList foundThemes; KTar archive(archiveName); archive.open(QIODevice::ReadOnly); const KArchiveDirectory *themeDir = archive.directory(); KArchiveEntry *possibleDir = nullptr; KArchiveDirectory *subDir = nullptr; // iterate all the dirs looking for an index.theme or index.desktop file const QStringList entries = themeDir->entries(); for (const QString &entry : entries) { possibleDir = const_cast(themeDir->entry(entry)); if (!possibleDir->isDirectory()) { continue; } subDir = dynamic_cast(possibleDir); if (!subDir) { continue; } if (subDir->entry(QStringLiteral("index.theme")) || subDir->entry(QStringLiteral("index.desktop"))) { foundThemes.append(subDir->name()); } } archive.close(); return foundThemes; } bool IconModule::installThemes(const QStringList &themes, const QString &archiveName) { bool everythingOk = true; const QString localThemesDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/icons/./")); emit showProgress(i18n("Installing icon themes...")); KTar archive(archiveName); archive.open(QIODevice::ReadOnly); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); const KArchiveDirectory *rootDir = archive.directory(); KArchiveDirectory *currentTheme = nullptr; for (const QString &theme : themes) { emit showProgress(i18n("Installing %1 theme...", theme)); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); currentTheme = dynamic_cast(const_cast(rootDir->entry(theme))); if (!currentTheme) { // we tell back that something went wrong, but try to install as much // as possible everythingOk = false; continue; } currentTheme->copyTo(localThemesDir + theme); } archive.close(); emit hideProgress(); return everythingOk; } QVariantList IconModule::previewIcons(const QString &themeName, int size, qreal dpr, int limit) { static QVector s_previewIcons{ {QStringLiteral("system-run"), QStringLiteral("exec")}, {QStringLiteral("folder")}, {QStringLiteral("document"), QStringLiteral("text-x-generic")}, {QStringLiteral("user-trash"), QStringLiteral("user-trash-empty")}, {QStringLiteral("system-help"), QStringLiteral("help-about"), QStringLiteral("help-contents")}, {QStringLiteral("preferences-system"), QStringLiteral("systemsettings"), QStringLiteral("configure")}, {QStringLiteral("text-html")}, {QStringLiteral("image-x-generic"), QStringLiteral("image-png"), QStringLiteral("image-jpeg")}, {QStringLiteral("video-x-generic"), QStringLiteral("video-x-theora+ogg"), QStringLiteral("video-mp4")}, {QStringLiteral("x-office-document")}, {QStringLiteral("x-office-spreadsheet")}, {QStringLiteral("x-office-presentation"), QStringLiteral("application-presentation")}, {QStringLiteral("user-home")}, {QStringLiteral("user-desktop"), QStringLiteral("desktop")}, {QStringLiteral("folder-image"), QStringLiteral("folder-images"), QStringLiteral("folder-pictures"), QStringLiteral("folder-picture")}, {QStringLiteral("folder-documents")}, {QStringLiteral("folder-download"), QStringLiteral("folder-downloads")}, {QStringLiteral("folder-video"), QStringLiteral("folder-videos")} }; // created on-demand as it is quite expensive to do and we don't want to do it every loop iteration either QScopedPointer theme; QVariantList pixmaps; for (const QStringList &iconNames : s_previewIcons) { const QString cacheKey = themeName + QLatin1Char('@') + QString::number(size) + QLatin1Char('@') + QString::number(dpr,'f',1) + QLatin1Char('@') + iconNames.join(QLatin1Char(',')); QPixmap pix; - if (!QPixmapCache::find(cacheKey, pix)) { + if (!QPixmapCache::find(cacheKey, &pix)) { if (!theme) { theme.reset(new KIconTheme(themeName)); } pix = getBestIcon(*theme.data(), iconNames, size, dpr); // Inserting a pixmap even if null so we know whether we searched for it already QPixmapCache::insert(cacheKey, pix); } if (pix.isNull()) { continue; } pixmaps.append(pix); if (limit > -1 && pixmaps.count() >= limit) { break; } } return pixmaps; } QPixmap IconModule::getBestIcon(KIconTheme &theme, const QStringList &iconNames, int size, qreal dpr) { QSvgRenderer renderer; const int iconSize = size * dpr; // not using initializer list as we want to unwrap inherits() const QStringList themes = QStringList() << theme.internalName() << theme.inherits(); for (const QString &themeName : themes) { KIconTheme theme(themeName); for (const QString &iconName : iconNames) { QString path = theme.iconPath(QStringLiteral("%1.png").arg(iconName), iconSize, KIconLoader::MatchBest); if (!path.isEmpty()) { QPixmap pixmap(path); pixmap.setDevicePixelRatio(dpr); return pixmap; } //could not find the .png, try loading the .svg or .svgz path = theme.iconPath(QStringLiteral("%1.svg").arg(iconName), iconSize, KIconLoader::MatchBest); if (path.isEmpty()) { path = theme.iconPath(QStringLiteral("%1.svgz").arg(iconName), iconSize, KIconLoader::MatchBest); } if (path.isEmpty()) { continue; } if (!renderer.load(path)) { continue; } QPixmap pixmap(iconSize, iconSize); pixmap.setDevicePixelRatio(dpr); pixmap.fill(QColor(Qt::transparent)); QPainter p(&pixmap); p.setViewport(0, 0, size, size); renderer.render(&p); return pixmap; } } return QPixmap(); } #include "main.moc" diff --git a/kcms/keyboard/xkb_helper.cpp b/kcms/keyboard/xkb_helper.cpp index 4a2948048..e907cc997 100644 --- a/kcms/keyboard/xkb_helper.cpp +++ b/kcms/keyboard/xkb_helper.cpp @@ -1,184 +1,185 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "xkb_helper.h" #include "debug.h" #include #include #include #include #include #include #include #include +#include #include #include "keyboard_config.h" static const char SETXKBMAP_EXEC[] = "setxkbmap"; static const char XMODMAP_EXEC[] = "xmodmap"; static bool setxkbmapNotFound = false; static QString setxkbmapExe; static bool xmodmapNotFound = false; static QString xmodmapExe; static const QString COMMAND_OPTIONS_SEPARATOR(QStringLiteral(",")); static QString getSetxkbmapExe() { if( setxkbmapNotFound ) return QLatin1String(""); if( setxkbmapExe.isEmpty() ) { setxkbmapExe = QStandardPaths::findExecutable(SETXKBMAP_EXEC); if( setxkbmapExe.isEmpty() ) { setxkbmapNotFound = true; qCCritical(KCM_KEYBOARD) << "Can't find" << SETXKBMAP_EXEC << "- keyboard layouts won't be configured"; return QLatin1String(""); } } return setxkbmapExe; } static void executeXmodmap(const QString& configFileName) { if( xmodmapNotFound ) return; if( QFile(configFileName).exists() ) { if( xmodmapExe.isEmpty() ) { xmodmapExe = QStandardPaths::findExecutable(XMODMAP_EXEC); if( xmodmapExe.isEmpty() ) { xmodmapNotFound = true; qCCritical(KCM_KEYBOARD) << "Can't find" << XMODMAP_EXEC << "- xmodmap files won't be run"; return; } } KProcess xmodmapProcess; xmodmapProcess << xmodmapExe; xmodmapProcess << configFileName; qCDebug(KCM_KEYBOARD) << "Executing" << xmodmapProcess.program().join(QLatin1Char(' ')); if( xmodmapProcess.execute() != 0 ) { qCCritical(KCM_KEYBOARD) << "Failed to execute " << xmodmapProcess.program(); } } } static void restoreXmodmap() { // TODO: is just home .Xmodmap enough or should system be involved too? // QString configFileName = QDir("/etc/X11/xinit").filePath(".Xmodmap"); // executeXmodmap(configFileName); QString configFileName = QDir::home().filePath(QStringLiteral(".Xmodmap")); executeXmodmap(configFileName); } //TODO: make private bool XkbHelper::runConfigLayoutCommand(const QStringList& setxkbmapCommandArguments) { - QTime timer; + QElapsedTimer timer; timer.start(); KProcess setxkbmapProcess; setxkbmapProcess << getSetxkbmapExe() << setxkbmapCommandArguments; int res = setxkbmapProcess.execute(); if( res == 0 ) { // restore Xmodmap mapping reset by setxkbmap qCDebug(KCM_KEYBOARD) << "Executed successfully in " << timer.elapsed() << "ms" << setxkbmapProcess.program().join(QLatin1Char(' ')); restoreXmodmap(); qCDebug(KCM_KEYBOARD) << "\t and with xmodmap" << timer.elapsed() << "ms"; return true; } else { qCCritical(KCM_KEYBOARD) << "Failed to run" << setxkbmapProcess.program().join(QLatin1Char(' ')) << "return code:" << res; } return false; } bool XkbHelper::initializeKeyboardLayouts(const QList& layoutUnits) { QStringList layouts; QStringList variants; foreach (const LayoutUnit& layoutUnit, layoutUnits) { layouts.append(layoutUnit.layout()); variants.append(layoutUnit.variant()); } QStringList setxkbmapCommandArguments; setxkbmapCommandArguments.append(QStringLiteral("-layout")); setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); if( ! variants.join(QLatin1String("")).isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-variant")); setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); } return runConfigLayoutCommand(setxkbmapCommandArguments); } bool XkbHelper::initializeKeyboardLayouts(KeyboardConfig& config) { QStringList setxkbmapCommandArguments; if( ! config.keyboardModel.isEmpty() ) { XkbConfig xkbConfig; X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::MODEL_ONLY); if( xkbConfig.keyboardModel != config.keyboardModel ) { setxkbmapCommandArguments.append(QStringLiteral("-model")); setxkbmapCommandArguments.append(config.keyboardModel); } } if( config.configureLayouts ) { QStringList layouts; QStringList variants; QList defaultLayouts = config.getDefaultLayouts(); foreach (const LayoutUnit& layoutUnit, defaultLayouts) { layouts.append(layoutUnit.layout()); variants.append(layoutUnit.variant()); } setxkbmapCommandArguments.append(QStringLiteral("-layout")); setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); if( ! variants.join(QLatin1String("")).isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-variant")); setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); } } if( config.resetOldXkbOptions ) { setxkbmapCommandArguments.append(QStringLiteral("-option")); } if( ! config.xkbOptions.isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-option")); setxkbmapCommandArguments.append(config.xkbOptions.join(COMMAND_OPTIONS_SEPARATOR)); } if( ! setxkbmapCommandArguments.isEmpty() ) { return runConfigLayoutCommand(setxkbmapCommandArguments); if( config.configureLayouts ) { X11Helper::setDefaultLayout(); } } return false; } diff --git a/kcms/kfontinst/kcmfontinst/FontList.cpp b/kcms/kfontinst/kcmfontinst/FontList.cpp index 3f5d14dc2..588d7100f 100644 --- a/kcms/kfontinst/kcmfontinst/FontList.cpp +++ b/kcms/kfontinst/kcmfontinst/FontList.cpp @@ -1,2060 +1,2060 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "FontList.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FcEngine.h" #include "Fc.h" #include "KfiConstants.h" #include "GroupList.h" #include "FontInstInterface.h" #include "XmlStrings.h" #include "Family.h" #include "Style.h" #include "File.h" namespace KFI { const QStringList CFontList::fontMimeTypes(QStringList() << "font/ttf" << "font/otf" << "application/x-font-ttf" << "application/x-font-otf" << "application/x-font-type1" << "application/x-font-pcf" << "application/x-font-bdf" << "application/vnd.kde.fontspackage"); static const int constMaxSlowed = 250; static void decompose(const QString &name, QString &family, QString &style) { int commaPos=name.lastIndexOf(','); family=-1==commaPos ? name : name.left(commaPos); style=-1==commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos+2); } static void addFont(CFontItem *font, CJobRunner::ItemList &urls, QStringList &fontNames, QSet *fonts, QSet &usedFonts, bool getEnabled, bool getDisabled) { if(!usedFonts.contains(font) && ( (getEnabled && font->isEnabled()) || (getDisabled && !font->isEnabled()) ) ) { urls.append(CJobRunner::Item(font->url(), font->name(), !font->isEnabled())); fontNames.append(font->name()); usedFonts.insert(font); if(fonts) fonts->insert(Misc::TFont(font->family(), font->styleInfo())); } } static QString replaceEnvVar(const QString &text) { QString mod(text); int endPos(text.indexOf('/')); if(endPos==-1) endPos=text.length()-1; else endPos--; if(endPos>0) { QString envVar(text.mid(1, endPos)); const char *val=getenv(envVar.toLatin1().constData()); if(val) mod=Misc::fileSyntax(QFile::decodeName(val)+mod.mid(endPos+1)); } return mod; } // // Convert from list such as: // // Arial // Arial, Bold // Courier // Times // Times, Italic // // To: // // Arial (Regular, Bold) // Coutier // Times (Regular, Italic) QStringList CFontList::compact(const QStringList &fonts) { QString lastFamily, entry; QStringList::ConstIterator it(fonts.begin()), end(fonts.end()); QStringList compacted; QSet usedStyles; for(; it!=end; ++it) { QString family, style; decompose(*it, family, style); if(family!=lastFamily) { usedStyles.clear(); if(entry.length()) { entry+=')'; compacted.append(entry); } entry=QString(family+" ("); lastFamily=family; } if(!usedStyles.contains(style)) { usedStyles.clear(); if(entry.length() && '('!=entry[entry.length()-1]) entry+=", "; entry+=style; usedStyles.insert(style); } } if(entry.length()) { entry+=')'; compacted.append(entry); } return compacted; } QString capitaliseFoundry(const QString &foundry) { QString f(foundry.toLower()); if(f==QLatin1String("ibm")) return QLatin1String("IBM"); else if(f==QLatin1String("urw")) return QLatin1String("URW"); else if(f==QLatin1String("itc")) return QLatin1String("ITC"); else if(f==QLatin1String("nec")) return QLatin1String("NEC"); else if(f==QLatin1String("b&h")) return QLatin1String("B&H"); else if(f==QLatin1String("dec")) return QLatin1String("DEC"); else { QChar *ch(f.data()); int len(f.length()); bool isSpace(true); while(len--) { if (isSpace) *ch=ch->toUpper(); isSpace=ch->isSpace(); ++ch; } } return f; } inline bool isSysFolder(const QString §) { return i18n(KFI_KIO_FONTS_SYS)==sect || KFI_KIO_FONTS_SYS==sect; } CFontItem::CFontItem(CFontModelItem *p, const Style &s, bool sys) : CFontModelItem(p), itsStyleName(FC::createStyleName(s.value())), itsStyle(s) { refresh(); if(!Misc::root()) setIsSystem(sys); } void CFontItem::refresh() { FileCont::ConstIterator it(itsStyle.files().begin()), end(itsStyle.files().end()); itsEnabled=false; for(; it!=end; ++it) if(!Misc::isHidden(Misc::getFile((*it).path()))) { itsEnabled=true; break; } } CFamilyItem::CFamilyItem(CFontList &p, const Family &f, bool sys) : CFontModelItem(nullptr), itsStatus(ENABLED), itsRealStatus(ENABLED), itsRegularFont(nullptr), itsParent(p) { itsName=f.name(); addFonts(f.styles(), sys); //updateStatus(); } CFamilyItem::~CFamilyItem() { qDeleteAll(itsFonts); itsFonts.clear(); } bool CFamilyItem::addFonts(const StyleCont &styles, bool sys) { StyleCont::ConstIterator it(styles.begin()), end(styles.end()); bool modified=false; for(; it!=end; ++it) { CFontItem *font=findFont((*it).value(), sys); if(!font) { // New font style! itsFonts.append(new CFontItem(this, *it, sys)); modified=true; } else { int before=(*it).files().size(); font->addFiles((*it).files()); if((*it).files().size()!=before) { modified=true; font->refresh(); } } } return modified; } CFontItem * CFamilyItem::findFont(quint32 style, bool sys) { CFontItemCont::ConstIterator fIt(itsFonts.begin()), fEnd(itsFonts.end()); for(; fIt!=fEnd; ++fIt) if((*(*fIt)).styleInfo()==style && (*(*fIt)).isSystem()==sys) return (*fIt); return nullptr; } void CFamilyItem::getFoundries(QSet &foundries) const { CFontItemCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end()); for(; it!=end; ++it) { FileCont::ConstIterator fIt((*it)->files().begin()), fEnd((*it)->files().end()); for(; fIt!=fEnd; ++fIt) if(!(*fIt).foundry().isEmpty()) foundries.insert(capitaliseFoundry((*fIt).foundry())); } } bool CFamilyItem::usable(const CFontItem *font, bool root) { return ( root || (font->isSystem() && itsParent.allowSys()) || (!font->isSystem() && itsParent.allowUser())); } void CFamilyItem::addFont(CFontItem *font, bool update) { itsFonts.append(font); if(update) { updateStatus(); updateRegularFont(font); } } void CFamilyItem::removeFont(CFontItem *font, bool update) { itsFonts.removeAll(font); if(update) updateStatus(); if(itsRegularFont==font) { itsRegularFont=nullptr; if(update) updateRegularFont(nullptr); } delete font; } void CFamilyItem::refresh() { updateStatus(); itsRegularFont=nullptr; updateRegularFont(nullptr); } bool CFamilyItem::updateStatus() { bool root(Misc::root()); EStatus oldStatus(itsStatus); CFontItemCont::ConstIterator it(itsFonts.begin()), end(itsFonts.end()); int en(0), dis(0), allEn(0), allDis(0); bool oldSys(isSystem()), sys(false); itsFontCount=0; for(; it!=end; ++it) if(usable(*it, root)) { if((*it)->isEnabled()) en++; else dis++; if(!sys) sys=(*it)->isSystem(); itsFontCount++; } else if((*it)->isEnabled()) allEn++; else allDis++; allEn+=en; allDis+=dis; itsStatus=en && dis ? PARTIAL : en ? ENABLED : DISABLED; itsRealStatus=allEn && allDis ? PARTIAL : allEn ? ENABLED : DISABLED; if(!root) setIsSystem(sys); return itsStatus!=oldStatus || isSystem()!=oldSys; } bool CFamilyItem::updateRegularFont(CFontItem *font) { static const quint32 constRegular=FC::createStyleVal(FC_WEIGHT_REGULAR, KFI_FC_WIDTH_NORMAL, FC_SLANT_ROMAN); CFontItem *oldFont(itsRegularFont); bool root(Misc::root()); if(font && usable(font, root)) { if(itsRegularFont) { int regDiff=abs((long)(itsRegularFont->styleInfo()-constRegular)), fontDiff=abs((long)(font->styleInfo()-constRegular)); if(fontDiffstyleInfo()-constRegular)); if(diff)), SLOT(fontList(int,QList))); } CFontList::~CFontList() { qDeleteAll(itsFamilies); itsFamilies.clear(); itsFamilyHash.clear(); } void CFontList::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to) { Q_UNUSED(from); Q_UNUSED(to); if(name==QLatin1String(OrgKdeFontinstInterface::staticInterfaceName())) load(); } void CFontList::fontList(int pid, const QList &families) { // printf("**** fontList:%d/%d %d\n", pid, getpid(), families.count()); if(pid==getpid()) { QList::ConstIterator it(families.begin()), end(families.end()); int count(families.size()); for(int i=0; it!=end; ++it, ++i) { fontsAdded(*it); emit listingPercent(i*100/count); } emit listingPercent(100); } } void CFontList::unsetSlowUpdates() { setSlowUpdates(false); } void CFontList::load() { for(int t=0; tlist(FontInst::SYS_MASK|FontInst::USR_MASK, getpid()); } void CFontList::setSlowUpdates(bool slow) { if(itsSlowUpdates!=slow) { if(!slow) for(int i=0; i families; QDataStream ds(&encodedData, QIODevice::WriteOnly); for(; it!=end; ++it) if((*it).isValid()) { if((static_cast((*it).internalPointer()))->isFont()) { CFontItem *font=static_cast((*it).internalPointer()); families.insert(font->family()); } else { CFamilyItem *fam=static_cast((*it).internalPointer()); families.insert(fam->name()); } } ds << families; mimeData->setData(KFI_FONT_DRAG_MIME, encodedData); return mimeData; } QStringList CFontList::mimeTypes() const { QStringList types; types << "text/uri-list"; return types; } QVariant CFontList::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) switch(role) { case Qt::DisplayRole: switch(section) { case COL_FONT: return i18n("Font"); case COL_STATUS: return i18n("Status"); default: break; } break; // case Qt::DecorationRole: // if(COL_STATUS==section) // return QIcon::fromTheme("fontstatus"); // break; case Qt::TextAlignmentRole: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case Qt::ToolTipRole: if(COL_STATUS==section) return i18n("This column shows the status of the font family, and of the " "individual font styles."); break; case Qt::WhatsThisRole: return whatsThis(); default: break; } return QVariant(); } QModelIndex CFontList::index(int row, int column, const QModelIndex &parent) const { if(parent.isValid()) // Then font... { CFamilyItem *fam=static_cast(parent.internalPointer()); if(rowfonts().count()) return createIndex(row, column, fam->fonts().at(row)); } else // Family.... if(row(index.internalPointer()); if(mi->isFamily()) return QModelIndex(); else { CFontItem *font=static_cast(index.internalPointer()); return createIndex(itsFamilies.indexOf(((CFamilyItem *)font->parent())), 0, font->parent()); } } int CFontList::rowCount(const QModelIndex &parent) const { if(parent.isValid()) { CFontModelItem *mi=static_cast(parent.internalPointer()); if(mi->isFont()) return 0; CFamilyItem *fam=static_cast(parent.internalPointer()); return fam->fonts().count(); } else return itsFamilies.count(); } void CFontList::refresh(bool allowSys, bool allowUser) { itsAllowSys=allowSys; itsAllowUser=allowUser; CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) (*it)->refresh(); } void CFontList::getFamilyStats(QSet &enabled, QSet &disabled, QSet &partial) { CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) { switch((*it)->realStatus()) { case CFamilyItem::ENABLED: enabled.insert((*it)->name()); break; case CFamilyItem::PARTIAL: partial.insert((*it)->name()); break; case CFamilyItem::DISABLED: disabled.insert((*it)->name()); break; } } } void CFontList::getFoundries(QSet &foundries) const { CFamilyItemCont::ConstIterator it(itsFamilies.begin()), end(itsFamilies.end()); for(; it!=end; ++it) (*it)->getFoundries(foundries); } QString CFontList::whatsThis() const { return i18n("

This list shows your installed fonts. The fonts are grouped by family, and the" " number in square brackets represents the number of styles in which the family is" " available. e.g.

" "
    " "
  • Times [4]" "
    • Regular
    • " "
    • Bold
    • " "
    • Bold Italic
    • " "
    • Italic
    • " "
    " "
  • " "
"); } void CFontList::fontsAdded(const KFI::Families &families) { // printf("**** FONT ADDED:%d\n", families.items.count()); if(itsSlowUpdates) storeSlowedMessage(families, MSG_ADD); else addFonts(families.items, families.isSystem && !Misc::root()); } void CFontList::fontsRemoved(const KFI::Families &families) { // printf("**** FONT REMOVED:%d\n", families.items.count()); if(itsSlowUpdates) storeSlowedMessage(families, MSG_DEL); else removeFonts(families.items, families.isSystem && !Misc::root()); } void CFontList::storeSlowedMessage(const Families &families, EMsgType type) { int folder=families.isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER; bool playOld=false; for(int i=0; iconstMaxSlowed) playOld=true; if(playOld) actionSlowedUpdates(families.isSystem); FamilyCont::ConstIterator family(families.items.begin()), fend(families.items.end()); for(; family!=fend; ++family) { FamilyCont::ConstIterator f=itsSlowedMsgs[type][folder].find(*family); if(f!=itsSlowedMsgs[type][folder].end()) { StyleCont::ConstIterator style((*family).styles().begin()), send((*family).styles().end()); for(; style!=send; ++style) { StyleCont::ConstIterator st=(*f).styles().find(*style); if(st==(*f).styles().end()) (*f).add(*style); else (*st).addFiles((*style).files()); } } else itsSlowedMsgs[type][folder].insert(*family); } } void CFontList::actionSlowedUpdates(bool sys) { int folder=sys ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER; for(int i=0; i modifiedFamilies; for(; family!=end; ++family) { if((*family).styles().count()>0) { CFamilyItem *famItem=findFamily((*family).name()); if(famItem) { int rowFrom=famItem->fonts().count(); if(famItem->addFonts((*family).styles(), sys)) { int rowTo=famItem->fonts().count(); if(rowTo!=rowFrom) { beginInsertRows(createIndex(famItem->rowNumber(), 0, famItem), rowFrom, rowTo); endInsertRows(); } modifiedFamilies.insert(famItem); } } else { famItem=new CFamilyItem(*this, *family, sys); itsFamilies.append(famItem); itsFamilyHash[famItem->name()]=famItem; modifiedFamilies.insert(famItem); } } } int famRowTo=itsFamilies.count(); if(famRowTo!=famRowFrom) { beginInsertRows(QModelIndex(), famRowFrom, famRowTo); endInsertRows(); } if(!modifiedFamilies.isEmpty()) { QSet::Iterator it(modifiedFamilies.begin()), end(modifiedFamilies.end()); for(; it!=end; ++it) (*it)->refresh(); } // if(emitLayout) // emit layoutChanged(); } void CFontList::removeFonts(const FamilyCont &families, bool sys) { // if(!itsSlowUpdates) // emit layoutAboutToBeChanged(); FamilyCont::ConstIterator family(families.begin()), end(families.end()); QSet modifiedFamilies; for(; family!=end; ++family) { if((*family).styles().count()>0) { CFamilyItem *famItem=findFamily((*family).name()); if(famItem) { StyleCont::ConstIterator it((*family).styles().begin()), end((*family).styles().end()); for(; it!=end; ++it) { CFontItem *fontItem=famItem->findFont((*it).value(), sys); if(fontItem) { int before=fontItem->files().count(); fontItem->removeFiles((*it).files()); if(fontItem->files().count()!=before) { if(fontItem->files().isEmpty()) { int row=-1; if(1!=famItem->fonts().count()) { row=fontItem->rowNumber(); beginRemoveRows(createIndex(famItem->rowNumber(), 0, famItem), row, row); } famItem->removeFont(fontItem, false); if(-1!=row) endRemoveRows(); } else fontItem->refresh(); } } } if(famItem->fonts().isEmpty()) { int row=famItem->rowNumber(); beginRemoveRows(QModelIndex(), row, row); itsFamilyHash.remove(famItem->name()); itsFamilies.removeAt(row); endRemoveRows(); } else modifiedFamilies.insert(famItem); } } } if(!modifiedFamilies.isEmpty()) { QSet::Iterator it(modifiedFamilies.begin()), end(modifiedFamilies.end()); for(; it!=end; ++it) (*it)->refresh(); } // if(!itsSlowUpdates) // emit layoutChanged(); } CFamilyItem * CFontList::findFamily(const QString &familyName) { CFamilyItemHash::Iterator it=itsFamilyHash.find(familyName); return it==itsFamilyHash.end() ? 0L : *it; } inline bool matchString(const QString &str, const QString &pattern) { return pattern.isEmpty() || -1!=str.indexOf(pattern, 0, Qt::CaseInsensitive); } CFontListSortFilterProxy::CFontListSortFilterProxy(QObject *parent, QAbstractItemModel *model) : QSortFilterProxyModel(parent), itsGroup(nullptr), itsFilterCriteria(CFontFilter::CRIT_FAMILY), itsFilterWs(0), itsFcQuery(nullptr) { setSourceModel(model); setSortCaseSensitivity(Qt::CaseInsensitive); setFilterKeyColumn(0); setDynamicSortFilter(false); itsTimer=new QTimer(this); connect(itsTimer, SIGNAL(timeout()), SLOT(timeout())); connect(model, SIGNAL(layoutChanged()), SLOT(invalidate())); itsTimer->setSingleShot(true); } QVariant CFontListSortFilterProxy::data(const QModelIndex &idx, int role) const { if (!idx.isValid()) return QVariant(); static const int constMaxFiles=20; QModelIndex index(mapToSource(idx)); CFontModelItem *mi=static_cast(index.internalPointer()); if(!mi) return QVariant(); switch(role) { case Qt::ToolTipRole: if(CFontFilter::CRIT_FILENAME==itsFilterCriteria || CFontFilter::CRIT_LOCATION==itsFilterCriteria || CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); FileCont allFiles; QString tip(""+fam->name()+""); bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria); tip+="

"; for(; it!=end; ++it) allFiles+=(*it)->files(); //qSort(allFiles); FileCont::ConstIterator fit(allFiles.begin()), fend(allFiles.end()); for(int i=0; fit!=fend && ifile()) tip+=""; else tip+=""; if(allFiles.count()>constMaxFiles) tip+=""; tip+="
"+Misc::contractHome((*fit).path())+"
"+Misc::contractHome((*fit).path())+"
"+i18n("...plus %1 more", allFiles.count()-constMaxFiles)+"

"; return tip; } else { CFontItem *font=static_cast(index.internalPointer()); QString tip(""+font->name()+""); const FileCont &files(font->files()); bool markMatch(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria); tip+="

"; //qSort(files); FileCont::ConstIterator fit(files.begin()), fend(files.end()); for(int i=0; fit!=fend && ifile()) tip+=""; else tip+=""; if(files.count()>constMaxFiles) tip+=""; tip+="
"+Misc::contractHome((*fit).path())+"
"+Misc::contractHome((*fit).path() )+"
"+i18n("...plus %1 more", files.count()-constMaxFiles)+"

"; return tip; } } break; case Qt::FontRole: if(COL_FONT==index.column() && mi->isSystem()) { QFont font; font.setItalic(true); return font; } break; case Qt::ForegroundRole: if(COL_FONT==index.column() && ( (mi->isFont() && !(static_cast(index.internalPointer()))->isEnabled()) || (mi->isFamily() && CFamilyItem::DISABLED==(static_cast(index.internalPointer()))->status())) ) return KColorScheme(QPalette::Active).foreground(KColorScheme::NegativeText).color(); break; case Qt::DisplayRole: if(COL_FONT==index.column()) { if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); return i18n("%1 [%2]", fam->name(), fam->fontCount()); } else return (static_cast(index.internalPointer()))->style(); } break; case Qt::DecorationRole: if(mi->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); switch(index.column()) { case COL_STATUS: switch(fam->status()) { case CFamilyItem::PARTIAL: return QIcon::fromTheme("dialog-ok"); case CFamilyItem::ENABLED: return QIcon::fromTheme("dialog-ok"); case CFamilyItem::DISABLED: return QIcon::fromTheme("dialog-cancel"); } break; default: break; } } else if(COL_STATUS==index.column()) return QIcon::fromTheme( (static_cast(index.internalPointer()))->isEnabled() ? "dialog-ok" : "dialog-cancel"); break; case Qt::SizeHintRole: if(mi->isFamily()) { const int s = KIconLoader::global()->currentSize(KIconLoader::Small); return QSize(s, s + 4); } default: break; } return QVariant(); } bool CFontListSortFilterProxy::acceptFont(CFontItem *fnt, bool checkFontText) const { if(itsGroup && (CGroupListItem::ALL!=itsGroup->type() || (!filterText().isEmpty() && checkFontText))) { bool fontMatch(!checkFontText); if(!fontMatch) switch(itsFilterCriteria) { case CFontFilter::CRIT_FONTCONFIG: fontMatch=itsFcQuery ? fnt->name()==itsFcQuery->font() // || fnt->files().contains(itsFcQuery->file()) : false; break; case CFontFilter::CRIT_STYLE: fontMatch=matchString(fnt->style(), itsFilterText); break; case CFontFilter::CRIT_FOUNDRY: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); for(; it!=end && !fontMatch; ++it) fontMatch=0==(*it).foundry().compare(itsFilterText, Qt::CaseInsensitive); break; } case CFontFilter::CRIT_FILENAME: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); for(; it!=end && !fontMatch; ++it) { QString file(Misc::getFile((*it).path())); int pos(Misc::isHidden(file) ? 1 : 0); if(pos==file.indexOf(itsFilterText, pos, Qt::CaseInsensitive)) fontMatch=true; } break; } case CFontFilter::CRIT_LOCATION: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); for(; it!=end && !fontMatch; ++it) if(0==Misc::getDir((*it).path()).indexOf(itsFilterText, 0, Qt::CaseInsensitive)) fontMatch=true; break; } case CFontFilter::CRIT_FILETYPE: { FileCont::ConstIterator it(fnt->files().begin()), end(fnt->files().end()); QStringList::ConstIterator mimeEnd(itsFilterTypes.constEnd()); for(; it!=end && !fontMatch; ++it) { QStringList::ConstIterator mime(itsFilterTypes.constBegin()); for(; mime!=mimeEnd; ++mime) if(Misc::checkExt((*it).path(), *mime)) fontMatch=true; } break; } case CFontFilter::CRIT_WS: fontMatch=fnt->writingSystems()&itsFilterWs; break; default: break; } return fontMatch && itsGroup->hasFont(fnt); } return true; } bool CFontListSortFilterProxy::acceptFamily(CFamilyItem *fam) const { CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); bool familyMatch(CFontFilter::CRIT_FAMILY==itsFilterCriteria && matchString(fam->name(), itsFilterText)); for(; it!=end; ++it) if(acceptFont(*it, !familyMatch)) return true; return false; } bool CFontListSortFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index(sourceModel()->index(sourceRow, 0, sourceParent)); if(index.isValid()) { CFontModelItem *mi=static_cast(index.internalPointer()); if(mi->isFont()) { CFontItem *font=static_cast(index.internalPointer()); return acceptFont(font, !(CFontFilter::CRIT_FAMILY==itsFilterCriteria && matchString(font->family(), itsFilterText))); } else return acceptFamily(static_cast(index.internalPointer())); } return false; } bool CFontListSortFilterProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { if(left.isValid() && right.isValid()) { CFontModelItem *lmi=static_cast(left.internalPointer()), *rmi=static_cast(right.internalPointer()); if(lmi->isFont()isFont()) return true; if(lmi->isFont()) { CFontItem *lfi=static_cast(left.internalPointer()), *rfi=static_cast(right.internalPointer()); if(COL_STATUS==filterKeyColumn()) { if(lfi->isEnabled()isEnabled() || (lfi->isEnabled()==rfi->isEnabled() && lfi->styleInfo()styleInfo())) return true; } else if(lfi->styleInfo()styleInfo()) return true; } else { CFamilyItem *lfi=static_cast(left.internalPointer()), *rfi=static_cast(right.internalPointer()); if(COL_STATUS==filterKeyColumn()) { if(lfi->status()status() || (lfi->status()==rfi->status() && QString::localeAwareCompare(lfi->name(), rfi->name())<0)) return true; } else if(QString::localeAwareCompare(lfi->name(), rfi->name())<0) return true; } } return false; } void CFontListSortFilterProxy::setFilterGroup(CGroupListItem *grp) { if(grp!=itsGroup) { // bool wasNull=!itsGroup; itsGroup=grp; // if(!(wasNull && itsGroup && CGroupListItem::ALL==itsGroup->type())) - clear(); + invalidate(); } } void CFontListSortFilterProxy::setFilterText(const QString &text) { if(text!=itsFilterText) { // // If we are filtering on file location, then expand ~ to /home/user, etc. if (CFontFilter::CRIT_LOCATION==itsFilterCriteria && !text.isEmpty() && ('~'==text[0] || '$'==text[0])) if('~'==text[0]) itsFilterText=1==text.length() ? QDir::homePath() : QString(text).replace(0, 1, QDir::homePath()); else itsFilterText=replaceEnvVar(text); else itsFilterText=text; if(itsFilterText.isEmpty()) { itsTimer->stop(); timeout(); } else itsTimer->start(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria ? 750 : 400); } } void CFontListSortFilterProxy::setFilterCriteria(CFontFilter::ECriteria crit, qulonglong ws, const QStringList &ft) { if(crit!=itsFilterCriteria || ws!=itsFilterWs || ft!=itsFilterTypes) { itsFilterWs=ws; itsFilterCriteria=crit; itsFilterTypes=ft; if(CFontFilter::CRIT_LOCATION==itsFilterCriteria) setFilterText(itsFilterText); itsTimer->stop(); timeout(); } } void CFontListSortFilterProxy::timeout() { if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { int commaPos=itsFilterText.indexOf(','); QString query(itsFilterText); if(-1!=commaPos) { QString style(query.mid(commaPos+1)); query.truncate(commaPos); query=query.trimmed(); query+=":style="; style=style.trimmed(); query+=style; } else query=query.trimmed(); if(!itsFcQuery) { itsFcQuery=new CFcQuery(this); connect(itsFcQuery, SIGNAL(finished()), SLOT(fcResults())); } itsFcQuery->run(query); } else { - clear(); + invalidate(); emit refresh(); } } void CFontListSortFilterProxy::fcResults() { if(CFontFilter::CRIT_FONTCONFIG==itsFilterCriteria) { - clear(); + invalidate(); emit refresh(); } } CFontListView::CFontListView(QWidget *parent, CFontList *model) : QTreeView(parent), itsProxy(new CFontListSortFilterProxy(this, model)), itsModel(model), itsAllowDrops(false) { setModel(itsProxy); itsModel=model; header()->setStretchLastSection(false); resizeColumnToContents(COL_STATUS); - header()->setResizeMode(COL_STATUS, QHeaderView::Fixed); - header()->setResizeMode(COL_FONT, QHeaderView::Stretch); + header()->setSectionResizeMode(COL_STATUS, QHeaderView::Fixed); + header()->setSectionResizeMode(COL_FONT, QHeaderView::Stretch); setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionBehavior(QAbstractItemView::SelectRows); setSortingEnabled(true); sortByColumn(COL_FONT, Qt::AscendingOrder); setAllColumnsShowFocus(true); setAlternatingRowColors(true); setAcceptDrops(true); setDropIndicatorShown(false); setDragEnabled(true); setDragDropMode(QAbstractItemView::DragDrop); - header()->setClickable(true); + header()->setSectionsClickable(true); header()->setSortIndicatorShown(true); connect(this, SIGNAL(collapsed(QModelIndex)), SLOT(itemCollapsed(QModelIndex))); connect(header(), SIGNAL(sectionClicked(int)), SLOT(setSortColumn(int))); connect(itsProxy, SIGNAL(refresh()), SIGNAL(refresh())); connect(itsModel, SIGNAL(listingPercent(int)), SLOT(listingPercent(int))); setWhatsThis(model->whatsThis()); header()->setWhatsThis(whatsThis()); itsMenu=new QMenu(this); itsDeleteAct=itsMenu->addAction(QIcon::fromTheme("edit-delete"), i18n("Delete"), this, SIGNAL(del())); itsMenu->addSeparator(); itsEnableAct=itsMenu->addAction(QIcon::fromTheme("font-enable"), i18n("Enable"), this, SIGNAL(enable())); itsDisableAct=itsMenu->addAction(QIcon::fromTheme("font-disable"), i18n("Disable"), this, SIGNAL(disable())); if(!Misc::app(KFI_VIEWER).isEmpty()) itsMenu->addSeparator(); itsPrintAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("document-print"), i18n("Print..."), this, SIGNAL(print())); itsViewAct=Misc::app(KFI_VIEWER).isEmpty() ? nullptr : itsMenu->addAction(QIcon::fromTheme("kfontview"), i18n("Open in Font Viewer"), this, SLOT(view())); itsMenu->addSeparator(); itsMenu->addAction(QIcon::fromTheme("view-refresh"), i18n("Reload"), model, SLOT(load())); } void CFontListView::getFonts(CJobRunner::ItemList &urls, QStringList &fontNames, QSet *fonts, bool selected, bool getEnabled, bool getDisabled) { QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes()); QSet usedFonts; QModelIndex index; foreach(index, selectedItems) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); addFont(font, urls, fontNames, fonts, usedFonts, getEnabled, getDisabled); } else { CFamilyItem *fam=static_cast(realIndex.internalPointer()); for(int ch=0; chfontCount(); ++ch) { QModelIndex child(itsProxy->mapToSource(index.child(ch, 0))); if(child.isValid() && (static_cast(child.internalPointer()))->isFont()) { CFontItem *font=static_cast(child.internalPointer()); addFont(font, urls, fontNames, fonts, usedFonts, getEnabled, getDisabled); } } } } } fontNames=CFontList::compact(fontNames); } QSet CFontListView::getFiles() { QModelIndexList items(allIndexes()); QModelIndex index; QSet files; foreach(index, items) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); FileCont::ConstIterator it(font->files().begin()), end(font->files().end()); for(; it!=end; ++it) { QStringList assoc; files.insert((*it).path()); Misc::getAssociatedFiles((*it).path(), assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for(; ait!=aend; ++ait) files.insert(*ait); } } } return files; } void CFontListView::getPrintableFonts(QSet &items, bool selected) { QModelIndexList selectedItems(selected ? selectedIndexes() : allIndexes()); QModelIndex index; foreach(index, selectedItems) { CFontItem *font=nullptr; if(index.isValid() && 0==index.column()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) font=static_cast(realIndex.internalPointer()); else { CFamilyItem *fam=static_cast(realIndex.internalPointer()); font=fam->regularFont(); } } } if(font && !font->isBitmap() && font->isEnabled()) items.insert(Misc::TFont(font->family(), font->styleInfo())); } } void CFontListView::setFilterGroup(CGroupListItem *grp) { CGroupListItem *oldGrp(itsProxy->filterGroup()); itsProxy->setFilterGroup(grp); itsAllowDrops=grp && !grp->isCustom(); if(!Misc::root()) { bool refreshStats(false); if(!grp || !oldGrp) refreshStats=true; else { // Check to see whether we have changed from listing all fonts, // listing just system or listing personal fonts. CGroupListItem::EType aType(CGroupListItem::CUSTOM==grp->type() || CGroupListItem::ALL==grp->type() || CGroupListItem::UNCLASSIFIED==grp->type() ? CGroupListItem::CUSTOM : grp->type()), bType(CGroupListItem::CUSTOM==oldGrp->type() || CGroupListItem::ALL==oldGrp->type() || CGroupListItem::UNCLASSIFIED==oldGrp->type() ? CGroupListItem::CUSTOM : oldGrp->type()); refreshStats=aType!=bType; } if(refreshStats) itsModel->refresh(!grp || !grp->isPersonal(), !grp || !grp->isSystem()); } // when switching groups, for some reason it is not always sorted. setSortingEnabled(true); } void CFontListView::listingPercent(int percent) { // when the font list is first loaded, for some reason it is not always sorted. // re-enabling sorting here seems to fix the issue - BUG 221610 if(100==percent) setSortingEnabled(true); } void CFontListView::refreshFilter() { itsProxy->clear(); } void CFontListView::filterText(const QString &text) { itsProxy->setFilterText(text); } void CFontListView::filterCriteria(int crit, qulonglong ws, const QStringList &ft) { itsProxy->setFilterCriteria((CFontFilter::ECriteria)crit, ws, ft); } void CFontListView::stats(int &enabled, int &disabled, int &partial) { enabled=disabled=partial=0; for(int i=0; irowCount(); ++i) { QModelIndex idx(itsProxy->index(i, 0, QModelIndex())); if(!idx.isValid()) break; QModelIndex sourceIdx(itsProxy->mapToSource(idx)); if(!sourceIdx.isValid()) break; if((static_cast(sourceIdx.internalPointer()))->isFamily()) switch((static_cast(sourceIdx.internalPointer()))->status()) { case CFamilyItem::ENABLED: enabled++; break; case CFamilyItem::DISABLED: disabled++; break; case CFamilyItem::PARTIAL: partial++; break; } } } void CFontListView::selectedStatus(bool &enabled, bool &disabled) { QModelIndexList selected(selectedIndexes()); QModelIndex index; enabled=disabled=false; foreach(index, selected) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFamily()) { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: enabled=true; break; case CFamilyItem::DISABLED: disabled=true; break; case CFamilyItem::PARTIAL: enabled=true; disabled=true; break; } } else { if((static_cast(realIndex.internalPointer()))->isEnabled()) enabled=true; else disabled=true; } } if(enabled && disabled) break; } } QModelIndexList CFontListView::allFonts() { QModelIndexList rv; int rowCount(itsProxy->rowCount()); for(int i=0; iindex(i, 0, QModelIndex())); int childRowCount(itsProxy->rowCount(idx)); for(int j=0; jindex(j, 0, idx)); if(child.isValid()) rv.append(itsProxy->mapToSource(child)); } } return rv; } void CFontListView::selectFirstFont() { if(0==selectedIndexes().count()) for(int i=0; iindex(0, i, QModelIndex())); if(idx.isValid()) selectionModel()->select(idx, QItemSelectionModel::Select); } } void CFontListView::setSortColumn(int col) { if(col!=itsProxy->filterKeyColumn()) { itsProxy->setFilterKeyColumn(col); - itsProxy->clear(); + itsProxy->invalidate(); } } void CFontListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QAbstractItemView::selectionChanged(selected, deselected); if(itsModel->slowUpdates()) return; emit itemsSelected(getSelectedItems()); } QModelIndexList CFontListView::getSelectedItems() { // // Go through current selection, and for any 'font' items that are selected, // ensure 'family' item is not... QModelIndexList selectedItems(selectedIndexes()), deselectList; QModelIndex index; QSet selectedFamilies; bool en(false), dis(false); foreach(index, selectedItems) if(index.isValid()) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font=static_cast(realIndex.internalPointer()); if(font->isEnabled()) en=true; else dis=true; if(!selectedFamilies.contains(font->parent())) { selectedFamilies.insert(font->parent()); for(int i=0; imapFromSource( itsModel->createIndex(font->parent()->rowNumber(), i, font->parent()))); } } else { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: en=true; break; case CFamilyItem::DISABLED: dis=true; break; case CFamilyItem::PARTIAL: en=dis=true; break; } } } } if(deselectList.count()) foreach(index, deselectList) selectionModel()->select(index, QItemSelectionModel::Deselect); QModelIndexList sel; QSet pointers; selectedItems=selectedIndexes(); foreach(index, selectedItems) { QModelIndex idx(itsProxy->mapToSource(index)); if(!pointers.contains(idx.internalPointer())) { pointers.insert(idx.internalPointer()); sel.append(idx); } } return sel; } void CFontListView::itemCollapsed(const QModelIndex &idx) { if(idx.isValid()) { QModelIndex index(itsProxy->mapToSource(idx)); if(index.isValid() && (static_cast(index.internalPointer()))->isFamily()) { CFamilyItem *fam=static_cast(index.internalPointer()); CFontItemCont::ConstIterator it(fam->fonts().begin()), end(fam->fonts().end()); for(; it!=end; ++it) for(int i=0; iselect(itsProxy->mapFromSource(itsModel->createIndex((*it)->rowNumber(), i, *it)), QItemSelectionModel::Deselect); } } } static bool isScalable(const QString &str) { QByteArray cFile(QFile::encodeName(str)); return Misc::checkExt(cFile, "ttf") || Misc::checkExt(cFile, "otf") || Misc::checkExt(cFile, "ttc") || Misc::checkExt(cFile, "pfa") || Misc::checkExt(cFile, "pfb"); } void CFontListView::view() { // Number of fonts user has selected, before we ask if they really want to view them all... static const int constMaxBeforePrompt=10; QModelIndexList selectedItems(selectedIndexes()); QModelIndex index; QSet fonts; foreach(index, selectedItems) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { CFontItem *font(static_cast(realIndex.internalPointer())); fonts.insert(font); } else { CFontItem *font((static_cast(realIndex.internalPointer()))->regularFont()); if(font) fonts.insert(font); } } } if(fonts.count() && (fonts.count()::ConstIterator it(fonts.begin()), end(fonts.end()); QStringList args; for(; it!=end; ++it) { QString file; int index(0); if(!(*it)->isEnabled()) { // For a disabled font, we need to find the first scalable font entry in its file list... FileCont::ConstIterator fit((*it)->files().begin()), fend((*it)->files().end()); for(; fit!=fend; ++fit) if(isScalable((*fit).path())) { file=(*fit).path(); index=(*fit).index(); break; } if(file.isEmpty()) { file=(*it)->fileName(); index=(*it)->index(); } } args << FC::encode((*it)->family(), (*it)->styleInfo(), file, index).url(); } QProcess::startDetached(Misc::app(KFI_VIEWER), args); } } QModelIndexList CFontListView::allIndexes() { QModelIndexList rv; int rowCount(itsProxy->rowCount()); for(int i=0; iindex(i, 0, QModelIndex())); int childRowCount(itsProxy->rowCount(idx)); rv.append(idx); for(int j=0; jindex(j, 0, idx)); if(child.isValid()) rv.append(child); } } return rv; } void CFontListView::startDrag(Qt::DropActions supportedActions) { QModelIndexList indexes(selectedIndexes()); if (indexes.count()) { QMimeData *data = model()->mimeData(indexes); if (!data) return; QModelIndex index(itsProxy->mapToSource(indexes.first())); const char *icon="application-x-font-pcf"; if(index.isValid()) { CFontItem *font=(static_cast(index.internalPointer()))->isFont() ? static_cast(index.internalPointer()) : (static_cast(index.internalPointer()))->regularFont(); if(font && !font->isBitmap()) // if("application/x-font-type1"==font->mimetype()) // icon="application-x-font-type1"; // else icon="application-x-font-ttf"; } QPoint hotspot; QPixmap pix(DesktopIcon(icon, KIconLoader::SizeMedium)); hotspot.setX(0); // pix.width()/2); hotspot.setY(0); // pix.height()/2); QDrag *drag = new QDrag(this); drag->setPixmap(pix); drag->setMimeData(data); drag->setHotSpot(hotspot); drag->start(supportedActions); } } void CFontListView::dragEnterEvent(QDragEnterEvent *event) { if(itsAllowDrops && event->mimeData()->hasFormat("text/uri-list")) // "application/x-kde-urilist" ?? event->acceptProposedAction(); } void CFontListView::dropEvent(QDropEvent *event) { if(itsAllowDrops && event->mimeData()->hasFormat("text/uri-list")) { event->acceptProposedAction(); QList urls(event->mimeData()->urls()); QList::ConstIterator it(urls.begin()), end(urls.end()); QSet kurls; QMimeDatabase db; for (; it!=end; ++it) { QMimeType mime = db.mimeTypeForUrl(*it); foreach (const QString &fontMime, CFontList::fontMimeTypes) { if (mime.inherits(fontMime)) { kurls.insert(*it); break; } } } if(!kurls.isEmpty()) emit fontsDropped(kurls); } } void CFontListView::contextMenuEvent(QContextMenuEvent *ev) { bool valid(indexAt(ev->pos()).isValid()); itsDeleteAct->setEnabled(valid); bool en(false), dis(false); QModelIndexList selectedItems(selectedIndexes()); QModelIndex index; foreach(index, selectedItems) { QModelIndex realIndex(itsProxy->mapToSource(index)); if(realIndex.isValid()) { if((static_cast(realIndex.internalPointer()))->isFont()) { if((static_cast(realIndex.internalPointer())->isEnabled())) en=true; else dis=true; } else { switch((static_cast(realIndex.internalPointer()))->status()) { case CFamilyItem::ENABLED: en=true; break; case CFamilyItem::DISABLED: dis=true; break; case CFamilyItem::PARTIAL: en=dis=true; break; } } } if(en && dis) break; } itsEnableAct->setEnabled(dis); itsDisableAct->setEnabled(en); if(itsPrintAct) itsPrintAct->setEnabled(en|dis); if(itsViewAct) itsViewAct->setEnabled(en|dis); itsMenu->popup(ev->globalPos()); } bool CFontListView::viewportEvent(QEvent *event) { executeDelayedItemsLayout(); return QTreeView::viewportEvent(event); } } diff --git a/kcms/kfontinst/kcmfontinst/PreviewList.cpp b/kcms/kfontinst/kcmfontinst/PreviewList.cpp index 75c9e4e2a..0c2a11e68 100644 --- a/kcms/kfontinst/kcmfontinst/PreviewList.cpp +++ b/kcms/kfontinst/kcmfontinst/PreviewList.cpp @@ -1,223 +1,223 @@ /* * KFontInst - KDE Font Installer * * Copyright 2009 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "PreviewList.h" #include "FontList.h" #include "Fc.h" #include "FcEngine.h" #include #include #include #include #include #include #include #include namespace KFI { static CFcEngine * theFcEngine= nullptr; CPreviewList::CPreviewList(QObject *parent) : QAbstractItemModel(parent) { } QVariant CPreviewList::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); CPreviewListItem *item=static_cast(index.internalPointer()); if(item) switch(role) { case Qt::DisplayRole: return FC::createName(item->name(), item->style()); default: break; } return QVariant(); } Qt::ItemFlags CPreviewList::flags(const QModelIndex &) const { return Qt::ItemIsEnabled; } QModelIndex CPreviewList::index(int row, int column, const QModelIndex &parent) const { if(!parent.isValid()) { CPreviewListItem *item=itsItems.value(row); if(item) return createIndex(row, column, item); } return QModelIndex(); } QModelIndex CPreviewList::parent(const QModelIndex &) const { return QModelIndex(); } void CPreviewList::clear() { emit layoutAboutToBeChanged(); qDeleteAll(itsItems); itsItems.clear(); emit layoutChanged(); } void CPreviewList::showFonts(const QModelIndexList &fonts) { clear(); emit layoutAboutToBeChanged(); QModelIndex index; foreach(index, fonts) { CFontModelItem *mi=static_cast(index.internalPointer()); CFontItem *font=mi->parent() ? static_cast(mi) : (static_cast(mi))->regularFont(); if(font) itsItems.append(new CPreviewListItem(font->family(), font->styleInfo(), font->isEnabled() ? QString() : font->fileName(), font->index())); } emit layoutChanged(); } class CPreviewListViewDelegate : public QStyledItemDelegate { public: CPreviewListViewDelegate(QObject *p, int previewSize) : QStyledItemDelegate(p), itsPreviewSize(previewSize) { } ~CPreviewListViewDelegate() override { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &idx) const override { CPreviewListItem *item=static_cast(idx.internalPointer()); QStyleOptionViewItem opt(option); opt.rect.adjust(1, constBorder-3, 0, -(1+itsPreviewSize)); QStyledItemDelegate::paint(painter, opt, idx); opt.rect.adjust(constBorder, option.rect.height()-(1+itsPreviewSize), -constBorder, 0); painter->save(); painter->setPen(QApplication::palette().color(QPalette::Text)); QRect lineRect(opt.rect.adjusted(-1, 3, 0, 2)); painter->drawLine(lineRect.bottomLeft(), lineRect.bottomRight()); painter->setClipRect(option.rect.adjusted(constBorder, 0, -constBorder, 0)); painter->drawPixmap(opt.rect.topLeft(), getPixmap(item)); painter->restore(); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const override { QSize sz(QStyledItemDelegate::sizeHint(option, idx)); //int pWidth(getPixmap(static_cast(idx.internalPointer())).width()); int pWidth(1536); return QSize((constBorder*2)+pWidth, sz.height()+1+constBorder+itsPreviewSize); } QPixmap getPixmap(CPreviewListItem *item) const { QString key; QPixmap pix; QColor text(QApplication::palette().color(QPalette::Text)); QTextStream(&key) << "kfi-" << item->name() << "-" << item->style() << "-" << text.rgba(); - if(!QPixmapCache::find(key, pix)) + if(!QPixmapCache::find(key, &pix)) { QColor bgnd(Qt::black); bgnd.setAlpha(0); // TODO: Ideally, for this preview we want the fonts to be of a set point size pix=QPixmap::fromImage(theFcEngine->drawPreview(item->file().isEmpty() ? item->name() : item->file(), item->style(), item->index(), text, bgnd, itsPreviewSize)); QPixmapCache::insert(key, pix); } return pix; } int itsPreviewSize; static const int constBorder=4; }; CPreviewListView::CPreviewListView(CFcEngine *eng, QWidget *parent) : QTreeView(parent) { theFcEngine=eng; QFont font; int pixelSize((int)(((font.pointSizeF()*QX11Info::appDpiY())/72.0)+0.5)); itsModel=new CPreviewList(this); setModel(itsModel); setItemDelegate(new CPreviewListViewDelegate(this, (pixelSize+12)*3)); setSelectionMode(NoSelection); setVerticalScrollMode(ScrollPerPixel); setSortingEnabled(false); setAlternatingRowColors(false); setAcceptDrops(false); setDragEnabled(false); header()->setVisible(false); setRootIsDecorated(false); resizeColumnToContents(0); } void CPreviewListView::refreshPreviews() { QPixmapCache::clear(); repaint(); resizeColumnToContents(0); } void CPreviewListView::showFonts(const QModelIndexList &fonts) { itsModel->showFonts(fonts); resizeColumnToContents(0); } void CPreviewListView::contextMenuEvent(QContextMenuEvent *ev) { emit showMenu(ev->pos()); } } diff --git a/kcms/kfontinst/lib/Misc.cpp b/kcms/kfontinst/lib/Misc.cpp index 806e234f5..e919ede73 100644 --- a/kcms/kfontinst/lib/Misc.cpp +++ b/kcms/kfontinst/lib/Misc.cpp @@ -1,493 +1,494 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "Misc.h" #include "config-paths.h" #include #include #include #include #include #include #include #include #include #include #include +#include #include #include namespace KFI { namespace Misc { QString prettyUrl(const QUrl &url) { QString u(url.url()); u.replace("%20", " "); return u; } QString dirSyntax(const QString &d) { if(!d.isEmpty()) { QString ds(d); ds.replace("//", "/"); int slashPos(ds.lastIndexOf('/')); if(slashPos!=(((int)ds.length())-1)) ds.append('/'); return ds; } return d; } QString fileSyntax(const QString &d) { if(!d.isEmpty()) { QString ds(d); ds.replace("//", "/"); int slashPos(ds.lastIndexOf('/')); if(slashPos==(((int)ds.length())-1)) ds.remove(slashPos, 1); return ds; } return d; } QString getDir(const QString &f) { QString d(f); int slashPos(d.lastIndexOf('/')); if(slashPos!=-1) d.remove(slashPos+1, d.length()); return dirSyntax(d); } QString getFile(const QString &f) { QString d(f); int slashPos=d.lastIndexOf('/'); if(slashPos!=-1) d.remove(0, slashPos+1); return d; } bool createDir(const QString &dir) { if (!QDir().mkpath(dir)) return false; // // Clear any umask before setting dir perms mode_t oldMask(umask(0000)); const QByteArray d = QFile::encodeName(dir); ::chmod(d.constData(), DIR_PERMS); // Reset umask ::umask(oldMask); return true; } void setFilePerms(const QByteArray &f) { // // Clear any umask before setting file perms mode_t oldMask(umask(0000)); ::chmod(f.constData(), FILE_PERMS); // Reset umask ::umask(oldMask); } bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3) { QStringList args; if(!p1.isEmpty()) args << p1; if(!p2.isEmpty()) args << p2; if(!p3.isEmpty()) args << p3; return 0==QProcess::execute(cmd, args); } QString changeExt(const QString &f, const QString &newExt) { QString newStr(f); int dotPos(newStr.lastIndexOf('.')); if(-1==dotPos) newStr+=QChar('.')+newExt; else { newStr.remove(dotPos+1, newStr.length()); newStr+=newExt; } return newStr; } // // Get a list of files associated with a file, e.g.: // // File: /home/a/courier.pfa // // Associated: /home/a/courier.afm /home/a/courier.pfm // void getAssociatedFiles(const QString &path, QStringList &files, bool afmAndPfm) { QString ext(path); int dotPos(ext.lastIndexOf('.')); bool check(false); if(-1==dotPos) // Hmm, no extension - check anyway... check=true; else // Cool, got an extension - see if it is a Type1 font... { ext=ext.mid(dotPos+1); check=0==ext.compare("pfa", Qt::CaseInsensitive) || 0==ext.compare("pfb", Qt::CaseInsensitive); } if(check) { const char *afm[]={"afm", "AFM", "Afm", nullptr}, *pfm[]={"pfm", "PFM", "Pfm", nullptr}; bool gotAfm(false); int e; for(e=0; afm[e]; ++e) { QString statFile(changeExt(path, afm[e])); if(fExists(statFile)) { files.append(statFile); gotAfm=true; break; } } if(afmAndPfm || !gotAfm) for(e=0; pfm[e]; ++e) { QString statFile(changeExt(path, pfm[e])); if(fExists(statFile)) { files.append(statFile); break; } } } } time_t getTimeStamp(const QString &item) { QT_STATBUF info; return !item.isEmpty() && 0==QT_LSTAT(QFile::encodeName(item), &info) ? info.st_mtime : 0; } bool check(const QString &path, bool file, bool checkW) { QT_STATBUF info; QByteArray pathC(QFile::encodeName(path)); return 0==QT_LSTAT(pathC, &info) && (file ? (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) : S_ISDIR(info.st_mode)) && (!checkW || 0==::access(pathC, W_OK)); } QString getFolder(const QString &defaultDir, const QString &root, QStringList &dirs) { if(dirs.contains(defaultDir)) return defaultDir; else { QStringList::const_iterator it, end=dirs.constEnd(); bool found=false; for(it=dirs.constBegin(); it!=end && !found; ++it) if(0==(*it).indexOf(root)) return *it; } return defaultDir; } bool checkExt(const QString &fname, const QString &ext) { QString extension('.'+ext); return fname.length()>extension.length() ? 0==fname.mid(fname.length()-extension.length()).compare(extension, Qt::CaseInsensitive) : false; } bool isBitmap(const QString &str) { return checkExt(str, "pcf") || checkExt(str, "bdf") || checkExt(str, "pcf.gz") || checkExt(str, "bdf.gz"); } bool isMetrics(const QString &str) { return checkExt(str, "afm") || checkExt(str, "pfm"); } int getIntQueryVal(const QUrl &url, const char *key, int defVal) { QUrlQuery query(url); QString item(query.queryItemValue(key)); int val(defVal); if(!item.isNull()) val=item.toInt(); return val; } bool printable(const QString &mime) { return "font/otf"==mime || "font/ttf"==mime || "application/x-font-type1"==mime || "application/x-font-ttf"==mime || "application/x-font-otf"==mime || "application/x-font-type1"==mime; } uint qHash(const KFI::Misc::TFont &key) { //return qHash(QString(key.family+'%'+QString().setNum(key.styleInfo, 16))); const QChar *p = key.family.unicode(); int n = key.family.size(); uint h = 0, g; h = (h << 4) + key.styleInfo; if ((g = (h & 0xf0000000)) != 0) h ^= g >> 23; h &= ~g; while (n--) { h = (h << 4) + (*p++).unicode(); if ((g = (h & 0xf0000000)) != 0) h ^= g >> 23; h &= ~g; } return h; } // Taken from qdom.cpp QString encodeText(const QString &str, QTextStream &s) { const QTextCodec *const codec = s.codec(); Q_ASSERT(codec); QString retval(str); int len = retval.length(), i = 0; while (i < len) { const QChar ati(retval.at(i)); if (ati == QLatin1Char('<')) { retval.replace(i, 1, QLatin1String("<")); len += 3; i += 4; } else if (ati == QLatin1Char('"')) { retval.replace(i, 1, QLatin1String(""")); len += 5; i += 6; } else if (ati == QLatin1Char('&')) { retval.replace(i, 1, QLatin1String("&")); len += 4; i += 5; } else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']')) { retval.replace(i, 1, QLatin1String(">")); len += 3; i += 4; } else { if(codec->canEncode(ati)) ++i; else { // We have to use a character reference to get it through. const ushort codepoint(ati.unicode()); const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';')); retval.replace(i, 1, replacement); i += replacement.length(); len += replacement.length() - 1; } } } return retval; } QString contractHome(QString path) { if (!path.isEmpty() && '/'==path[0]) { QString home(QDir::homePath()); if(path.startsWith(home)) { int len = home.length(); if(len>1 && (path.length() == len || path[len] == '/')) return path.replace(0, len, QString::fromLatin1("~")); } } return path; } QString expandHome(QString path) { if(!path.isEmpty() && '~'==path[0]) return 1==path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath()); return path; } QMap getFontFileMap(const QSet &files) { QMap map; QSet::ConstIterator it=files.constBegin(), end=files.constEnd(); QMap > fontsFiles; for(;it!=end; ++it) fontsFiles[unhide(getFile(*it))].insert(getDir(*it)); QMap >::ConstIterator fIt(fontsFiles.constBegin()), fEnd(fontsFiles.constEnd()); for(; fIt!=fEnd; ++fIt) if(fIt.value().count()>1) { QVector orig(fIt.value().count()), modified(fIt.value().count()); QSet::ConstIterator oIt(fIt.value().constBegin()), oEnd(fIt.value().constEnd()); bool good=true; int count=fIt.value().count(); for(int i=0; i apps; if(!apps.contains(name)) { QStringList installPaths; if (qstrcmp(path, "libexec") == 0) installPaths.append(KFONTINST_LIBEXEC_DIR); apps[name] = QStandardPaths::findExecutable(name, installPaths); } return apps[name]; } } // Misc:: } // KFI:: diff --git a/kcms/kfontinst/viewpart/FontPreview.cpp b/kcms/kfontinst/viewpart/FontPreview.cpp index 8517533c1..0d68d4b6f 100644 --- a/kcms/kfontinst/viewpart/FontPreview.cpp +++ b/kcms/kfontinst/viewpart/FontPreview.cpp @@ -1,178 +1,178 @@ /* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "FontPreview.h" #include "FcEngine.h" #include "CharTip.h" #include #include #include #include #include namespace KFI { static const int constBorder=4; static const int constStepSize=16; CFontPreview::CFontPreview(QWidget *parent) : QWidget(parent), itsCurrentFace(1), itsLastWidth(0), itsLastHeight(0), itsStyleInfo(KFI_NO_STYLE_INFO), itsTip(nullptr) { itsEngine=new CFcEngine; } CFontPreview::~CFontPreview() { delete itsTip; delete itsEngine; } void CFontPreview::showFont(const QString &name, unsigned long styleInfo, int face) { itsFontName=name; itsStyleInfo=styleInfo; showFace(face); } void CFontPreview::showFace(int face) { itsCurrentFace=face; showFont(); } void CFontPreview::showFont() { itsLastWidth=width()+constStepSize; itsLastHeight=height()+constStepSize; itsImage=itsEngine->draw(itsFontName, itsStyleInfo, itsCurrentFace, palette().text().color(), palette().base().color(), itsLastWidth, itsLastHeight, false, itsRange, &itsChars); if(!itsImage.isNull()) { itsLastChar=CFcEngine::TChar(); setMouseTracking(itsChars.count()>0); update(); emit status(true); emit atMax(itsEngine->atMax()); emit atMin(itsEngine->atMin()); } else { itsLastChar=CFcEngine::TChar(); setMouseTracking(false); update(); emit status(false); emit atMax(true); emit atMin(true); } } void CFontPreview::zoomIn() { itsEngine->zoomIn(); showFont(); emit atMax(itsEngine->atMax()); } void CFontPreview::zoomOut() { itsEngine->zoomOut(); showFont(); emit atMin(itsEngine->atMin()); } void CFontPreview::setUnicodeRange(const QList &r) { itsRange=r; showFont(); } void CFontPreview::paintEvent(QPaintEvent *) { QPainter paint(this); paint.fillRect(rect(), palette().base()); if(!itsImage.isNull()) { if(abs(width()-itsLastWidth)>constStepSize || abs(height()-itsLastHeight)>constStepSize) showFont(); else paint.drawImage(QPointF(constBorder, constBorder), itsImage, QRectF(0, 0, (width()-(constBorder*2)) * itsImage.devicePixelRatioF(), (height()-(constBorder*2)) * itsImage.devicePixelRatioF())); } } void CFontPreview::mouseMoveEvent(QMouseEvent *event) { if(!itsChars.isEmpty()) { QList::ConstIterator end(itsChars.end()); if(itsLastChar.isNull() || !itsLastChar.contains(event->pos())) for(QList::ConstIterator it(itsChars.begin()); it!=end; ++it) if((*it).contains(event->pos())) { if(!itsTip) itsTip=new CCharTip(this); itsTip->setItem(*it); itsLastChar=*it; break; } } } void CFontPreview::wheelEvent(QWheelEvent *e) { - if(e->delta()>0) + if(e->angleDelta().y()>0) zoomIn(); - else if(e->delta()<0) + else if(e->angleDelta().y()<0) zoomOut(); e->accept(); } QSize CFontPreview::sizeHint() const { return QSize(132, 132); } QSize CFontPreview::minimumSizeHint() const { return QSize(32, 32); } } diff --git a/kcms/krdb/krdb.cpp b/kcms/krdb/krdb.cpp index a2c53bed9..46ac97662 100644 --- a/kcms/krdb/krdb.cpp +++ b/kcms/krdb/krdb.cpp @@ -1,990 +1,990 @@ /**************************************************************************** ** ** ** KRDB - puts current KDE color scheme into preprocessor statements ** cats specially written application default files and uses xrdb -merge to ** write to RESOURCE_MANAGER. Thus it gives a simple way to make non-KDE ** applications fit in with the desktop ** ** Copyright (C) 1998 by Mark Donohoe ** Copyright (C) 1999 by Dirk A. Mueller (reworked for KDE 2.0) ** Copyright (C) 2001 by Matthias Ettrich (add support for GTK applications ) ** Copyright (C) 2001 by Waldo Bastian ** Copyright (C) 2002 by Karol Szwed ** This application is freely distributable under the GNU Public License. ** *****************************************************************************/ #include #include #include #include #include #include #undef Unsorted #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krdb.h" #if HAVE_X11 #include #include #endif inline const char * gtkEnvVar(int version) { return 2==version ? "GTK2_RC_FILES" : "GTK_RC_FILES"; } inline const char * sysGtkrc(int version) { if(2==version) { if(access("/etc/opt/gnome/gtk-2.0", F_OK) == 0) return "/etc/opt/gnome/gtk-2.0/gtkrc"; else return "/etc/gtk-2.0/gtkrc"; } else { if(access("/etc/opt/gnome/gtk", F_OK) == 0) return "/etc/opt/gnome/gtk/gtkrc"; else return "/etc/gtk/gtkrc"; } } inline const char * userGtkrc(int version) { return 2==version ? "/.gtkrc-2.0" : "/.gtkrc"; } // ----------------------------------------------------------------------------- static QString writableGtkrc(int version) { QString gtkrc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QDir dir; dir.mkpath(gtkrc); gtkrc += 2==version?"/gtkrc-2.0":"/gtkrc"; return gtkrc; } // ----------------------------------------------------------------------------- static void applyGtkStyles(bool active, int version) { QString gtkkde = writableGtkrc(version); QByteArray gtkrc = getenv(gtkEnvVar(version)); QStringList list = QFile::decodeName(gtkrc).split( QLatin1Char(':')); QString userHomeGtkrc = QDir::homePath()+userGtkrc(version); if (!list.contains(userHomeGtkrc)) list.prepend(userHomeGtkrc); QLatin1String systemGtkrc = QLatin1String(sysGtkrc(version)); if (!list.contains(systemGtkrc)) list.prepend(systemGtkrc); list.removeAll(QLatin1String("")); list.removeAll(gtkkde); list.append(gtkkde); // Pass env. var to kdeinit. QString name = gtkEnvVar(version); QString value = list.join(QLatin1Char(':')); org::kde::KLauncher klauncher(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QDBusConnection::sessionBus()); klauncher.setLaunchEnv(name, value); } // ----------------------------------------------------------------------------- static void applyQtColors( KSharedConfigPtr kglobalcfg, QSettings& settings, QPalette& newPal ) { QStringList actcg, inactcg, discg; /* export kde color settings */ int i; for (i = 0; i < QPalette::NColorRoles; i++) actcg << newPal.color(QPalette::Active, (QPalette::ColorRole) i).name(); for (i = 0; i < QPalette::NColorRoles; i++) inactcg << newPal.color(QPalette::Inactive, (QPalette::ColorRole) i).name(); for (i = 0; i < QPalette::NColorRoles; i++) discg << newPal.color(QPalette::Disabled, (QPalette::ColorRole) i).name(); settings.setValue(QStringLiteral("/qt/Palette/active"), actcg); settings.setValue(QStringLiteral("/qt/Palette/inactive"), inactcg); settings.setValue(QStringLiteral("/qt/Palette/disabled"), discg); // export kwin's colors to qtrc for kstyle to use KConfigGroup wmCfgGroup(kglobalcfg, "WM"); // active colors QColor clr = newPal.color( QPalette::Active, QPalette::Window ); clr = wmCfgGroup.readEntry("activeBackground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeBackground"), clr.name()); if (QPixmap::defaultDepth() > 8) clr = clr.darker(110); clr = wmCfgGroup.readEntry("activeBlend", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeBlend"), clr.name()); clr = newPal.color( QPalette::Active, QPalette::HighlightedText ); clr = wmCfgGroup.readEntry("activeForeground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeForeground"), clr.name()); clr = newPal.color( QPalette::Active,QPalette::Window ); clr = wmCfgGroup.readEntry("frame", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/frame"), clr.name()); clr = wmCfgGroup.readEntry("activeTitleBtnBg", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/activeTitleBtnBg"), clr.name()); // inactive colors clr = newPal.color(QPalette::Inactive, QPalette::Window); clr = wmCfgGroup.readEntry("inactiveBackground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBackground"), clr.name()); if (QPixmap::defaultDepth() > 8) clr = clr.darker(110); clr = wmCfgGroup.readEntry("inactiveBlend", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBlend"), clr.name()); clr = newPal.color(QPalette::Inactive, QPalette::Window).darker(); clr = wmCfgGroup.readEntry("inactiveForeground", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveForeground"), clr.name()); clr = newPal.color(QPalette::Inactive, QPalette::Window); clr = wmCfgGroup.readEntry("inactiveFrame", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveFrame"), clr.name()); clr = wmCfgGroup.readEntry("inactiveTitleBtnBg", clr); settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveTitleBtnBg"), clr.name()); KConfigGroup kdeCfgGroup(kglobalcfg, "KDE"); settings.setValue(QStringLiteral("/qt/KDE/contrast"), kdeCfgGroup.readEntry("contrast", 7)); } // ----------------------------------------------------------------------------- static void applyQtSettings( KSharedConfigPtr kglobalcfg, QSettings& settings ) { /* export font settings */ // NOTE keep this in sync with kfontsettingsdata in plasma-integration (cf. also Bug 378262) QFont defaultFont(QStringLiteral("Noto Sans"), 10, -1); defaultFont.setStyleHint(QFont::SansSerif); const KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("General")); const QString fontInfo = configGroup.readEntry(QStringLiteral("font"), QString()); if (!fontInfo.isEmpty()) { defaultFont.fromString(fontInfo); } settings.setValue(QStringLiteral("/qt/font"), defaultFont.toString()); /* export effects settings */ KConfigGroup kdeCfgGroup(kglobalcfg, "General"); bool effectsEnabled = kdeCfgGroup.readEntry("EffectsEnabled", false); bool fadeMenus = kdeCfgGroup.readEntry("EffectFadeMenu", false); bool fadeTooltips = kdeCfgGroup.readEntry("EffectFadeTooltip", false); bool animateCombobox = kdeCfgGroup.readEntry("EffectAnimateCombo", false); QStringList guieffects; if (effectsEnabled) { guieffects << QStringLiteral("general"); if (fadeMenus) guieffects << QStringLiteral("fademenu"); if (animateCombobox) guieffects << QStringLiteral("animatecombo"); if (fadeTooltips) guieffects << QStringLiteral("fadetooltip"); } else guieffects << QStringLiteral("none"); settings.setValue(QStringLiteral("/qt/GUIEffects"), guieffects); } // ----------------------------------------------------------------------------- static void addColorDef(QString& s, const char* n, const QColor& col) { QString tmp; tmp.sprintf("#define %s #%02x%02x%02x\n", n, col.red(), col.green(), col.blue()); s += tmp; } // ----------------------------------------------------------------------------- static void copyFile(QFile& tmp, QString const& filename, bool ) { QFile f( filename ); if ( f.open(QIODevice::ReadOnly) ) { QByteArray buf( 8192, ' ' ); while ( !f.atEnd() ) { int read = f.read( buf.data(), buf.size() ); if ( read > 0 ) tmp.write( buf.data(), read ); } } } // ----------------------------------------------------------------------------- static QString item( int i ) { return QString::number( i / 255.0, 'f', 3 ); } static QString color( const QColor& col ) { return QStringLiteral( "{ %1, %2, %3 }" ).arg( item( col.red() ) ).arg( item( col.green() ) ).arg( item( col.blue() ) ); } static void createGtkrc( bool exportColors, const QPalette& cg, bool exportGtkTheme, const QString& gtkTheme, int version ) { // lukas: why does it create in ~/.kde/share/config ??? // pfeiffer: so that we don't overwrite the user's gtkrc. // it is found via the GTK_RC_FILES environment variable. QSaveFile saveFile( writableGtkrc(version) ); if ( !saveFile.open(QIODevice::WriteOnly) ) return; QTextStream t ( &saveFile ); t.setCodec( QTextCodec::codecForLocale () ); t << i18n( "# created by KDE Plasma, %1\n" "#\n" "# If you do not want Plasma to override your GTK settings, select\n" "# Colors in the System Settings and disable the checkbox\n" "# \"Apply colors to non-Qt applications\"\n" "#\n" "#\n", QDateTime::currentDateTime().toString()); if ( 2==version ) { // we should maybe check for MacOS settings here t << endl; t << "gtk-alternative-button-order = 1" << endl; t << endl; } if (exportGtkTheme) { QString gtkStyle; if (gtkTheme.toLower() == QLatin1String("oxygen")) gtkStyle = QStringLiteral("oxygen-gtk"); else gtkStyle = gtkTheme; bool exist_gtkrc = false; QByteArray gtkrc = getenv(gtkEnvVar(version)); QStringList listGtkrc = QFile::decodeName(gtkrc).split(QLatin1Char(':')); if (listGtkrc.contains(saveFile.fileName())) listGtkrc.removeAll(saveFile.fileName()); listGtkrc.append(QDir::homePath() + userGtkrc(version)); listGtkrc.append(QDir::homePath() + "/.gtkrc-2.0-kde"); listGtkrc.append(QDir::homePath() + "/.gtkrc-2.0-kde4"); listGtkrc.removeAll(QLatin1String("")); listGtkrc.removeDuplicates(); for (int i = 0; i < listGtkrc.size(); ++i) { if ((exist_gtkrc = QFile::exists(listGtkrc.at(i)))) break; } if (!exist_gtkrc) { QString gtk2ThemeFilename; gtk2ThemeFilename = QStringLiteral("%1/.themes/%2/gtk-2.0/gtkrc").arg(QDir::homePath()).arg(gtkStyle); if (!QFile::exists(gtk2ThemeFilename)) { QStringList gtk2ThemePath; gtk2ThemeFilename.clear(); QByteArray xdgDataDirs = getenv("XDG_DATA_DIRS"); gtk2ThemePath.append(QDir::homePath() + "/.local"); gtk2ThemePath.append(QFile::decodeName(xdgDataDirs).split(QLatin1Char(':'))); gtk2ThemePath.removeDuplicates(); for (int i = 0; i < gtk2ThemePath.size(); ++i) { gtk2ThemeFilename = QStringLiteral("%1/themes/%2/gtk-2.0/gtkrc").arg(gtk2ThemePath.at(i)).arg(gtkStyle); if (QFile::exists(gtk2ThemeFilename)) break; else gtk2ThemeFilename.clear(); } } if (!gtk2ThemeFilename.isEmpty()) { t << "include \"" << gtk2ThemeFilename << "\"" << endl; t << endl; t << "gtk-theme-name=\"" << gtkStyle << "\"" << endl; t << endl; if (gtkStyle == QLatin1String("oxygen-gtk")) exportColors = false; } } } if (exportColors) { t << "style \"default\"" << endl; t << "{" << endl; t << " bg[NORMAL] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << " bg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " bg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << " bg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " bg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << endl; t << " base[NORMAL] = " << color( cg.color( QPalette::Active, QPalette::Base ) ) << endl; t << " base[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " base[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Window ) ) << endl; t << " base[ACTIVE] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << " base[PRELIGHT] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl; t << endl; t << " text[NORMAL] = " << color( cg.color(QPalette::Active, QPalette::Text) ) << endl; t << " text[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << " text[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " text[ACTIVE] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << " text[PRELIGHT] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << endl; t << " fg[NORMAL] = " << color ( cg.color( QPalette::Active, QPalette::WindowText ) ) << endl; t << " fg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl; t << " fg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl; t << " fg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::WindowText ) ) << endl; t << " fg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::WindowText ) ) << endl; t << "}" << endl; t << endl; t << "class \"*\" style \"default\"" << endl; t << endl; // tooltips don't have the standard background color t << "style \"ToolTip\"" << endl; t << "{" << endl; t << " bg[NORMAL] = " << color( cg.color( QPalette::ToolTipBase ) ) << endl; t << " base[NORMAL] = " << color( cg.color( QPalette::ToolTipBase ) ) << endl; t << " text[NORMAL] = " << color( cg.color( QPalette::ToolTipText ) ) << endl; t << " fg[NORMAL] = " << color( cg.color( QPalette::ToolTipText ) ) << endl; t << "}" << endl; t << endl; t << "widget \"gtk-tooltip\" style \"ToolTip\"" << endl; t << "widget \"gtk-tooltips\" style \"ToolTip\"" << endl; t << "widget \"gtk-tooltip*\" style \"ToolTip\"" << endl; t << endl; // highlight the current (mouse-hovered) menu-item // not every button, checkbox, etc. t << "style \"MenuItem\"" << endl; t << "{" << endl; t << " bg[PRELIGHT] = " << color( cg.color(QPalette::Highlight) ) << endl; t << " fg[PRELIGHT] = " << color( cg.color(QPalette::HighlightedText) ) << endl; t << "}" << endl; t << endl; t << "class \"*MenuItem\" style \"MenuItem\"" << endl; t << endl; } saveFile.commit(); } // --------------------------------------------------------------------- QString gtkColorsHelper(const QString &name, const QString &color) { return QStringLiteral("@define-color %1 %2;\n").arg(name, color); } void checkGtkCss() { QFile gtkCss(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/gtk-3.0/gtk.css"); if (gtkCss.open(QIODevice::ReadWrite)) { QTextStream gtkStream(>kCss); bool hasImport = false; while (!gtkStream.atEnd()) { QString line = gtkStream.readLine(); if (line.contains("@import 'colors.css';")) { hasImport = true; } } if (!hasImport) { gtkStream << "@import 'colors.css';"; } } } void exportGtkColors(QList activeColorSchemes, QList inactiveColorSchemes, QList disabledColorSchemes, KConfigGroup groupWMTheme, QTextStream& colorsStream) { /* Normal (Non Backdrop, Non Insensitive) */ // General Colors colorsStream << gtkColorsHelper("theme_fg_color", activeColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_bg_color", activeColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_text_color", activeColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_base_color", activeColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_view_hover_decoration_color", activeColorSchemes[0].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_hovering_selected_bg_color", activeColorSchemes[3].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_selected_bg_color", activeColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_selected_fg_color", activeColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_view_active_decoration_color", activeColorSchemes[0].decoration(KColorScheme::HoverColor).color().name()); // Button Colors colorsStream << gtkColorsHelper("theme_button_background_normal", activeColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover", activeColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus", activeColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_normal", activeColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active", activeColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor windowForegroundColor = activeColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor windowBackgroundColor = activeColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor bordersColor = KColorUtils::mix(windowBackgroundColor,windowForegroundColor, 0.25); colorsStream << gtkColorsHelper("borders", bordersColor.name()); colorsStream << gtkColorsHelper("warning_color", activeColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color", activeColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color", activeColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Backdrop (Inactive) */ // General colorsStream << gtkColorsHelper("theme_unfocused_fg_color",inactiveColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_text_color", inactiveColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_bg_color", inactiveColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_base_color", inactiveColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_selected_bg_color_alt", inactiveColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_selected_bg_color", inactiveColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_selected_fg_color", inactiveColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Button colorsStream << gtkColorsHelper("theme_button_background_backdrop", inactiveColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover_backdrop", inactiveColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus_backdrop", inactiveColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_backdrop", inactiveColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active_backdrop", inactiveColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor inactiveWindowForegroundColor = inactiveColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor inactiveWindowBackgroundColor = inactiveColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor inactiveBordersColor = KColorUtils::mix(inactiveWindowBackgroundColor,inactiveWindowForegroundColor, 0.25); colorsStream << gtkColorsHelper("unfocused_borders", inactiveBordersColor.name()); colorsStream << gtkColorsHelper("warning_color_backdrop", inactiveColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color_backdrop", inactiveColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color_backdrop", inactiveColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Insensitive (Disabled) */ // General colorsStream << gtkColorsHelper("insensitive_fg_color",disabledColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("insensitive_base_fg_color", disabledColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("insensitive_bg_color", disabledColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_base_color", disabledColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_selected_bg_color", disabledColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_selected_fg_color", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Button colorsStream << gtkColorsHelper("theme_button_background_insensitive", disabledColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover_insensitive", disabledColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus_insensitive", disabledColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_insensitive", disabledColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active_insensitive", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor disabledWindowForegroundColor = disabledColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor disabledWindowBackgroundColor = disabledColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor disabledBordersColor = KColorUtils::mix(disabledWindowBackgroundColor,disabledWindowForegroundColor, 0.25); colorsStream << gtkColorsHelper("insensitive_borders", disabledBordersColor.name()); colorsStream << gtkColorsHelper("warning_color_insensitive", disabledColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color_insensitive", disabledColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color_insensitive", disabledColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Insensitive Backdrop (Inactive Disabled) These pretty much have the same appearance as regular inactive colors, but they're seperate in case we decide to make them different in the future. */ // General colorsStream << gtkColorsHelper("insensitive_unfocused_fg_color",disabledColorSchemes[1].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_view_text_color", disabledColorSchemes[0].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("insensitive_unfocused_bg_color", disabledColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_unfocused_view_bg_color", disabledColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_unfocused_selected_bg_color", disabledColorSchemes[3].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("insensitive_unfocused_selected_fg_color", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Button colorsStream << gtkColorsHelper("theme_button_background_backdrop_insensitive", disabledColorSchemes[2].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_hover_backdrop_insensitive", disabledColorSchemes[2].decoration(KColorScheme::HoverColor).color().name()); colorsStream << gtkColorsHelper("theme_button_decoration_focus_backdrop_insensitive", disabledColorSchemes[2].decoration(KColorScheme::FocusColor).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_backdrop_insensitive", disabledColorSchemes[2].foreground(KColorScheme::NormalText).color().name()); colorsStream << gtkColorsHelper("theme_button_foreground_active_backdrop_insensitive", disabledColorSchemes[3].foreground(KColorScheme::NormalText).color().name()); // Misc Colors QColor unfocusedDisabledWindowForegroundColor = disabledColorSchemes[1].foreground(KColorScheme::NormalText).color(); QColor unfocusedDisabledWindowBackgroundColor = disabledColorSchemes[1].background(KColorScheme::NormalBackground).color(); QColor unfocusedDisabledBordersColor = KColorUtils::mix(unfocusedDisabledWindowBackgroundColor,unfocusedDisabledWindowForegroundColor, 0.25); colorsStream << gtkColorsHelper("unfocused_insensitive_borders", unfocusedDisabledBordersColor.name()); colorsStream << gtkColorsHelper("warning_color_insensitive_backdrop", disabledColorSchemes[0].foreground(KColorScheme::NeutralText).color().name()); colorsStream << gtkColorsHelper("success_color_insensitive_backdrop", disabledColorSchemes[0].foreground(KColorScheme::PositiveText).color().name()); colorsStream << gtkColorsHelper("error_color_insensitive_backdrop", disabledColorSchemes[0].foreground(KColorScheme::NegativeText).color().name()); /* Ignorant Colors (These colors do not care about backdrop or insensitive states) */ colorsStream << gtkColorsHelper("link_color", activeColorSchemes[0].foreground(KColorScheme::LinkText).color().name()); colorsStream << gtkColorsHelper("link_visited_color", activeColorSchemes[0].foreground(KColorScheme::VisitedText).color().name()); QColor tooltipForegroundColor = activeColorSchemes[4].foreground(KColorScheme::NormalText).color(); QColor tooltipBackgroundColor = activeColorSchemes[4].background(KColorScheme::NormalBackground).color(); QColor tooltipBorderColor = KColorUtils::mix(tooltipBackgroundColor, tooltipForegroundColor, 0.25); colorsStream << gtkColorsHelper("tooltip_text", tooltipForegroundColor.name()); colorsStream << gtkColorsHelper("tooltip_background", tooltipBackgroundColor.name()); colorsStream << gtkColorsHelper("tooltip_border", tooltipBorderColor.name()); colorsStream << gtkColorsHelper("content_view_bg", activeColorSchemes[0].background(KColorScheme::NormalBackground).color().name()); // Titlebar colors colorsStream << gtkColorsHelper("theme_titlebar_background", "rgb(" + groupWMTheme.readEntry("activeBackground", "") + QLatin1Char(')')); colorsStream << gtkColorsHelper("theme_titlebar_foreground", "rgb(" + groupWMTheme.readEntry("activeForeground", "") + QLatin1Char(')')); colorsStream << gtkColorsHelper("theme_titlebar_background_light", activeColorSchemes[1].background(KColorScheme::NormalBackground).color().name()); colorsStream << gtkColorsHelper("theme_titlebar_foreground_backdrop", "rgb(" + groupWMTheme.readEntry("inactiveForeground", "") + QLatin1Char(')')); colorsStream << gtkColorsHelper("theme_titlebar_background_backdrop", "rgb(" + groupWMTheme.readEntry("inactiveBackground", "") + QLatin1Char(')')); colorsStream << gtkColorsHelper("theme_titlebar_foreground_insensitive", "rgb(" + groupWMTheme.readEntry("inactiveForeground", "") + QLatin1Char(')')); colorsStream << gtkColorsHelper("theme_titlebar_foreground_insensitive_backdrop", "rgb(" + groupWMTheme.readEntry("inactiveForeground", "") + QLatin1Char(')')); } void saveGtkColors(KSharedConfigPtr& config) { checkGtkCss(); QFile colorsCss(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/gtk-3.0/colors.css"); if (colorsCss.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream colorsStream(&colorsCss); /* 0 Active View 1 Active Window 2 Active Button 3 Active Selection 4 Active Tooltip 5 Active Complimentary */ QList activeColorSchemes{ KColorScheme(QPalette::Active, KColorScheme::View, config), KColorScheme(QPalette::Active, KColorScheme::Window, config), KColorScheme(QPalette::Active, KColorScheme::Button, config), KColorScheme(QPalette::Active, KColorScheme::Selection, config), KColorScheme(QPalette::Active, KColorScheme::Tooltip, config), KColorScheme(QPalette::Active, KColorScheme::Complementary, config) }; QList inactiveColorSchemes{ KColorScheme(QPalette::Inactive, KColorScheme::View, config), KColorScheme(QPalette::Inactive, KColorScheme::Window, config), KColorScheme(QPalette::Inactive, KColorScheme::Button, config), KColorScheme(QPalette::Inactive, KColorScheme::Selection, config), KColorScheme(QPalette::Inactive, KColorScheme::Tooltip, config), KColorScheme(QPalette::Inactive, KColorScheme::Complementary, config) }; QList disabledColorSchemes{ KColorScheme(QPalette::Disabled, KColorScheme::View, config), KColorScheme(QPalette::Disabled, KColorScheme::Window, config), KColorScheme(QPalette::Disabled, KColorScheme::Button, config), KColorScheme(QPalette::Disabled, KColorScheme::Selection, config), KColorScheme(QPalette::Disabled, KColorScheme::Tooltip, config), KColorScheme(QPalette::Disabled, KColorScheme::Complementary, config) }; KConfigGroup groupWMTheme(config, "WM"); exportGtkColors(activeColorSchemes, inactiveColorSchemes, disabledColorSchemes, groupWMTheme, colorsStream); } } void saveGtkColors() { checkGtkCss(); QFile colorsCss(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/gtk-3.0/colors.css"); KConfigGroup groupWMTheme(KSharedConfig::openConfig(), "WM"); if (colorsCss.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream colorsStream(&colorsCss); /* 0 Active View 1 Active Window 2 Active Button 3 Active Selection 4 Active Tooltip 5 Active Complimentary */ QList activeColorSchemes{ KColorScheme(QPalette::Active, KColorScheme::View), KColorScheme(QPalette::Active, KColorScheme::Window), KColorScheme(QPalette::Active, KColorScheme::Button), KColorScheme(QPalette::Active, KColorScheme::Selection), KColorScheme(QPalette::Active, KColorScheme::Tooltip), KColorScheme(QPalette::Active, KColorScheme::Complementary) }; QList inactiveColorSchemes{ KColorScheme(QPalette::Inactive, KColorScheme::View), KColorScheme(QPalette::Inactive, KColorScheme::Window), KColorScheme(QPalette::Inactive, KColorScheme::Button), KColorScheme(QPalette::Inactive, KColorScheme::Selection), KColorScheme(QPalette::Inactive, KColorScheme::Tooltip), KColorScheme(QPalette::Inactive, KColorScheme::Complementary) }; QList disabledColorSchemes{ KColorScheme(QPalette::Disabled, KColorScheme::View), KColorScheme(QPalette::Disabled, KColorScheme::Window), KColorScheme(QPalette::Disabled, KColorScheme::Button), KColorScheme(QPalette::Disabled, KColorScheme::Selection), KColorScheme(QPalette::Disabled, KColorScheme::Tooltip), KColorScheme(QPalette::Disabled, KColorScheme::Complementary) }; exportGtkColors(activeColorSchemes, inactiveColorSchemes, disabledColorSchemes, groupWMTheme, colorsStream); } } // ----------------------------------------------------------------------------- void runRdb( uint flags ) { // Obtain the application palette that is about to be set. bool exportColors = flags & KRdbExportColors; bool exportQtColors = flags & KRdbExportQtColors; bool exportQtSettings = flags & KRdbExportQtSettings; bool exportXftSettings = flags & KRdbExportXftSettings; bool exportGtkTheme = flags & KRdbExportGtkTheme; bool exportGtkColors = flags & KRdbExportGtkColors; KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig( QStringLiteral("kdeglobals") ); KConfigGroup kglobals(kglobalcfg, "KDE"); QPalette newPal = KColorScheme::createApplicationPalette(kglobalcfg); QTemporaryFile tmpFile; if (!tmpFile.open()) { qDebug() << "Couldn't open temp file"; exit(0); } KConfigGroup generalCfgGroup(kglobalcfg, "General"); QString gtkTheme; if (kglobals.hasKey("widgetStyle")) gtkTheme = kglobals.readEntry("widgetStyle"); else gtkTheme = QStringLiteral("oxygen"); createGtkrc( exportColors, newPal, exportGtkTheme, gtkTheme, 1 ); createGtkrc( exportColors, newPal, exportGtkTheme, gtkTheme, 2 ); // Export colors to non-(KDE/Qt) apps (e.g. Motif, GTK+ apps) if (exportColors) { KConfigGroup g(KSharedConfig::openConfig(), "WM"); QString preproc; QColor backCol = newPal.color( QPalette::Active, QPalette::Window ); addColorDef(preproc, "FOREGROUND" , newPal.color( QPalette::Active, QPalette::WindowText ) ); addColorDef(preproc, "BACKGROUND" , backCol); addColorDef(preproc, "HIGHLIGHT" , backCol.lighter(100+(2*KColorScheme::contrast()+4)*16/1)); addColorDef(preproc, "LOWLIGHT" , backCol.darker(100+(2*KColorScheme::contrast()+4)*10)); addColorDef(preproc, "SELECT_BACKGROUND" , newPal.color( QPalette::Active, QPalette::Highlight)); addColorDef(preproc, "SELECT_FOREGROUND" , newPal.color( QPalette::Active, QPalette::HighlightedText)); addColorDef(preproc, "WINDOW_BACKGROUND" , newPal.color( QPalette::Active, QPalette::Base ) ); addColorDef(preproc, "WINDOW_FOREGROUND" , newPal.color( QPalette::Active, QPalette::Text ) ); addColorDef(preproc, "INACTIVE_BACKGROUND", g.readEntry("inactiveBackground", QColor(224, 223, 222))); addColorDef(preproc, "INACTIVE_FOREGROUND", g.readEntry("inactiveBackground", QColor(224, 223, 222))); addColorDef(preproc, "ACTIVE_BACKGROUND" , g.readEntry("activeBackground", QColor(48, 174, 232))); addColorDef(preproc, "ACTIVE_FOREGROUND" , g.readEntry("activeBackground", QColor(48, 174, 232))); //--------------------------------------------------------------- tmpFile.write( preproc.toLatin1(), preproc.length() ); QStringList list; const QStringList adPaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kdisplay/app-defaults/"), QStandardPaths::LocateDirectory); for (QStringList::ConstIterator it = adPaths.constBegin(); it != adPaths.constEnd(); ++it) { QDir dSys( *it ); if ( dSys.exists() ) { dSys.setFilter( QDir::Files ); dSys.setSorting( QDir::Name ); dSys.setNameFilters(QStringList(QStringLiteral("*.ad"))); list += dSys.entryList(); } } for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) copyFile(tmpFile, QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdisplay/app-defaults/"+(*it)), true); } // Merge ~/.Xresources or fallback to ~/.Xdefaults QString homeDir = QDir::homePath(); QString xResources = homeDir + "/.Xresources"; // very primitive support for ~/.Xresources by appending it if ( QFile::exists( xResources ) ) copyFile(tmpFile, xResources, true); else copyFile(tmpFile, homeDir + "/.Xdefaults", true); // Export the Xcursor theme & size settings KConfigGroup mousecfg(KSharedConfig::openConfig( QStringLiteral("kcminputrc") ), "Mouse" ); QString theme = mousecfg.readEntry("cursorTheme", QString()); QString size = mousecfg.readEntry("cursorSize", QString()); QString contents; if (!theme.isNull()) contents = "Xcursor.theme: " + theme + '\n'; if (!size.isNull()) contents += "Xcursor.size: " + size + '\n'; if (exportXftSettings) { contents += QLatin1String("Xft.antialias: "); if(generalCfgGroup.readEntry("XftAntialias", true)) contents += QLatin1String("1\n"); else contents += QLatin1String("0\n"); QString hintStyle = generalCfgGroup.readEntry("XftHintStyle", "hintslight"); contents += QLatin1String("Xft.hinting: "); if(hintStyle.isEmpty()) contents += QLatin1String("-1\n"); else { if(hintStyle!=QLatin1String("hintnone")) contents += QLatin1String("1\n"); else contents += QLatin1String("0\n"); contents += "Xft.hintstyle: " + hintStyle + '\n'; } QString subPixel = generalCfgGroup.readEntry("XftSubPixel", "rgb"); if(!subPixel.isEmpty()) contents += "Xft.rgba: " + subPixel + '\n'; KConfig _cfgfonts( QStringLiteral("kcmfonts") ); KConfigGroup cfgfonts(&_cfgfonts, "General"); int dpi; //even though this sets up the X rdb, we want to use the value the //user has set to use when under wayland - as X apps will be scaled by the compositor if (KWindowSystem::isPlatformWayland()) { dpi = cfgfonts.readEntry( "forceFontDPIWayland", 0); if (dpi == 0) { //with wayland we want xwayland to run at 96 dpi (unless set otherwise) as we have wayland scaling on top dpi = 96; } } else { dpi = cfgfonts.readEntry( "forceFontDPI", 0); } if( dpi != 0 ) contents += "Xft.dpi: " + QString::number(dpi) + '\n'; else { KProcess proc; proc << QStringLiteral("xrdb") << QStringLiteral("-quiet") << QStringLiteral("-remove") << QStringLiteral("-nocpp"); proc.start(); if (proc.waitForStarted()) { proc.write( QByteArray( "Xft.dpi\n" ) ); proc.closeWriteChannel(); proc.waitForFinished(); } } } if (contents.length() > 0) tmpFile.write( contents.toLatin1(), contents.length() ); tmpFile.flush(); KProcess proc; #ifndef NDEBUG proc << QStringLiteral("xrdb") << QStringLiteral("-merge") << tmpFile.fileName(); #else proc << "xrdb" << "-quiet" << "-merge" << tmpFile.fileName(); #endif proc.execute(); applyGtkStyles(exportColors, 1); applyGtkStyles(exportColors, 2); /* Qt exports */ if ( exportQtColors || exportQtSettings ) { QSettings* settings = new QSettings(QStringLiteral("Trolltech")); if ( exportQtColors ) applyQtColors( kglobalcfg, *settings, newPal ); // For kcmcolors if ( exportQtSettings ) applyQtSettings( kglobalcfg, *settings ); // For kcmstyle delete settings; - QApplication::flush(); + QCoreApplication::processEvents(); #if HAVE_X11 if (qApp->platformName() == QLatin1String("xcb")) { // We let KIPC take care of ourselves, as we are in a KDE app with // QApp::setDesktopSettingsAware(false); // Instead of calling QApp::x11_apply_settings() directly, we instead // modify the timestamp which propagates the settings changes onto // Qt-only apps without adversely affecting ourselves. // Cheat and use the current timestamp, since we just saved to qtrc. QDateTime settingsstamp = QDateTime::currentDateTime(); static Atom qt_settings_timestamp = 0; if (!qt_settings_timestamp) { QString atomname(QStringLiteral("_QT_SETTINGS_TIMESTAMP_")); atomname += XDisplayName( nullptr ); // Use the $DISPLAY envvar. qt_settings_timestamp = XInternAtom( QX11Info::display(), atomname.toLatin1(), False); } QBuffer stamp; QDataStream s(&stamp.buffer(), QIODevice::WriteOnly); s << settingsstamp; XChangeProperty( QX11Info::display(), QX11Info::appRootWindow(), qt_settings_timestamp, qt_settings_timestamp, 8, PropModeReplace, (unsigned char*) stamp.buffer().data(), stamp.buffer().size() ); QApplication::flush(); } #endif } //Legacy support: //Try to sync kde4 settings with ours Kdelibs4Migration migration; //kf5 congig groups for general and icons KConfigGroup generalGroup(kglobalcfg, "General"); KConfigGroup iconsGroup(kglobalcfg, "Icons"); const QString colorSchemeName = generalGroup.readEntry("ColorScheme", QString()); //if no valid color scheme saved, something weird is going on, abort if (colorSchemeName.isEmpty()) { return; } QString colorSchemeSrcFile; if (colorSchemeName != QLatin1String("Default")) { //fix filename, copied from ColorsCM::saveScheme() QString colorSchemeFilename = colorSchemeName; colorSchemeFilename.remove('\''); // So Foo's does not become FooS QRegExp fixer(QStringLiteral("[\\W,.-]+(.?)")); int offset; while ((offset = fixer.indexIn(colorSchemeFilename)) >= 0) colorSchemeFilename.replace(offset, fixer.matchedLength(), fixer.cap(1).toUpper()); colorSchemeFilename.replace(0, 1, colorSchemeFilename.at(0).toUpper()); //clone the color scheme colorSchemeSrcFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "color-schemes/" + colorSchemeFilename + ".colors"); const QString dest = migration.saveLocation("data", QStringLiteral("color-schemes")) + colorSchemeName + ".colors"; QFile::remove(dest); QFile::copy(colorSchemeSrcFile, dest); } //Apply the color scheme QString configFilePath = migration.saveLocation("config") + "kdeglobals"; if (configFilePath.isEmpty()) { return; } KConfig kde4config(configFilePath, KConfig::SimpleConfig); KConfigGroup kde4generalGroup(&kde4config, "General"); kde4generalGroup.writeEntry("ColorScheme", colorSchemeName); //fonts QString font = generalGroup.readEntry("font", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("font", font); } font = generalGroup.readEntry("desktopFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("desktopFont", font); } font = generalGroup.readEntry("menuFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("menuFont", font); } font = generalGroup.readEntry("smallestReadableFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("smallestReadableFont", font); } font = generalGroup.readEntry("taskbarFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("taskbarFont", font); } font = generalGroup.readEntry("toolBarFont", QString()); if (!font.isEmpty()) { kde4generalGroup.writeEntry("toolBarFont", font); } //TODO: does exist any way to check if a qt4 widget style is present from a qt5 app? //kde4generalGroup.writeEntry("widgetStyle", "qtcurve"); kde4generalGroup.sync(); KConfigGroup kde4IconGroup(&kde4config, "Icons"); QString iconTheme = iconsGroup.readEntry("Theme", QString()); if (!iconTheme.isEmpty()) { kde4IconGroup.writeEntry("Theme", iconTheme); } kde4IconGroup.sync(); if (!colorSchemeSrcFile.isEmpty()) { //copy all the groups in the color scheme in kdeglobals KSharedConfigPtr kde4ColorConfig = KSharedConfig::openConfig(colorSchemeSrcFile, KConfig::SimpleConfig); foreach (const QString &grp, kde4ColorConfig->groupList()) { KConfigGroup cg(kde4ColorConfig, grp); KConfigGroup cg2(&kde4config, grp); cg.copyTo(&cg2); } } //widgets settings KConfigGroup kglobals4(&kde4config, "KDE"); kglobals4.writeEntry("ShowIconsInMenuItems", kglobals.readEntry("ShowIconsInMenuItems", true)); kglobals4.writeEntry("ShowIconsOnPushButtons", kglobals.readEntry("ShowIconsOnPushButtons", true)); kglobals4.writeEntry("contrast", kglobals.readEntry("contrast", 4)); //FIXME: this should somehow check if the kde4 version of the style is installed kde4generalGroup.writeEntry("widgetStyle", kglobals.readEntry("widgetStyle", "breeze")); //toolbar style KConfigGroup toolbars4(&kde4config, "Toolbar style"); KConfigGroup toolbars5(kglobalcfg, "Toolbar style"); toolbars4.writeEntry("ToolButtonStyle", toolbars5.readEntry("ToolButtonStyle", "TextBesideIcon")); toolbars4.writeEntry("ToolButtonStyleOtherToolbars", toolbars5.readEntry("ToolButtonStyleOtherToolbars", "TextBesideIcon")); if (exportGtkColors) { saveGtkColors(); } } diff --git a/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp index 09a884713..724ae4c73 100644 --- a/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp +++ b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp @@ -1,423 +1,423 @@ /* * Copyright (C) 2019 Atul Bisht * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "libinputtouchpad.h" #include "logging.h" #include #include #include #include #include #include const Parameter libinputProperties[] = { /* libinput disable supports property */ {"supportsDisableEvents", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_AVAILABLE, 8, 0}, {"enabled", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED, 8, 0}, {"enabledDefault", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT, 8, 0}, /* LeftHandSupport */ {"leftHandedEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_LEFT_HANDED_DEFAULT, 8, 0}, {"leftHanded", PT_INT, 0, 1, LIBINPUT_PROP_LEFT_HANDED, 8, 0}, /* Disable on external mouse */ {"supportsDisableEventsOnExternalMouse",PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_AVAILABLE, 8, 1}, {"disableEventsOnExternalMouse", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED, 8, 1}, {"disableEventsOnExternalMouseDefault", PT_INT, 0, 1, LIBINPUT_PROP_SENDEVENTS_ENABLED_DEFAULT, 8, 1}, /* Disable while typing */ {"disableWhileTypingEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_DISABLE_WHILE_TYPING_DEFAULT, 8, 0}, {"disableWhileTyping", PT_INT, 0, 1, LIBINPUT_PROP_DISABLE_WHILE_TYPING, 8, 0}, /* Middle Emulation */ {"middleEmulationEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED_DEFAULT, 8, 0}, {"middleEmulation", PT_INT, 0, 1, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, 8, 0}, /* This is a boolean for all three fingers, no per-finger config */ {"tapToClick", PT_INT, 0, 1, LIBINPUT_PROP_TAP, 8, 0}, {"tapToClickEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DEFAULT, 8, 0}, /* LMR */ {"lrmTapButtonMapEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT, 8, 0}, {"lrmTapButtonMap", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP, 8, 0}, {"lmrTapButtonMapEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP_DEFAULT, 8, 1}, {"lmrTapButtonMap", PT_INT, 0, 1, LIBINPUT_PROP_TAP_BUTTONMAP, 8, 1}, /* Tap and Drag Enabled */ {"tapAndDragEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_DEFAULT, 8, 0}, {"tapAndDrag", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG, 8, 0}, /* Tap and Drag Lock Enabled */ {"tapDragLockEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_LOCK_DEFAULT, 8, 0}, {"tapDragLock", PT_INT, 0, 1, LIBINPUT_PROP_TAP_DRAG_LOCK, 8, 0}, /* libinput normalizes the accel to -1/1 */ {"defaultPointerAcceleration", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL_DEFAULT, 0 /*float */, 0}, {"pointerAcceleration", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL, 0 /*float */, 0}, /* Libinput Accel Profile */ {"supportsPointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, 8, 0}, {"defaultPointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT, 8, 0}, {"pointerAccelerationProfileAdaptive", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, 8, 0}, {"supportsPointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, 8, 1}, {"defaultPointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED_DEFAULT, 8, 1}, {"pointerAccelerationProfileFlat", PT_BOOL, 0, 1, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, 8, 1}, /* Natural Scrolling */ {"naturalScrollEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL_DEFAULT, 8, 0}, {"naturalScroll", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL, 8, 0}, /* Horizontal scrolling */ {"horizontalScrolling", PT_INT, 0, 1, LIBINPUT_PROP_HORIZ_SCROLL_ENABLED, 8, 0}, /* Two-Finger Scrolling */ {"supportsScrollTwoFinger", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 0}, {"scrollTwoFingerEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 0}, {"scrollTwoFinger", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 0}, /* Edge Scrolling */ {"supportsScrollEdge", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 1}, {"scrollEdgeEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 1}, {"scrollEdge", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 1}, /* scroll on button */ {"supportsScrollOnButtonDown", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, 8, 2}, {"scrollOnButtonDownEnabledByDefault", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED_DEFAULT, 8, 2}, {"scrollOnButtonDown", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 2}, /* Scroll Button for scroll on button Down */ {"defaultScrollButton", PT_INT, 0, INT_MAX, LIBINPUT_PROP_SCROLL_BUTTON_DEFAULT, 32, 0}, {"scrollButton", PT_INT, 0, INT_MAX, LIBINPUT_PROP_SCROLL_BUTTON, 32, 0}, /* Click Methods */ {"supportsClickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHODS_AVAILABLE, 8, 0}, {"defaultClickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT, 8, 0}, {"clickMethodAreas", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED, 8, 0}, {"supportsClickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHODS_AVAILABLE, 8, 1}, {"defaultClickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED_DEFAULT, 8, 1}, {"clickMethodClickfinger", PT_INT, 0, 1, LIBINPUT_PROP_CLICK_METHOD_ENABLED, 8, 1}, /* libinput doesn't have a separate toggle for horiz scrolling */ { nullptr, PT_INT, 0, 0, nullptr, 0, 0 } }; Qt::MouseButtons maskBtns(Display *display, XIButtonClassInfo *buttonInfo) { Qt::MouseButtons buttons = Qt::NoButton; for (int i = 0; i < buttonInfo->num_buttons; ++i) { QByteArray reply = XGetAtomName(display, buttonInfo->labels[i]); if (reply == BTN_LABEL_PROP_BTN_LEFT) { buttons |= Qt::LeftButton; } if (reply == BTN_LABEL_PROP_BTN_RIGHT) { buttons |= Qt::RightButton; } if (reply == BTN_LABEL_PROP_BTN_MIDDLE) { buttons |= Qt::MiddleButton; } if (reply == BTN_LABEL_PROP_BTN_SIDE) { buttons |= Qt::ExtraButton1; } if (reply == BTN_LABEL_PROP_BTN_EXTRA) { buttons |= Qt::ExtraButton2; } if (reply == BTN_LABEL_PROP_BTN_FORWARD) { buttons |= Qt::ForwardButton; } if (reply == BTN_LABEL_PROP_BTN_BACK) { buttons |= Qt::BackButton; } if (reply == BTN_LABEL_PROP_BTN_TASK) { buttons |= Qt::TaskButton; } } return buttons; } LibinputTouchpad::LibinputTouchpad(Display *display, int deviceId): LibinputCommon(), XlibTouchpad(display, deviceId) { loadSupportedProperties(libinputProperties); int nDevices = 0; XIDeviceInfo *deviceInfo = XIQueryDevice(m_display, m_deviceId, &nDevices); m_name = deviceInfo->name; for (int i = 0; i < deviceInfo->num_classes; ++i) { XIAnyClassInfo *classInfo = deviceInfo->classes[i]; if (classInfo->type == XIButtonClass) { XIButtonClassInfo *btnInfo = (XIButtonClassInfo*) classInfo; m_supportedButtons.avail = true; m_supportedButtons.set(maskBtns(m_display, btnInfo)); } if (classInfo->type == XITouchClass) { XITouchClassInfo *touchInfo = (XITouchClassInfo*) classInfo; m_tapFingerCount.avail = true; m_tapFingerCount.set(touchInfo->num_touches); } } XIFreeDeviceInfo(deviceInfo); /* FingerCount cannot be zero */ if (!m_tapFingerCount.val) { m_tapFingerCount.avail = true; m_tapFingerCount.set(1); } m_config = KSharedConfig::openConfig(QStringLiteral("touchpadxlibinputrc")); } bool LibinputTouchpad::getConfig() { bool success = true; success &= valueLoader(m_supportsDisableEvents); success &= valueLoader(m_enabled); success &= valueLoader(m_enabledDefault); success &= valueLoader(m_tapToClickEnabledByDefault); success &= valueLoader(m_tapToClick); success &= valueLoader(m_lrmTapButtonMapEnabledByDefault); success &= valueLoader(m_lrmTapButtonMap); success &= valueLoader(m_lmrTapButtonMapEnabledByDefault); success &= valueLoader(m_lmrTapButtonMap); success &= valueLoader(m_tapAndDragEnabledByDefault); success &= valueLoader(m_tapAndDrag); success &= valueLoader(m_tapDragLockEnabledByDefault); success &= valueLoader(m_tapDragLock); success &= valueLoader(m_leftHandedEnabledByDefault); success &= valueLoader(m_leftHanded); success &= valueLoader(m_supportsDisableEventsOnExternalMouse); success &= valueLoader(m_disableEventsOnExternalMouse); success &= valueLoader(m_disableEventsOnExternalMouseDefault); success &= valueLoader(m_disableWhileTypingEnabledByDefault); success &= valueLoader(m_disableWhileTyping); success &= valueLoader(m_middleEmulationEnabledByDefault); success &= valueLoader(m_middleEmulation); success &= valueLoader(m_defaultPointerAcceleration); success &= valueLoader(m_pointerAcceleration); success &= valueLoader(m_supportsPointerAccelerationProfileFlat); success &= valueLoader(m_defaultPointerAccelerationProfileFlat); success &= valueLoader(m_pointerAccelerationProfileFlat); success &= valueLoader(m_supportsPointerAccelerationProfileAdaptive); success &= valueLoader(m_defaultPointerAccelerationProfileAdaptive); success &= valueLoader(m_pointerAccelerationProfileAdaptive); success &= valueLoader(m_naturalScrollEnabledByDefault); success &= valueLoader(m_naturalScroll); success &= valueLoader(m_horizontalScrolling); success &= valueLoader(m_supportsScrollTwoFinger); success &= valueLoader(m_scrollTwoFingerEnabledByDefault); success &= valueLoader(m_isScrollTwoFinger); success &= valueLoader(m_supportsScrollEdge); success &= valueLoader(m_scrollEdgeEnabledByDefault); success &= valueLoader(m_isScrollEdge); success &= valueLoader(m_supportsScrollOnButtonDown); success &= valueLoader(m_scrollOnButtonDownEnabledByDefault); success &= valueLoader(m_isScrollOnButtonDown); success &= valueLoader(m_defaultScrollButton); success &= valueLoader(m_scrollButton); // click methods success &= valueLoader(m_supportsClickMethodAreas); success &= valueLoader(m_supportsClickMethodClickfinger); success &= valueLoader(m_defaultClickMethodAreas); success &= valueLoader(m_defaultClickMethodClickfinger); success &= valueLoader(m_clickMethodAreas); success &= valueLoader(m_clickMethodClickfinger); return success; } bool LibinputTouchpad::applyConfig() { QVector msgs; msgs << valueWriter(m_enabled) << valueWriter(m_tapToClick) << valueWriter(m_lrmTapButtonMap) << valueWriter(m_lmrTapButtonMap) << valueWriter(m_tapAndDrag) << valueWriter(m_tapDragLock) << valueWriter(m_leftHanded) << valueWriter(m_disableWhileTyping) << valueWriter(m_middleEmulation) << valueWriter(m_pointerAcceleration) << valueWriter(m_pointerAccelerationProfileFlat) << valueWriter(m_pointerAccelerationProfileAdaptive) << valueWriter(m_naturalScroll) << valueWriter(m_horizontalScrolling) << valueWriter(m_isScrollTwoFinger) << valueWriter(m_isScrollEdge) << valueWriter(m_isScrollOnButtonDown) << valueWriter(m_scrollButton) << valueWriter(m_clickMethodAreas) << valueWriter(m_clickMethodClickfinger); bool success = true; QString error_msg; for (QString m : msgs) { if (!m.isNull()) { qCCritical(KCM_TOUCHPAD) << "in error:" << m; if (!success) { error_msg.append("\n"); } error_msg.append(m); success = false; } } if (!success) { qCCritical(KCM_TOUCHPAD) << error_msg; } flush(); return success; } bool LibinputTouchpad::getDefaultConfig() { m_enabled.set(m_enabledDefault); m_tapToClick.set(m_tapToClickEnabledByDefault); m_lrmTapButtonMap.set(m_lrmTapButtonMap); m_lmrTapButtonMap.set(m_lmrTapButtonMapEnabledByDefault); m_tapAndDrag.set(m_tapAndDragEnabledByDefault); m_tapDragLock.set(m_tapDragLockEnabledByDefault); m_leftHanded.set(m_leftHandedEnabledByDefault); m_disableEventsOnExternalMouse.set(m_disableEventsOnExternalMouseDefault); m_disableWhileTyping.set(m_disableWhileTypingEnabledByDefault); m_middleEmulation.set(m_middleEmulationEnabledByDefault); m_pointerAcceleration.set(m_defaultPointerAcceleration); m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat); m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive); m_naturalScroll.set(m_naturalScrollEnabledByDefault); m_horizontalScrolling.set(true); m_isScrollTwoFinger.set(m_scrollTwoFingerEnabledByDefault); m_isScrollEdge.set(m_scrollEdgeEnabledByDefault); m_isScrollOnButtonDown.set(m_scrollOnButtonDownEnabledByDefault); m_scrollButton.set(m_defaultScrollButton); m_clickMethodAreas.set(m_defaultClickMethodAreas); m_clickMethodClickfinger.set(m_defaultClickMethodClickfinger); return true; } bool LibinputTouchpad::isChangedConfig() { bool changed = m_enabled.changed() || m_tapToClick.changed() || m_lrmTapButtonMap.changed() || m_lmrTapButtonMap.changed() || m_tapAndDrag.changed() || m_tapDragLock.changed() || m_leftHanded.changed() || m_disableEventsOnExternalMouse.changed() || m_disableWhileTyping.changed() || m_middleEmulation.changed() || m_pointerAcceleration.changed() || m_pointerAccelerationProfileFlat.changed() || m_pointerAccelerationProfileAdaptive.changed() || m_naturalScroll.changed() || m_horizontalScrolling.changed() || m_isScrollTwoFinger.changed() || m_isScrollEdge.changed() || m_isScrollOnButtonDown.changed() || m_scrollButton.changed() || m_clickMethodAreas.changed() || m_clickMethodClickfinger.changed(); return changed; } int LibinputTouchpad::touchpadOff() { return m_enabled.val; } XcbAtom &LibinputTouchpad::touchpadOffAtom() { return *m_atoms[QLatin1String(LIBINPUT_PROP_SENDEVENTS_ENABLED)].data(); } template bool LibinputTouchpad::valueLoader(Prop &prop) { - const Parameter *p = findParameter(QString::fromAscii(prop.name)); + const Parameter *p = findParameter(QString::fromLatin1(prop.name)); if (!p) { - qCCritical(KCM_TOUCHPAD) << "Error on read of " << QString::fromAscii(prop.name); + qCCritical(KCM_TOUCHPAD) << "Error on read of " << QString::fromLatin1(prop.name); } QVariant reply = getParameter(p); if (!reply.isValid()) { prop.avail = false; return true; } prop.avail = true; auto touchpadConfig = m_config->group(m_name); const T replyValue = valueLoaderPart(reply); const T loadedValue = touchpadConfig.readEntry(QString(prop.name), replyValue); prop.old = replyValue; prop.val = loadedValue; return true; } template QString LibinputTouchpad::valueWriter(const Prop &prop) { const Parameter *p = findParameter(QString::fromAscii(prop.name)); if (!p || !prop.changed()) { return QString(); } bool error = !setParameter( p, prop.val); if (error) { qCCritical(KCM_TOUCHPAD) << "Cannot set property " + QString::fromAscii(prop.name); return QStringLiteral("Cannot set property ") + QString::fromAscii(prop.name); } auto touchpadConfig = m_config->group(m_name); touchpadConfig.writeEntry(QString(prop.name), prop.val); touchpadConfig.config()->sync(); return QString(); }