diff --git a/kcms/fonts/CMakeLists.txt b/kcms/fonts/CMakeLists.txt --- a/kcms/fonts/CMakeLists.txt +++ b/kcms/fonts/CMakeLists.txt @@ -10,13 +10,14 @@ include_directories(../kfontinst/lib) -set(kcm_fonts_PART_SRCS ../krdb/krdb.cpp previewrenderengine.cpp previewimageprovider.cpp fonts.cpp ../kfontinst/lib/FcEngine.cpp) +set(kcm_fonts_PART_SRCS ../krdb/krdb.cpp previewrenderengine.cpp previewimageprovider.cpp fonts.cpp fontsaasettings.cpp ../kfontinst/lib/FcEngine.cpp) if(X11_FOUND) set(kcm_fonts_PART_SRCS ${kcm_fonts_PART_SRCS} ${libkxftconfig_SRCS}) endif() -kconfig_add_kcfg_files(kcm_fonts_PART_SRCS fontssettings.kcfgc GENERATE_MOC) +kconfig_add_kcfg_files(kcm_fonts_PART_SRCS fontssettings.kcfgc fontsaasettingsbase.kcfgc GENERATE_MOC) + add_library(kcm_fonts MODULE ${kcm_fonts_PART_SRCS}) target_link_libraries(kcm_fonts Qt5::DBus Qt5::Xml KF5::KCMUtils KF5::I18n KF5::KDELibs4Support ${FREETYPE_LIBRARIES} kfontinst) diff --git a/kcms/fonts/fonts.h b/kcms/fonts/fonts.h --- a/kcms/fonts/fonts.h +++ b/kcms/fonts/fonts.h @@ -33,139 +33,55 @@ #include -#include "kxftconfig.h" - class FontsSettings; - -class FontAASettings : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QAbstractItemModel *subPixelOptionsModel READ subPixelOptionsModel CONSTANT) - Q_PROPERTY(int subPixelCurrentIndex READ subPixelCurrentIndex WRITE setSubPixelCurrentIndex NOTIFY subPixelCurrentIndexChanged) - Q_PROPERTY(QAbstractItemModel *hintingOptionsModel READ hintingOptionsModel CONSTANT) - Q_PROPERTY(int hintingCurrentIndex READ hintingCurrentIndex WRITE setHintingCurrentIndex NOTIFY hintingCurrentIndexChanged) - - Q_PROPERTY(bool exclude READ exclude WRITE setExclude NOTIFY excludeChanged) - Q_PROPERTY(int excludeTo READ excludeTo WRITE setExcludeTo NOTIFY excludeToChanged) - Q_PROPERTY(int excludeFrom READ excludeFrom WRITE setExcludeFrom NOTIFY excludeFromChanged) - Q_PROPERTY(bool antiAliasing READ antiAliasing WRITE setAntiAliasing NOTIFY aliasingChanged) - Q_PROPERTY(int dpi READ dpi WRITE setDpi NOTIFY dpiChanged) - - struct State - { - bool exclude; - int excludeFrom; - int excludeTo; - int antiAliasing; - bool antiAliasingHasLocalConfig; - bool subPixelHasLocalConfig; - bool hintingHasLocalConfig; - int dpi; - int subPixel; - int hinting; - - bool operator==(const State& other) const; - bool operator!=(const State& other) const; - }; - -public: - enum AASetting { AAEnabled, AASystem, AADisabled }; -#if defined(HAVE_FONTCONFIG) && HAVE_X11 - FontAASettings(QObject *parent); - - bool save(KXftConfig::AntiAliasing::State aaState); - void load(); - void defaults(); - QAbstractItemModel* subPixelOptionsModel() { return m_subPixelOptionsModel; } - QAbstractItemModel* hintingOptionsModel() { return m_hintingOptionsModel; } - - void setExclude(bool exclude); - bool exclude() const; - - void setExcludeTo(int excludeTo); - int excludeTo() const; - - void setExcludeFrom(int excludeFrom); - int excludeFrom() const; - - void setAntiAliasing(bool antiAliasing); - bool antiAliasing() const; - - bool antiAliasingNeedsSave() const; - bool subPixelNeedsSave() const; - bool hintingNeedsSave() const; - - void setDpi(const int &dpi); - int dpi() const; - - int subPixelCurrentIndex(); - void setSubPixelCurrentIndex(int idx); - void setSubPixel(int idx); - int hintingCurrentIndex(); - void setHintingCurrentIndex(int idx); - void setHinting(int idx); - - bool needsSave() const; - bool isDefaults() const; - -#endif - -Q_SIGNALS: - void excludeChanged(); - void excludeToChanged(); - void excludeFromChanged(); - void antiAliasingChanged(); - void aliasingChangeApplied(); - void aliasingChanged(); - void dpiChanged(); - void subPixelCurrentIndexChanged(); - void hintingCurrentIndexChanged(); - -#if defined(HAVE_FONTCONFIG) && HAVE_X11 -private: - State m_state; - State m_originalState; - QStandardItemModel *m_subPixelOptionsModel; - QStandardItemModel *m_hintingOptionsModel; -#endif -}; +class FontsAASettings; /** * The Desktop/fonts tab in kcontrol. */ class KFonts : public KQuickAddons::ManagedConfigModule { Q_OBJECT Q_PROPERTY(FontsSettings *fontsSettings READ fontsSettings CONSTANT) - Q_PROPERTY(QObject *fontAASettings READ fontAASettings CONSTANT) + Q_PROPERTY(FontsAASettings *fontsAASettings READ fontsAASettings CONSTANT) + Q_PROPERTY(QAbstractItemModel *subPixelOptionsModel READ subPixelOptionsModel CONSTANT) + Q_PROPERTY(int subPixelCurrentIndex READ subPixelCurrentIndex WRITE setSubPixelCurrentIndex NOTIFY subPixelCurrentIndexChanged) + Q_PROPERTY(QAbstractItemModel *hintingOptionsModel READ hintingOptionsModel CONSTANT) + Q_PROPERTY(int hintingCurrentIndex READ hintingCurrentIndex WRITE setHintingCurrentIndex NOTIFY hintingCurrentIndexChanged) public: KFonts(QObject *parent, const QVariantList &); ~KFonts() override; FontsSettings *fontsSettings() const; + FontsAASettings *fontsAASettings() const; - QObject* fontAASettings() { return m_fontAASettings; } + int subPixelCurrentIndex() const; + void setHintingCurrentIndex(int idx); + int hintingCurrentIndex() const; + void setSubPixelCurrentIndex(int idx); + QAbstractItemModel *subPixelOptionsModel() const; + QAbstractItemModel *hintingOptionsModel() const; public Q_SLOTS: void load() override; void save() override; - void defaults() override; Q_INVOKABLE void adjustAllFonts(); Q_SIGNALS: void fontsHaveChanged(); + void hintingCurrentIndexChanged(); + void subPixelCurrentIndexChanged(); + void aliasingChangeApplied(); private: - bool isSaveNeeded() const override; - bool isDefaults() const override; QFont applyFontDiff(const QFont &fnt, const QFont &newFont, int fontDiffFlags); void setNearestExistingFonts(); FontsSettings *m_settings; - - FontAASettings *m_fontAASettings; + FontsAASettings *m_settingsAA; + QStandardItemModel *m_subPixelOptionsModel; + QStandardItemModel *m_hintingOptionsModel; }; #endif diff --git a/kcms/fonts/fonts.cpp b/kcms/fonts/fonts.cpp --- a/kcms/fonts/fonts.cpp +++ b/kcms/fonts/fonts.cpp @@ -47,8 +47,10 @@ #include "../krdb/krdb.h" #include "previewimageprovider.h" +#include "kxftconfig.h" #include "fontssettings.h" +#include "fontsaasettings.h" /**** DLL Interface ****/ K_PLUGIN_FACTORY_WITH_JSON(KFontsFactory, "kcm_fonts.json", registerPlugin();) @@ -106,430 +108,36 @@ return result; } -/**** FontAASettings ****/ -#if defined(HAVE_FONTCONFIG) && HAVE_X11 -FontAASettings::FontAASettings(QObject *parent) - : QObject(parent) - , m_state() - , m_originalState() - , m_subPixelOptionsModel(new QStandardItemModel(this)) - , m_hintingOptionsModel(new QStandardItemModel(this)) -{ - m_state.subPixel = KXftConfig::SubPixel::None; - for (int t = KXftConfig::SubPixel::None; t <= KXftConfig::SubPixel::Vbgr; ++t) { - QStandardItem *item = new QStandardItem(KXftConfig::description((KXftConfig::SubPixel::Type)t)); - m_subPixelOptionsModel->appendRow(item); - } - - m_state.hinting = KXftConfig::Hint::None; - for (int s = KXftConfig::Hint::None; s <= KXftConfig::Hint::Full; ++s) { - QStandardItem * item = new QStandardItem(KXftConfig::description((KXftConfig::Hint::Style)s)); - m_hintingOptionsModel->appendRow(item); - } -} - -void FontAASettings::load() -{ - double from, to; - KXftConfig xft; - - if (xft.getExcludeRange(from, to)) { - m_state.excludeFrom = from; - m_state.excludeTo = to; - setExclude(true); - } else { - m_state.excludeFrom = 8; - m_state.excludeTo = 15; - setExclude(false); - } - m_originalState.exclude = m_state.exclude; - m_originalState.excludeFrom = m_state.excludeFrom; - m_originalState.excludeTo = m_state.excludeTo; - excludeToChanged(); - excludeFromChanged(); - - // start with empty subpixel type - KXftConfig::SubPixel::Type spType = KXftConfig::SubPixel::NotSet; - // get subpixel type from config - xft.getSubPixelType(spType); - m_originalState.subPixel = spType; - // if it is not set, we set it to rgb - if (spType == KXftConfig::SubPixel::NotSet) { - spType = KXftConfig::SubPixel::Rgb; - } - setSubPixel(spType); - m_state.subPixelHasLocalConfig = xft.subPixelTypeHasLocalConfig(); - - // start with empty hint style - KXftConfig::Hint::Style hStyle = KXftConfig::Hint::NotSet; - // get value from config; - xft.getHintStyle(hStyle); - m_originalState.hinting = hStyle; - // if it is not set, we set it to slight hinting - if (hStyle == KXftConfig::Hint::NotSet) { - hStyle = KXftConfig::Hint::Slight; - } - setHinting(hStyle); - m_state.hintingHasLocalConfig = xft.hintStyleHasLocalConfig(); - - KConfig _cfgfonts("kcmfonts"); - KConfigGroup cfgfonts(&_cfgfonts, "General"); - - int dpicfg; - if (KWindowSystem::isPlatformWayland()) { - dpicfg = cfgfonts.readEntry("forceFontDPIWayland", 0); - } else { - dpicfg = cfgfonts.readEntry("forceFontDPI", 0); - } - - if (dpicfg <= 0) { - m_originalState.dpi = 0; - } else { - m_originalState.dpi = dpicfg; - }; - - setDpi(dpicfg); - - KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); - KConfigGroup cg(config, "General"); - - if (cfgfonts.readEntry("dontChangeAASettings", true)) { - setAntiAliasing(true); //AASystem - m_state.antiAliasingHasLocalConfig = false; - } else if (cg.readEntry("XftAntialias", true)) { - setAntiAliasing(true); //AAEnabled - m_state.antiAliasingHasLocalConfig = xft.antiAliasingHasLocalConfig(); - } else { - setAntiAliasing(false); //AADisabled - m_state.antiAliasingHasLocalConfig = xft.antiAliasingHasLocalConfig(); - } - m_originalState.antiAliasing = m_state.antiAliasing; - m_originalState.antiAliasingHasLocalConfig = m_state.antiAliasingHasLocalConfig; -} - -bool FontAASettings::save(KXftConfig::AntiAliasing::State aaState) -{ - KXftConfig xft; - - KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); - KConfigGroup grp(config, "General"); - - xft.setAntiAliasing(aaState); - if (m_state.exclude) { - xft.setExcludeRange(m_state.excludeFrom, m_state.excludeTo); - } else { - xft.setExcludeRange(0, 0); - } - - KXftConfig::SubPixel::Type spType = (KXftConfig::SubPixel::Type)m_state.subPixel; - - if (subPixelNeedsSave()) { - xft.setSubPixelType(spType); - } else { - xft.setSubPixelType(KXftConfig::SubPixel::NotSet); - } - grp.writeEntry("XftSubPixel", KXftConfig::toStr(spType)); - if (aaState == KXftConfig::AntiAliasing::NotSet) { - grp.revertToDefault("XftAntialias"); - } else { - grp.writeEntry("XftAntialias", aaState == KXftConfig::AntiAliasing::Enabled); - } - - bool mod = false; - KXftConfig::Hint::Style hStyle = (KXftConfig::Hint::Style)m_state.hinting; - - if (hintingNeedsSave()) { - xft.setHintStyle(hStyle); - } else { - xft.setHintStyle(KXftConfig::Hint::NotSet); - } - - QString hs(KXftConfig::toStr(hStyle)); - - if (hs != grp.readEntry("XftHintStyle")) { - if (KXftConfig::Hint::NotSet == hStyle) { - grp.revertToDefault("XftHintStyle"); - } else { - grp.writeEntry("XftHintStyle", hs); - } - } - mod = true; - config->sync(); - - if (!mod) { - mod = xft.changed(); - } - - xft.apply(); - - KConfig _cfgfonts("kcmfonts"); - KConfigGroup cfgfonts(&_cfgfonts, "General"); - - if (KWindowSystem::isPlatformWayland()) { - cfgfonts.writeEntry("forceFontDPIWayland", m_state.dpi); - } else { - cfgfonts.writeEntry("forceFontDPI", m_state.dpi); - } - - cfgfonts.sync(); - -#if HAVE_X11 - // if the setting is reset in the module, remove the dpi value, - // otherwise don't explicitly remove it and leave any possible system-wide value - if (m_state.dpi == 0 && m_originalState.dpi != 0 && !KWindowSystem::isPlatformWayland()) { - QProcess proc; - proc.setProcessChannelMode(QProcess::ForwardedChannels); - proc.start("xrdb", QStringList() << "-quiet" << "-remove" << "-nocpp"); - if (proc.waitForStarted()) { - proc.write(QByteArray("Xft.dpi\n")); - proc.closeWriteChannel(); - proc.waitForFinished(); - } - } -#endif - - QApplication::processEvents(); // Process font change ourselves - - // Don't overwrite global settings unless explicitly asked for - e.g. the system - // fontconfig setup may be much more complex than this module can provide. - // TODO: With AASystem the changes already made by this module should be reverted somehow. -#if defined(HAVE_FONTCONFIG) && defined (HAVE_X11) - if (mod || (m_state.antiAliasing != m_originalState.antiAliasing) || m_state.dpi != m_originalState.dpi) { - m_originalState.antiAliasing = m_state.antiAliasing; - m_originalState.dpi = m_state.dpi; - emit aliasingChangeApplied(); - } -#else -#if HAVE_X11 - if (m_state.dpi != m_originalState.dpi) { - m_originalState.dpi = m_state.dpi; - } -#endif -#endif - - m_originalState.exclude = m_state.exclude; - m_originalState.excludeTo = m_state.excludeTo; - m_originalState.excludeFrom = m_state.excludeFrom; - - m_originalState.subPixel = m_state.subPixel; - m_originalState.hinting = m_state.hinting; - - return mod; -} - -void FontAASettings::defaults() -{ - setExclude(false); - setExcludeTo(15); - setExcludeFrom(8); - setAntiAliasing(true); - m_originalState.antiAliasing = m_state.antiAliasing; - m_state.antiAliasingHasLocalConfig = false; - setDpi(0); - setSubPixel(KXftConfig::SubPixel::Rgb); - m_state.subPixelHasLocalConfig = false; - setHinting(KXftConfig::Hint::Slight); - m_state.hintingHasLocalConfig = false; -} - -#endif - -void FontAASettings::setExclude(bool exclude) -{ - if (exclude == m_state.exclude) { - return; - } - - m_state.exclude = exclude; - emit excludeChanged(); -} - -bool FontAASettings::exclude() const -{ - return m_state.exclude; -} - -void FontAASettings::setExcludeTo(int excludeTo) -{ - if (m_state.excludeTo == excludeTo) { - return; - } - - m_state.excludeTo = excludeTo; - emit excludeToChanged(); -} - -int FontAASettings::excludeTo() const -{ - return m_state.excludeTo; -} - -void FontAASettings::setExcludeFrom(int excludeFrom) -{ - if (m_state.excludeFrom == excludeFrom) { - return; - } - - m_state.excludeFrom = excludeFrom; - emit excludeFromChanged(); -} - -int FontAASettings::excludeFrom() const -{ - return m_state.excludeFrom; -} - -void FontAASettings::setAntiAliasing(bool antiAliasing) -{ - if (m_state.antiAliasing == antiAliasing) { - return; - } - - m_state.antiAliasing = antiAliasing; - emit aliasingChanged(); -} - -bool FontAASettings::antiAliasing() const -{ - return m_state.antiAliasing; -} - -bool FontAASettings::antiAliasingNeedsSave() const -{ - return m_state.antiAliasingHasLocalConfig || (m_state.antiAliasing != m_originalState.antiAliasing); -} - -bool FontAASettings::subPixelNeedsSave() const -{ - return m_state.subPixelHasLocalConfig || (m_state.subPixel != m_originalState.subPixel); -} - -bool FontAASettings::hintingNeedsSave() const -{ - return m_state.hintingHasLocalConfig || (m_state.hinting != m_originalState.hinting); -} - -void FontAASettings::setDpi(const int &dpi) -{ - if (m_state.dpi == dpi) { - return; - } - - m_state.dpi = dpi; - emit dpiChanged(); -} - -int FontAASettings::dpi() const -{ - return m_state.dpi; -} - -void FontAASettings::setSubPixel(int idx) -{ - if (m_state.subPixel == idx) { - return; - } - - m_state.subPixel = idx; - emit subPixelCurrentIndexChanged(); -} - -void FontAASettings::setSubPixelCurrentIndex(int idx) -{ - setSubPixel(KXftConfig::SubPixel::None + idx); -} - -int FontAASettings::subPixelCurrentIndex() -{ - return m_state.subPixel - KXftConfig::SubPixel::None; -} - -void FontAASettings::setHinting(int idx) -{ - if (m_state.hinting == idx) { - return; - } - - m_state.hinting = idx; - emit hintingCurrentIndexChanged(); -} - -void FontAASettings::setHintingCurrentIndex(int idx) -{ - setHinting(KXftConfig::Hint::None + idx); -} - -int FontAASettings::hintingCurrentIndex() -{ - return m_state.hinting - KXftConfig::Hint::None; -} - -bool FontAASettings::needsSave() const -{ - return m_state != m_originalState; -} - -bool FontAASettings::isDefaults() const -{ - State defaultState{}; - defaultState.exclude = false; - defaultState.excludeTo = 15; - defaultState.excludeFrom = 8; - defaultState.antiAliasing = true; - defaultState.dpi = 0; - defaultState.subPixel = KXftConfig::SubPixel::Rgb; - defaultState.hinting = KXftConfig::Hint::Slight; - return m_state == defaultState; -} - -bool FontAASettings::State::operator==(const State& other) const -{ - if ( - exclude != other.exclude - || antiAliasing != other.antiAliasing - || dpi != other.dpi - || subPixel != other.subPixel - || hinting != other.hinting - ) { - return false; - } - - if (exclude && (excludeFrom != other.excludeFrom || excludeTo != other.excludeTo)) { - return false; - } - - return true; -} - -bool FontAASettings::State::operator!=(const State& other) const -{ - return !(*this == other); -} - /**** KFonts ****/ KFonts::KFonts(QObject *parent, const QVariantList &args) : KQuickAddons::ManagedConfigModule(parent, args) , m_settings(new FontsSettings(this)) - , m_fontAASettings(new FontAASettings(this)) + , m_settingsAA(new FontsAASettings(this)) + , m_subPixelOptionsModel(new QStandardItemModel(this)) + , m_hintingOptionsModel(new QStandardItemModel(this)) { KAboutData* about = new KAboutData("kcm_fonts", i18n("Fonts"), "0.1", QString(), KAboutLicense::LGPL); about->addAuthor(i18n("Antonis Tsiapaliokas"), QString(), "antonis.tsiapaliokas@kde.org"); setAboutData(about); qmlRegisterType(); qmlRegisterType(); + qmlRegisterType(); setButtons(Apply | Default | Help); - connect(m_fontAASettings, &FontAASettings::subPixelCurrentIndexChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::hintingCurrentIndexChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::excludeChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::excludeFromChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::excludeToChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::antiAliasingChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::aliasingChanged, this, &KFonts::settingsChanged); - connect(m_fontAASettings, &FontAASettings::dpiChanged, this, &KFonts::settingsChanged); + for (KXftConfig::SubPixel::Type t : {KXftConfig::SubPixel::None, KXftConfig::SubPixel::Rgb, KXftConfig::SubPixel::Bgr, KXftConfig::SubPixel::Vrgb, KXftConfig::SubPixel::Vbgr}) { + auto item = new QStandardItem(KXftConfig::description(t)); + m_subPixelOptionsModel->appendRow(item); + } + + for (KXftConfig::Hint::Style s : {KXftConfig::Hint::None, KXftConfig::Hint::Slight, KXftConfig::Hint::Medium, KXftConfig::Hint::Full}) { + auto item = new QStandardItem(KXftConfig::description(s)); + m_hintingOptionsModel->appendRow(item); + } + connect(m_settingsAA, &FontsAASettings::hintingChanged, this, &KFonts::hintingCurrentIndexChanged); + connect(m_settingsAA, &FontsAASettings::subPixelChanged, this, &KFonts::subPixelCurrentIndexChanged); } KFonts::~KFonts() @@ -541,10 +149,19 @@ return m_settings; } -void KFonts::defaults() +FontsAASettings *KFonts::fontsAASettings() const { - ManagedConfigModule::defaults(); - m_fontAASettings->defaults(); + return m_settingsAA; +} + +QAbstractItemModel *KFonts::subPixelOptionsModel() const +{ + return m_subPixelOptionsModel; +} + +QAbstractItemModel *KFonts::hintingOptionsModel() const +{ + return m_hintingOptionsModel; } void KFonts::setNearestExistingFonts() @@ -561,7 +178,6 @@ { // first load all the settings ManagedConfigModule::load(); - m_fontAASettings->load(); // Then set the existing fonts based on those settings setNearestExistingFonts(); @@ -578,42 +194,42 @@ void KFonts::save() { - ManagedConfigModule::save(); + auto dpiItem = m_settingsAA->findItem("forceFontDPI"); + auto dpiWaylandItem = m_settingsAA->findItem("forceFontDPIWayland"); + auto antiAliasingItem = m_settingsAA->findItem("antiAliasing"); + Q_ASSERT(dpiItem && dpiWaylandItem && antiAliasingItem); + if (dpiItem->isSaveNeeded() || dpiWaylandItem->isSaveNeeded() || antiAliasingItem->isSaveNeeded()) { + emit aliasingChangeApplied(); + } - KConfig _cfgfonts("kcmfonts"); - KConfigGroup cfgfonts(&_cfgfonts, "General"); + auto forceFontDPIChanged = dpiItem->isSaveNeeded(); - FontAASettings::AASetting aaSetting = FontAASettings::AASystem; - if (m_fontAASettings->antiAliasingNeedsSave()) { - aaSetting = m_fontAASettings->antiAliasing() ? FontAASettings::AAEnabled : FontAASettings::AADisabled; - } - cfgfonts.writeEntry("dontChangeAASettings", aaSetting == FontAASettings::AASystem); - - if (aaSetting == FontAASettings::AAEnabled) { - m_fontAASettings->save(KXftConfig::AntiAliasing::Enabled); - } else if (aaSetting == FontAASettings::AADisabled) { - m_fontAASettings->save(KXftConfig::AntiAliasing::Disabled); - } else { - m_fontAASettings->save(KXftConfig::AntiAliasing::NotSet); + ManagedConfigModule::save(); + +#if HAVE_X11 + // if the setting is reset in the module, remove the dpi value, + // otherwise don't explicitly remove it and leave any possible system-wide value + if (m_settingsAA->forceFontDPI() == 0 && forceFontDPIChanged && !KWindowSystem::isPlatformWayland()) { + QProcess proc; + proc.setProcessChannelMode(QProcess::ForwardedChannels); + proc.start("xrdb", QStringList() << "-quiet" << "-remove" << "-nocpp"); + if (proc.waitForStarted()) { + proc.write(QByteArray("Xft.dpi\n")); + proc.closeWriteChannel(); + proc.waitForFinished(); + } } + QApplication::processEvents(); +#endif + KGlobalSettings::self()->emitChange(KGlobalSettings::FontChanged); runRdb(KRdbExportXftSettings | KRdbExportGtkTheme); emit fontsHaveChanged(); } -bool KFonts::isSaveNeeded() const -{ - return m_fontAASettings->needsSave(); -} - -bool KFonts::isDefaults() const -{ - return m_fontAASettings->isDefaults(); -} - void KFonts::adjustAllFonts() { QFont font = m_settings->font(); @@ -663,5 +279,25 @@ return font; } +int KFonts::subPixelCurrentIndex() const +{ + return m_settingsAA->subPixel() - KXftConfig::SubPixel::None; +} + +void KFonts::setSubPixelCurrentIndex(int idx) +{ + m_settingsAA->setSubPixel(static_cast(KXftConfig::SubPixel::None + idx)); +} + +int KFonts::hintingCurrentIndex() const +{ + return m_settingsAA->hinting() - KXftConfig::Hint::None; +} + +void KFonts::setHintingCurrentIndex(int idx) +{ + m_settingsAA->setHinting(static_cast(KXftConfig::Hint::None + idx)); +} + #include "fonts.moc" diff --git a/kcms/fonts/fontsaasettings.h b/kcms/fonts/fontsaasettings.h new file mode 100644 --- /dev/null +++ b/kcms/fonts/fontsaasettings.h @@ -0,0 +1,76 @@ +/** + * Copyright 2020 Benjamin Port + * + * 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. + */ + +#ifndef FONTSAASETTINGS_H +#define FONTSAASETTINGS_H + +#include "fontsaasettingsbase.h" +#include "kxftconfig.h" + +class FontAASettingsStore; + +class FontsAASettings : public FontsAASettingsBase +{ + Q_OBJECT + + Q_PROPERTY(bool exclude READ exclude WRITE setExclude NOTIFY excludeChanged) + Q_PROPERTY(int excludeFrom READ excludeFrom WRITE setExcludeFrom NOTIFY excludeFromChanged) + Q_PROPERTY(int excludeTo READ excludeTo WRITE setExcludeTo NOTIFY excludeToChanged) + Q_PROPERTY(bool antiAliasing READ antiAliasing WRITE setAntiAliasing NOTIFY antiAliasingChanged) + Q_PROPERTY(int dpi READ dpi WRITE setDpi NOTIFY dpiChanged) + Q_PROPERTY(KXftConfig::SubPixel::Type subPixel READ subPixel WRITE setSubPixel NOTIFY subPixelChanged) + Q_PROPERTY(KXftConfig::Hint::Style hinting READ hinting WRITE setHinting NOTIFY hintingChanged) + +public: + FontsAASettings(QObject *parent = nullptr); + + bool exclude() const; + int excludeFrom() const; + int excludeTo() const; + bool antiAliasing() const; + int dpi() const; + KXftConfig::SubPixel::Type subPixel() const; + KXftConfig::Hint::Style hinting() const; + + void setExclude(bool exclude); + void setExcludeFrom(int excludeFrom); + void setExcludeTo(int excludeTo); + void setAntiAliasing(bool antiAliasing); + void setDpi(int dpi); + void setSubPixel(KXftConfig::SubPixel::Type subPixel); + void setHinting(KXftConfig::Hint::Style hinting); + +signals: + void excludeChanged(); + void excludeFromChanged(); + void excludeToChanged(); + void antiAliasingChanged(); + void dpiChanged(); + void subPixelChanged(); + void hintingChanged(); + void aliasingChangeApplied(); + +private: + FontAASettingsStore *m_fontAASettingsStore; + bool usrSave() override; + + using NotifySignalType = void (FontsAASettings::*)(); + void addItemInternal(const QByteArray &propertyName, const QVariant &defaultValue, NotifySignalType notifySignal); +}; + +#endif diff --git a/kcms/fonts/fontsaasettings.cpp b/kcms/fonts/fontsaasettings.cpp new file mode 100644 --- /dev/null +++ b/kcms/fonts/fontsaasettings.cpp @@ -0,0 +1,363 @@ +/** + * Copyright 2020 Benjamin Port + * + * 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 "fontsaasettings.h" + +#include +#include + +#include "kxftconfig.h" + +namespace { + bool defaultExclude() + { + return false; + } + + int defaultExcludeFrom() + { + return 8; + } + + int defaultExcludeTo() + { + return 15; + } + + bool defaultAntiAliasing() + { + return true; + } + + int defaultSubPixel() + { + return KXftConfig::SubPixel::Rgb; + } + + int defaultHinting() + { + return KXftConfig::Hint::Slight; + } +} + + +class FontAASettingsStore : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool exclude READ exclude WRITE setExclude) + Q_PROPERTY(int excludeFrom READ excludeFrom WRITE setExcludeFrom) + Q_PROPERTY(int excludeTo READ excludeTo WRITE setExcludeTo) + Q_PROPERTY(bool antiAliasing READ antiAliasing WRITE setAntiAliasing) + Q_PROPERTY(KXftConfig::SubPixel::Type subPixel READ subPixel WRITE setSubPixel) + Q_PROPERTY(KXftConfig::Hint::Style hinting READ hinting WRITE setHinting) +public: + FontAASettingsStore(FontsAASettings *parent = nullptr) + : QObject(parent) + , m_settings(parent) + { + load(); + } + + bool exclude() const + { + return m_exclude; + } + + void setExclude(bool exclude) + { + m_exclude = exclude; + } + + int excludeFrom() const + { + return m_excludeFrom; + } + + void setExcludeFrom(int excludeFrom) + { + m_excludeFrom = excludeFrom; + } + + int excludeTo() const + { + return m_excludeTo; + } + + void setExcludeTo(int excludeTo) + { + m_excludeTo = excludeTo; + } + + bool antiAliasing() const + { + return m_antiAliasing; + } + + void setAntiAliasing(bool antiAliasing) + { + if (antiAliasing != m_antiAliasing) { + m_antiAliasingChanged = true; + } + m_antiAliasing = antiAliasing; + } + + KXftConfig::SubPixel::Type subPixel() const + { + return m_subPixel; + } + + void setSubPixel(KXftConfig::SubPixel::Type subPixel) + { + m_subPixel = subPixel; + } + + KXftConfig::Hint::Style hinting() const + { + return m_hinting; + } + + void setHinting(KXftConfig::Hint::Style hinting) + { + m_hinting = hinting; + } + + void save() + { + KXftConfig xft; + KXftConfig::AntiAliasing::State aaState = KXftConfig::AntiAliasing::NotSet; + if (m_antiAliasingChanged || xft.antiAliasingHasLocalConfig()) { + aaState = m_antiAliasing ? KXftConfig::AntiAliasing::Enabled : KXftConfig::AntiAliasing::Disabled; + } + xft.setAntiAliasing(aaState); + + if (m_exclude) { + xft.setExcludeRange(m_excludeFrom, m_excludeTo); + } else { + xft.setExcludeRange(0, 0); + } + + KXftConfig::SubPixel::Type spType = static_cast(m_subPixel); + if (m_subPixelChanged || xft.subPixelTypeHasLocalConfig()) { + xft.setSubPixelType(spType); + } else { + xft.setSubPixelType(KXftConfig::SubPixel::NotSet); + } + + KXftConfig::Hint::Style hStyle = static_cast(m_hinting); + if (m_hintingChanged || xft.hintStyleHasLocalConfig()) { + xft.setHintStyle(hStyle); + } else { + xft.setHintStyle(KXftConfig::Hint::NotSet); + } + + // Write to KConfig to sync with krdb + KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); + KConfigGroup grp(config, "General"); + + grp.writeEntry("XftSubPixel", KXftConfig::toStr(spType)); + + if (aaState == KXftConfig::AntiAliasing::NotSet) { + grp.revertToDefault("XftAntialias"); + } else { + grp.writeEntry("XftAntialias", aaState == KXftConfig::AntiAliasing::Enabled); + } + + QString hs(KXftConfig::toStr(hStyle)); + if (hs != grp.readEntry("XftHintStyle")) { + if (KXftConfig::Hint::NotSet == hStyle) { + grp.revertToDefault("XftHintStyle"); + } else { + grp.writeEntry("XftHintStyle", hs); + } + } + + xft.apply(); + + m_subPixelChanged = false; + m_hintingChanged = false; + m_antiAliasingChanged = false; + } + + void load() + { + double from, to; + KXftConfig xft; + + if (xft.getExcludeRange(from, to)) { + setExclude(true); + setExcludeFrom(from); + setExcludeTo(to); + } else { + setExclude(defaultExclude()); + setExcludeFrom(defaultExcludeFrom()); + setExcludeTo(defaultExcludeTo()); + } + + // sub pixel + KXftConfig::SubPixel::Type spType = KXftConfig::SubPixel::NotSet; + xft.getSubPixelType(spType); + // if it is not set, we set it to rgb + if (spType == KXftConfig::SubPixel::NotSet) { + spType = KXftConfig::SubPixel::Rgb; + } + setSubPixel(spType); + + // hinting + KXftConfig::Hint::Style hStyle = KXftConfig::Hint::NotSet; + xft.getHintStyle(hStyle); + // if it is not set, we set it to slight hinting + if (hStyle == KXftConfig::Hint::NotSet) { + hStyle = KXftConfig::Hint::Slight; + } + setHinting(hStyle); + + KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals"); + KConfigGroup cg(config, "General"); + const auto aaState = xft.getAntiAliasing(); + setAntiAliasing(aaState != KXftConfig::AntiAliasing::Disabled); + + m_subPixelChanged = false; + m_hintingChanged = false; + m_antiAliasingChanged = false; + } + +private: + FontsAASettings *m_settings; + bool m_antiAliasing; + bool m_antiAliasingChanged; + KXftConfig::SubPixel::Type m_subPixel; + bool m_subPixelChanged; + KXftConfig::Hint::Style m_hinting; + bool m_hintingChanged; + bool m_exclude; + int m_excludeFrom; + int m_excludeTo; +}; + + +FontsAASettings::FontsAASettings(QObject *parent) + : FontsAASettingsBase(parent) + , m_fontAASettingsStore(new FontAASettingsStore(this)) +{ + addItemInternal("exclude", defaultExclude(), &FontsAASettings::excludeChanged); + addItemInternal("excludeFrom", defaultExcludeFrom(), &FontsAASettings::excludeFromChanged); + addItemInternal("excludeTo", defaultExcludeTo(), &FontsAASettings::excludeToChanged); + addItemInternal("antiAliasing", defaultAntiAliasing(), &FontsAASettings::antiAliasingChanged); + addItemInternal("subPixel", defaultSubPixel(), &FontsAASettings::subPixelChanged); + addItemInternal("hinting", defaultHinting(), &FontsAASettings::hintingChanged); + + connect(this, &FontsAASettings::forceFontDPIWaylandChanged, this, &FontsAASettings::dpiChanged); + connect(this, &FontsAASettings::forceFontDPIChanged, this, &FontsAASettings::dpiChanged); +} + +void FontsAASettings::addItemInternal(const QByteArray &propertyName, const QVariant &defaultValue, NotifySignalType notifySignal) +{ + auto item = new KPropertySkeletonItem(m_fontAASettingsStore, propertyName, defaultValue); + addItem(item, propertyName); + item->setNotifyFunction([this, notifySignal] { emit (this->*notifySignal)(); }); +} + +bool FontsAASettings::exclude() const +{ + return findItem("exclude")->property().toBool(); +} + +void FontsAASettings::setExclude(bool exclude) +{ + findItem("exclude")->setProperty(exclude); +} + +int FontsAASettings::excludeFrom() const +{ + return findItem("excludeFrom")->property().toInt(); +} + +void FontsAASettings::setExcludeFrom(int excludeFrom) +{ + findItem("excludeFrom")->setProperty(excludeFrom); +} + +int FontsAASettings::excludeTo() const +{ + return findItem("excludeTo")->property().toInt(); +} + +void FontsAASettings::setExcludeTo(int excludeTo) +{ + findItem("excludeTo")->setProperty(excludeTo); +} + +bool FontsAASettings::antiAliasing() const +{ + return findItem("antiAliasing")->property().toBool(); +} + +void FontsAASettings::setAntiAliasing(bool antiAliasing) +{ + findItem("antiAliasing")->setProperty(antiAliasing); +} + +int FontsAASettings::dpi() const +{ + if (KWindowSystem::isPlatformWayland()) { + return forceFontDPIWayland(); + } else { + return forceFontDPI(); + } +} + +void FontsAASettings::setDpi(int newDPI) +{ + if (dpi() == newDPI) { + return; + } + if (KWindowSystem::isPlatformWayland()) { + setForceFontDPIWayland(newDPI); + } else { + setForceFontDPI(newDPI); + } + emit dpiChanged(); +} + +KXftConfig::SubPixel::Type FontsAASettings::subPixel() const +{ + return findItem("subPixel")->property().value(); +} + +void FontsAASettings::setSubPixel(KXftConfig::SubPixel::Type subPixel) +{ + findItem("subPixel")->setProperty(subPixel); +} + +KXftConfig::Hint::Style FontsAASettings::hinting() const +{ + return findItem("hinting")->property().value(); +} + +void FontsAASettings::setHinting(KXftConfig::Hint::Style hinting) +{ + findItem("hinting")->setProperty(hinting); +} + +bool FontsAASettings::usrSave() +{ + m_fontAASettingsStore->save(); + return FontsAASettingsBase::usrSave(); +} + +#include "fontsaasettings.moc" diff --git a/kcms/fonts/fontsaasettingsbase.kcfg b/kcms/fonts/fontsaasettingsbase.kcfg new file mode 100644 --- /dev/null +++ b/kcms/fonts/fontsaasettingsbase.kcfg @@ -0,0 +1,17 @@ + + + + + + + 0 + + + + 0 + + + diff --git a/kcms/fonts/fontsaasettingsbase.kcfgc b/kcms/fonts/fontsaasettingsbase.kcfgc new file mode 100644 --- /dev/null +++ b/kcms/fonts/fontsaasettingsbase.kcfgc @@ -0,0 +1,6 @@ +File=fontsaasettingsbase.kcfg +ClassName=FontsAASettingsBase +Mutators=true +DefaultValueGetters=true +GenerateProperties=true +ParentInConstructor=true diff --git a/kcms/fonts/kxftconfig.h b/kcms/fonts/kxftconfig.h --- a/kcms/fonts/kxftconfig.h +++ b/kcms/fonts/kxftconfig.h @@ -27,6 +27,7 @@ #include #include #include +#include class KXftConfig { @@ -200,6 +201,8 @@ QDateTime m_time; }; +Q_DECLARE_METATYPE(KXftConfig::Hint::Style) +Q_DECLARE_METATYPE(KXftConfig::SubPixel::Type) #endif #endif diff --git a/kcms/fonts/package/contents/ui/main.qml b/kcms/fonts/package/contents/ui/main.qml --- a/kcms/fonts/package/contents/ui/main.qml +++ b/kcms/fonts/package/contents/ui/main.qml @@ -39,7 +39,7 @@ text: i18n("Some changes such as anti-aliasing or DPI will only affect newly started applications.") Connections { - target: kcm.fontAASettings + target: kcm onAliasingChangeApplied: antiAliasingMessage.visible = true } } @@ -107,17 +107,17 @@ QtControls.CheckBox { id: antiAliasingCheckBox - checked: kcm.fontAASettings.antiAliasing - onCheckedChanged: kcm.fontAASettings.antiAliasing = checked + checked: kcm.fontsAASettings.antiAliasing + onCheckedChanged: kcm.fontsAASettings.antiAliasing = checked Kirigami.FormData.label: i18n("Anti-Aliasing:") text: i18n("Enable") Layout.fillWidth: true } QtControls.CheckBox { id: excludeCheckBox - checked: kcm.fontAASettings.exclude - onCheckedChanged: kcm.fontAASettings.exclude = checked; + checked: kcm.fontsAASettings.exclude + onCheckedChanged: kcm.fontsAASettings.exclude = checked; text: i18n("Exclude range from anti-aliasing") Layout.fillWidth: true enabled: antiAliasingCheckBox.checked @@ -130,11 +130,12 @@ QtControls.SpinBox { id: excludeFromSpinBox stepSize: 1 - onValueChanged: kcm.fontAASettings.excludeFrom = value + onValueChanged: kcm.fontsAASettings.excludeFrom = value textFromValue: function(value, locale) { return i18n("%1 pt", value)} valueFromText: function(text, locale) { return parseInt(text) } editable: true enabled: excludeCheckBox.checked + value: kcm.fontsAASettings.excludeFrom } QtControls.Label { @@ -147,26 +148,27 @@ QtControls.SpinBox { id: excludeToSpinBox stepSize: 1 - onValueChanged: kcm.fontAASettings.excludeTo = value + onValueChanged: kcm.fontsAASettings.excludeTo = value textFromValue: function(value, locale) { return i18n("%1 pt", value)} valueFromText: function(text, locale) { return parseInt(text) } editable: true enabled: excludeCheckBox.checked + value: kcm.fontsAASettings.excludeTo } Connections { - target: kcm.fontAASettings - onExcludeFromChanged: excludeFromSpinBox.value = kcm.fontAASettings.excludeFrom; - onExcludeToChanged: excludeToSpinBox.value = kcm.fontAASettings.excludeTo; + target: kcm.fontsAASettings + onExcludeFromChanged: excludeFromSpinBox.value = kcm.fontsAASettings.excludeFrom; + onExcludeToChanged: excludeToSpinBox.value = kcm.fontsAASettings.excludeTo; } } QtControls.ComboBox { id: subPixelCombo Layout.preferredWidth: formLayout.maxImplicitWidth Kirigami.FormData.label: i18nc("Used as a noun, and precedes a combobox full of options", "Sub-pixel rendering:") - currentIndex: kcm.fontAASettings.subPixelCurrentIndex - onCurrentIndexChanged: kcm.fontAASettings.subPixelCurrentIndex = currentIndex; - model: kcm.fontAASettings.subPixelOptionsModel + currentIndex: kcm.subPixelCurrentIndex + onCurrentIndexChanged: kcm.subPixelCurrentIndex = currentIndex; + model: kcm.subPixelOptionsModel textRole: "display" enabled: antiAliasingCheckBox.checked popup.height: popup.implicitHeight @@ -184,7 +186,7 @@ } Image { id: subPixelComboImage - source: "image://preview/" + model.index + "_" + kcm.fontAASettings.hintingCurrentIndex + ".png" + source: "image://preview/" + model.index + "_" + kcm.hintingCurrentIndex + ".png" // Setting sourceSize here is necessary as a workaround for QTBUG-38127 // // With this bug, images requested from a QQuickImageProvider have an incorrect scale with devicePixelRatio != 1 when sourceSize is not set. @@ -201,9 +203,9 @@ id: hintingCombo Layout.preferredWidth: formLayout.maxImplicitWidth Kirigami.FormData.label: i18nc("Used as a noun, and precedes a combobox full of options", "Hinting:") - currentIndex: kcm.fontAASettings.hintingCurrentIndex - onCurrentTextChanged: kcm.fontAASettings.hintingCurrentIndex = currentIndex; - model: kcm.fontAASettings.hintingOptionsModel + currentIndex: kcm.hintingCurrentIndex + onCurrentTextChanged: kcm.hintingCurrentIndex = currentIndex; + model: kcm.hintingOptionsModel textRole: "display" enabled: antiAliasingCheckBox.checked popup.height: popup.implicitHeight @@ -221,7 +223,7 @@ } Image { id: hintingComboImage - source: "image://preview/" + kcm.fontAASettings.subPixelCurrentIndex + "_" + model.index + ".png" + source: "image://preview/" + kcm.subPixelCurrentIndex + "_" + model.index + ".png" // Setting sourceSize here is necessary as a workaround for QTBUG-38127 // // With this bug, images requested from a QQuickImageProvider have an incorrect scale with devicePixelRatio != 1 when sourceSize is not set. @@ -237,18 +239,18 @@ RowLayout { QtControls.CheckBox { id: dpiCheckBox - checked: kcm.fontAASettings.dpi !== 0 + checked: kcm.fontsAASettings.dpi !== 0 text: i18n("Force font DPI:") - onClicked: kcm.fontAASettings.dpi = (checked ? dpiSpinBox.value : 0) + onClicked: kcm.fontsAASettings.dpi = (checked ? dpiSpinBox.value : 0) } QtControls.SpinBox { id: dpiSpinBox stepSize: 24 editable: true enabled: dpiCheckBox.checked - value: kcm.fontAASettings.dpi !== 0 ? kcm.fontAASettings.dpi : 96 - onValueModified: kcm.fontAASettings.dpi = value + value: kcm.fontsAASettings.dpi !== 0 ? kcm.fontsAASettings.dpi : 96 + onValueModified: kcm.fontsAASettings.dpi = value // to: need to divide to stepSize to: 1008 // lowest vaue here can be == stepSize, that is because 0 means off