File indexing completed on 2024-05-19 05:38:05

0001 /*
0002     SPDX-FileCopyrightText: 2020 Benjamin Port <benjamin.port@enioka.com>
0003     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "fontsaasettings.h"
0009 
0010 #include <KWindowSystem>
0011 #include <QDebug>
0012 
0013 using namespace Qt::StringLiterals;
0014 
0015 namespace
0016 {
0017 bool defaultExclude()
0018 {
0019     return false;
0020 }
0021 
0022 int defaultExcludeFrom()
0023 {
0024     return 8;
0025 }
0026 
0027 int defaultExcludeTo()
0028 {
0029     return 15;
0030 }
0031 
0032 bool defaultAntiAliasing()
0033 {
0034     return true;
0035 }
0036 
0037 KXftConfig::SubPixel::Type defaultSubPixel()
0038 {
0039     return KXftConfig::SubPixel::Rgb;
0040 }
0041 
0042 KXftConfig::Hint::Style defaultHinting()
0043 {
0044     return KXftConfig::Hint::Slight;
0045 }
0046 }
0047 
0048 class FontAASettingsStore : public QObject
0049 {
0050     Q_OBJECT
0051     Q_PROPERTY(bool exclude READ exclude WRITE setExclude)
0052     Q_PROPERTY(int excludeFrom READ excludeFrom WRITE setExcludeFrom)
0053     Q_PROPERTY(int excludeTo READ excludeTo WRITE setExcludeTo)
0054     Q_PROPERTY(bool antiAliasing READ antiAliasing WRITE setAntiAliasing)
0055     Q_PROPERTY(KXftConfig::SubPixel::Type subPixel READ subPixel WRITE setSubPixel)
0056     Q_PROPERTY(KXftConfig::Hint::Style hinting READ hinting WRITE setHinting)
0057 public:
0058     FontAASettingsStore(FontsAASettings *parent = nullptr)
0059         : QObject(parent)
0060     {
0061         load();
0062     }
0063 
0064     bool exclude() const
0065     {
0066         return m_exclude;
0067     }
0068 
0069     void setExclude(bool exclude)
0070     {
0071         if (m_exclude != exclude) {
0072             m_exclude = exclude;
0073         }
0074     }
0075 
0076     int excludeFrom() const
0077     {
0078         return m_excludeFrom;
0079     }
0080 
0081     void setExcludeFrom(int excludeFrom)
0082     {
0083         if (m_excludeFrom != excludeFrom) {
0084             m_excludeFrom = excludeFrom;
0085         }
0086     }
0087 
0088     int excludeTo() const
0089     {
0090         return m_excludeTo;
0091     }
0092 
0093     void setExcludeTo(int excludeTo)
0094     {
0095         if (m_excludeTo != excludeTo) {
0096             m_excludeTo = excludeTo;
0097         }
0098     }
0099 
0100     bool isImmutable() const
0101     {
0102         return m_isImmutable;
0103     }
0104 
0105     bool antiAliasing() const
0106     {
0107         return m_antiAliasing;
0108     }
0109 
0110     void setAntiAliasing(bool antiAliasing)
0111     {
0112         if (antiAliasing != m_antiAliasing) {
0113             m_antiAliasingChanged = true;
0114             m_antiAliasing = antiAliasing;
0115         }
0116     }
0117 
0118     KXftConfig::SubPixel::Type subPixel() const
0119     {
0120         return m_subPixel;
0121     }
0122 
0123     void setSubPixel(KXftConfig::SubPixel::Type subPixel)
0124     {
0125         if (m_subPixel != subPixel) {
0126             m_subPixelChanged = true;
0127             m_subPixel = subPixel;
0128         }
0129     }
0130 
0131     KXftConfig::Hint::Style hinting() const
0132     {
0133         return m_hinting;
0134     }
0135 
0136     void setHinting(KXftConfig::Hint::Style hinting)
0137     {
0138         if (m_hinting != hinting) {
0139             m_hintingChanged = true;
0140             m_hinting = hinting;
0141         }
0142     }
0143 
0144     void save()
0145     {
0146         KXftConfig xft;
0147         KXftConfig::AntiAliasing::State aaState = KXftConfig::AntiAliasing::NotSet;
0148         if (m_antiAliasingChanged || xft.antiAliasingHasLocalConfig()) {
0149             aaState = m_antiAliasing ? KXftConfig::AntiAliasing::Enabled : KXftConfig::AntiAliasing::Disabled;
0150         }
0151         xft.setAntiAliasing(aaState);
0152 
0153         if (m_exclude) {
0154             xft.setExcludeRange(m_excludeFrom, m_excludeTo);
0155         } else {
0156             xft.setExcludeRange(0, 0);
0157         }
0158 
0159         if (m_subPixelChanged || xft.subPixelTypeHasLocalConfig()) {
0160             xft.setSubPixelType(m_subPixel);
0161         } else {
0162             xft.setSubPixelType(KXftConfig::SubPixel::NotSet);
0163         }
0164 
0165         if (m_hintingChanged || xft.hintStyleHasLocalConfig()) {
0166             xft.setHintStyle(m_hinting);
0167         } else {
0168             xft.setHintStyle(KXftConfig::Hint::NotSet);
0169         }
0170 
0171         // Write to KConfig to sync with krdb
0172         KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals");
0173         KConfigGroup grp(config, u"General"_s);
0174 
0175         grp.writeEntry("XftSubPixel", KXftConfig::toStr(m_subPixel));
0176 
0177         if (aaState == KXftConfig::AntiAliasing::NotSet) {
0178             grp.revertToDefault("XftAntialias");
0179         } else {
0180             grp.writeEntry("XftAntialias", aaState == KXftConfig::AntiAliasing::Enabled);
0181         }
0182 
0183         QString hs(KXftConfig::toStr(m_hinting));
0184         if (hs != grp.readEntry("XftHintStyle")) {
0185             if (KXftConfig::Hint::NotSet == m_hinting) {
0186                 grp.revertToDefault("XftHintStyle");
0187             } else {
0188                 grp.writeEntry("XftHintStyle", hs);
0189             }
0190         }
0191 
0192         xft.apply();
0193 
0194         m_subPixelChanged = false;
0195         m_hintingChanged = false;
0196         m_antiAliasingChanged = false;
0197     }
0198 
0199     void load()
0200     {
0201         double from, to;
0202         KXftConfig xft;
0203 
0204         if (xft.getExcludeRange(from, to)) {
0205             setExclude(true);
0206             setExcludeFrom(from);
0207             setExcludeTo(to);
0208         } else {
0209             setExclude(defaultExclude());
0210             setExcludeFrom(defaultExcludeFrom());
0211             setExcludeTo(defaultExcludeTo());
0212         }
0213 
0214         // sub pixel
0215         KXftConfig::SubPixel::Type spType = KXftConfig::SubPixel::NotSet;
0216         xft.getSubPixelType(spType);
0217         // if it is not set, we have no subpixel hinting
0218         if (spType == KXftConfig::SubPixel::NotSet) {
0219             spType = KXftConfig::SubPixel::None;
0220         }
0221         setSubPixel(spType);
0222 
0223         // hinting
0224         KXftConfig::Hint::Style hStyle = KXftConfig::Hint::NotSet;
0225         xft.getHintStyle(hStyle);
0226         // if it is not set, we have no hinting
0227         if (hStyle == KXftConfig::Hint::NotSet) {
0228             hStyle = KXftConfig::Hint::None;
0229         }
0230         setHinting(hStyle);
0231 
0232         KSharedConfig::Ptr config = KSharedConfig::openConfig("kdeglobals");
0233         KConfigGroup cg(config, QStringLiteral("General"));
0234         m_isImmutable = cg.isEntryImmutable("XftAntialias");
0235 
0236         const auto aaState = xft.getAntiAliasing();
0237         setAntiAliasing(aaState != KXftConfig::AntiAliasing::Disabled);
0238 
0239         m_subPixelChanged = false;
0240         m_hintingChanged = false;
0241         m_antiAliasingChanged = false;
0242     }
0243 
0244 private:
0245     bool m_isImmutable;
0246     bool m_antiAliasing;
0247     bool m_antiAliasingChanged;
0248     KXftConfig::SubPixel::Type m_subPixel;
0249     bool m_subPixelChanged;
0250     KXftConfig::Hint::Style m_hinting;
0251     bool m_hintingChanged;
0252     bool m_exclude;
0253     int m_excludeFrom;
0254     int m_excludeTo;
0255 };
0256 
0257 FontsAASettings::FontsAASettings(QObject *parent)
0258     : FontsAASettingsBase(parent)
0259     , m_fontAASettingsStore(new FontAASettingsStore(this))
0260 {
0261     addItemInternal("exclude", defaultExclude(), &FontsAASettings::excludeChanged);
0262     addItemInternal("excludeFrom", defaultExcludeFrom(), &FontsAASettings::excludeFromChanged);
0263     addItemInternal("excludeTo", defaultExcludeTo(), &FontsAASettings::excludeToChanged);
0264     addItemInternal("antiAliasing", defaultAntiAliasing(), &FontsAASettings::antiAliasingChanged);
0265     addItemInternal("subPixel", defaultSubPixel(), &FontsAASettings::subPixelChanged);
0266     addItemInternal("hinting", defaultHinting(), &FontsAASettings::hintingChanged);
0267 
0268     connect(this, &FontsAASettings::forceFontDPIChanged, this, &FontsAASettings::dpiChanged);
0269 }
0270 
0271 void FontsAASettings::addItemInternal(const QByteArray &propertyName, const QVariant &defaultValue, NotifySignalType notifySignal)
0272 {
0273     auto item = new KPropertySkeletonItem(m_fontAASettingsStore, propertyName, defaultValue);
0274     addItem(item, propertyName);
0275     item->setNotifyFunction([this, notifySignal] {
0276         Q_EMIT(this->*notifySignal)();
0277     });
0278 }
0279 
0280 bool FontsAASettings::exclude() const
0281 {
0282     return findItem("exclude")->property().toBool();
0283 }
0284 
0285 void FontsAASettings::setExclude(bool exclude)
0286 {
0287     findItem("exclude")->setProperty(exclude);
0288 }
0289 
0290 int FontsAASettings::excludeFrom() const
0291 {
0292     return findItem("excludeFrom")->property().toInt();
0293 }
0294 
0295 void FontsAASettings::setExcludeFrom(int excludeFrom)
0296 {
0297     findItem("excludeFrom")->setProperty(excludeFrom);
0298 }
0299 
0300 int FontsAASettings::excludeTo() const
0301 {
0302     return findItem("excludeTo")->property().toInt();
0303 }
0304 
0305 void FontsAASettings::setExcludeTo(int excludeTo)
0306 {
0307     findItem("excludeTo")->setProperty(excludeTo);
0308 }
0309 
0310 bool FontsAASettings::antiAliasing() const
0311 {
0312     return findItem("antiAliasing")->property().toBool();
0313 }
0314 
0315 void FontsAASettings::setAntiAliasing(bool enabled)
0316 {
0317     if (antiAliasing() == enabled) {
0318         return;
0319     }
0320 
0321     findItem("antiAliasing")->setProperty(enabled);
0322     if (!enabled) {
0323         setSubPixel(KXftConfig::SubPixel::None);
0324     } else if (subPixel() == KXftConfig::SubPixel::None) {
0325         setSubPixel(defaultSubPixel());
0326     }
0327 }
0328 
0329 int FontsAASettings::dpi() const
0330 {
0331     return forceFontDPI();
0332 }
0333 
0334 void FontsAASettings::setDpi(int newDPI)
0335 {
0336     if (dpi() == newDPI) {
0337         return;
0338     }
0339 
0340     setForceFontDPI(newDPI);
0341     Q_EMIT dpiChanged();
0342 }
0343 
0344 KXftConfig::SubPixel::Type FontsAASettings::subPixel() const
0345 {
0346     return findItem("subPixel")->property().value<KXftConfig::SubPixel::Type>();
0347 }
0348 
0349 void FontsAASettings::setSubPixel(KXftConfig::SubPixel::Type type)
0350 {
0351     if (subPixel() == type) {
0352         return;
0353     }
0354 
0355     findItem("subPixel")->setProperty(type);
0356 }
0357 
0358 KXftConfig::Hint::Style FontsAASettings::hinting() const
0359 {
0360     return findItem("hinting")->property().value<KXftConfig::Hint::Style>();
0361 }
0362 
0363 bool FontsAASettings::isAaImmutable() const
0364 {
0365     return m_fontAASettingsStore->isImmutable();
0366 }
0367 
0368 bool FontsAASettings::excludeStateProxy() const
0369 {
0370     return false;
0371 }
0372 
0373 void FontsAASettings::setHinting(KXftConfig::Hint::Style hinting)
0374 {
0375     findItem("hinting")->setProperty(hinting);
0376 }
0377 
0378 bool FontsAASettings::usrSave()
0379 {
0380     m_fontAASettingsStore->save();
0381     return FontsAASettingsBase::usrSave();
0382 }
0383 
0384 #include "fontsaasettings.moc"