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+=""+Misc::contractHome((*fit).path())+" |
";
else
tip+=""+Misc::contractHome((*fit).path())+" |
";
if(allFiles.count()>constMaxFiles)
tip+=""+i18n("...plus %1 more", allFiles.count()-constMaxFiles)+" |
";
tip+="
";
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+=""+Misc::contractHome((*fit).path())+" |
";
else
tip+=""+Misc::contractHome((*fit).path() )+" |
";
if(files.count()>constMaxFiles)
tip+=""+i18n("...plus %1 more", files.count()-constMaxFiles)+" |
";
tip+="
";
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("") + 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();
}