not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / fonts / kxftconfig.cpp
blobd0e5eff41f8a6ae3cc4e9b76a80172357de2f0d4
1 /*
2 Copyright (c) 2002 Craig Drummond <craig@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "kxftconfig.h"
21 #ifdef HAVE_FONTCONFIG
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <sys/stat.h>
28 #include <QRegExp>
29 #include <QFile>
30 #include <QX11Info>
31 #include <QByteArray>
32 #include <klocale.h>
33 #include <kde_file.h>
34 #include <QDir>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <fontconfig/fontconfig.h>
39 #include <kdebug.h>
41 using namespace std;
43 QString KXftConfig::contractHome(QString path)
45 if (!path.isEmpty() && '/'==path[0])
47 QString home(QDir::homePath());
49 if(path.startsWith(home))
51 int len = home.length();
53 if(path.length() == len || path[len] == '/')
54 return path.replace(0, len, QLatin1String("~"));
58 return path;
61 QString KXftConfig::expandHome(QString path)
63 if(!path.isEmpty() && '~'==path[0])
64 return 1==path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath());
66 return path;
69 static int point2Pixel(double point)
71 return (int)(((point*QX11Info::appDpiY())/72.0)+0.5);
74 static int pixel2Point(double pixel)
76 return (int)(((pixel*72.0)/(double)QX11Info::appDpiY())+0.5);
79 static bool equal(double d1, double d2)
81 return (fabs(d1 - d2) < 0.0001);
84 static QString dirSyntax(const QString &d)
86 if(!d.isNull())
88 QString ds(d);
90 ds.replace("//", "/");
92 int slashPos=ds.lastIndexOf('/');
94 if(slashPos!=(((int)ds.length())-1))
95 ds.append('/');
97 return ds;
100 return d;
103 static QString xDirSyntax(const QString &d)
105 if(!d.isNull())
107 QString ds(d);
108 int slashPos=ds.lastIndexOf('/');
110 if(slashPos==(((int)ds.length())-1))
111 ds.remove(slashPos, 1);
112 return ds;
115 return d;
118 static bool check(const QString &path, unsigned int fmt, bool checkW=false)
120 KDE_struct_stat info;
121 QByteArray pathC(QFile::encodeName(path));
123 return 0==KDE_lstat(pathC, &info) && (info.st_mode&S_IFMT)==fmt &&
124 (!checkW || 0==::access(pathC, W_OK));
127 inline bool fExists(const QString &p)
129 return check(p, S_IFREG, false);
132 inline bool dWritable(const QString &p)
134 return check(p, S_IFDIR, true);
137 inline bool dExists(const QString &p)
139 return check(p, S_IFDIR, false);
142 static QString getDir(const QString &f)
144 QString d(f);
146 int slashPos=d.lastIndexOf('/');
148 if(-1!=slashPos)
149 d.remove(slashPos+1, d.length());
151 return dirSyntax(d);
154 static time_t getTimeStamp(const QString &item)
156 KDE_struct_stat info;
158 return !item.isNull() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0;
161 inline QString fileSyntax(const QString &f) { return xDirSyntax(f); }
163 // Obtain location of config file to use.
165 // For system, prefer the following:
167 // <...>/config.d/00kde.conf = preferred method from FontConfig >= 2.3
168 // <...>/local.conf
170 // Non-system, prefer:
172 // $HOME/<...>/.fonts.conf
173 // $HOME/<...>/fonts.conf
175 QString getConfigFile(bool system)
177 #if (FC_VERSION>=20300)
178 static const char * constKdeRootFcFile="00kde.conf";
179 #endif
181 FcStrList *list=FcConfigGetConfigFiles(FcConfigGetCurrent());
182 QStringList files;
183 FcChar8 *file;
184 QString home(dirSyntax(QDir::homePath()));
186 while((file=FcStrListNext(list)))
188 QString f((const char *)file);
190 if(fExists(f))
192 // For nonsystem, only consider file within $HOME
193 if(system || 0==fileSyntax(f).indexOf(home))
194 files.append(f);
196 #if (FC_VERSION>=20300)
197 if(system && dExists(f) && (f.contains(QRegExp("/conf\\.d/?$")) ||
198 f.contains(QRegExp("/conf\\.d?$"))) )
199 return dirSyntax(f)+constKdeRootFcFile; // This ones good enough for me!
200 #endif
204 // Go through list of files, looking for the preferred one...
205 if(files.count())
207 QStringList::const_iterator it(files.begin()),
208 end(files.end());
210 for(; it!=end; ++it)
211 if(-1!=(*it).indexOf(QRegExp(system ? "/local\\.conf$" : "/\\.?fonts\\.conf$")))
212 return *it;
213 return files.front(); // Just return the 1st one...
215 else // Hmmm... no known files?
216 return system ? "/etc/fonts/local.conf" : fileSyntax(home+"/.fonts.conf");
219 static QString getEntry(QDomElement element, const char *type, unsigned int numAttributes, ...)
221 if(numAttributes==element.attributes().length())
223 va_list args;
224 unsigned int arg;
225 bool ok=true;
227 va_start(args, numAttributes);
229 for(arg=0; arg<numAttributes && ok; ++arg)
231 const char *attr=va_arg(args, const char *);
232 const char *val =va_arg(args, const char *);
234 if(!attr || !val || val!=element.attribute(attr))
235 ok=false;
238 va_end(args);
240 if(ok)
242 QDomNode n=element.firstChild();
244 if(!n.isNull())
246 QDomElement e = n.toElement();
248 if(!e.isNull() && type==e.tagName())
249 return e.text();
254 return QString();
257 static KXftConfig::SubPixel::Type strToType(const char *str)
259 if(0==strcmp(str, "rgb"))
260 return KXftConfig::SubPixel::Rgb;
261 else if(0==strcmp(str, "bgr"))
262 return KXftConfig::SubPixel::Bgr;
263 else if(0==strcmp(str, "vrgb"))
264 return KXftConfig::SubPixel::Vrgb;
265 else if(0==strcmp(str, "vbgr"))
266 return KXftConfig::SubPixel::Vbgr;
267 else
268 return KXftConfig::SubPixel::None;
271 static KXftConfig::Hint::Style strToStyle(const char *str)
273 if(0==strcmp(str, "hintslight"))
274 return KXftConfig::Hint::Slight;
275 else if(0==strcmp(str, "hintmedium"))
276 return KXftConfig::Hint::Medium;
277 else if(0==strcmp(str, "hintfull"))
278 return KXftConfig::Hint::Full;
279 else
280 return KXftConfig::Hint::None;
283 KXftConfig::KXftConfig(int required, bool system)
284 : m_doc("fontconfig"),
285 m_required(required),
286 m_system(system)
288 m_file=getConfigFile(system);
289 kDebug(1208) << "Using fontconfig file:" << m_file;
290 m_antiAliasing = aliasingEnabled();
291 reset();
294 KXftConfig::~KXftConfig()
298 bool KXftConfig::reset()
300 bool ok=false;
302 m_madeChanges=false;
303 m_hint.reset();
304 m_hinting.reset();
305 m_dirs.clear();
306 m_excludeRange.reset();
307 m_excludePixelRange.reset();
308 m_subPixel.reset();
310 QFile f(m_file);
312 if(f.open(QIODevice::ReadOnly))
314 m_time=getTimeStamp(m_file);
315 ok=true;
316 m_doc.clear();
318 if(m_doc.setContent(&f))
319 readContents();
320 f.close();
322 else
323 ok=!fExists(m_file) && dWritable(getDir(m_file));
325 if(m_doc.documentElement().isNull())
326 m_doc.appendChild(m_doc.createElement("fontconfig"));
328 if(ok && m_required&ExcludeRange)
331 // Check exclude range values - i.e. size and pixel size...
332 // If "size" range is set, ensure "pixelsize" matches...
333 if(!equal(0, m_excludeRange.from) || !equal(0, m_excludeRange.to))
335 double pFrom=(double)point2Pixel(m_excludeRange.from),
336 pTo=(double)point2Pixel(m_excludeRange.to);
338 if(!equal(pFrom, m_excludePixelRange.from) || !equal(pTo, m_excludePixelRange.to))
340 m_excludePixelRange.from=pFrom;
341 m_excludePixelRange.to=pTo;
342 m_madeChanges=true;
343 apply();
346 else if(!equal(0, m_excludePixelRange.from) || !equal(0, m_excludePixelRange.to))
348 // "pixelsize" set, but not "size" !!!
349 m_excludeRange.from=(int)pixel2Point(m_excludePixelRange.from);
350 m_excludeRange.to=(int)pixel2Point(m_excludePixelRange.to);
351 m_madeChanges=true;
352 apply();
356 return ok;
359 bool KXftConfig::apply()
361 bool ok=true;
363 if(m_madeChanges)
366 // Check if file has been written since we last read it. If it has, then re-read and add any
367 // of our changes...
368 if(fExists(m_file) && getTimeStamp(m_file)!=m_time)
370 KXftConfig newConfig(m_required, m_system);
372 if(m_required&Dirs)
374 QStringList list(getDirList());
375 QStringList::const_iterator it(list.begin()),
376 end(list.end());
378 for(it=list.constBegin(); it!=list.constEnd(); ++it)
379 newConfig.addDir(*it);
382 if(m_required&ExcludeRange)
383 newConfig.setExcludeRange(m_excludeRange.from, m_excludeRange.to);
384 if(m_required&SubPixelType)
385 newConfig.setSubPixelType(m_subPixel.type);
386 if(m_required&HintStyle)
387 newConfig.setHintStyle(m_hint.style);
388 if(m_required&AntiAlias)
389 newConfig.setAntiAliasing(m_antiAliasing.set);
391 ok=newConfig.changed() ? newConfig.apply() : true;
392 if(ok)
393 reset();
394 else
395 m_time=getTimeStamp(m_file);
397 else
399 if(m_required&ExcludeRange)
401 // Ensure these are always equal...
402 m_excludePixelRange.from=(int)point2Pixel(m_excludeRange.from);
403 m_excludePixelRange.to=(int)point2Pixel(m_excludeRange.to);
406 FcAtomic *atomic=FcAtomicCreate((const unsigned char *)(QFile::encodeName(m_file).data()));
408 ok=false;
409 if(atomic)
411 if(FcAtomicLock(atomic))
413 FILE *f=fopen((char *)FcAtomicNewFile(atomic), "w");
415 if(f)
417 if(m_required&Dirs)
419 applyDirs();
420 removeDirs();
422 if(m_required&SubPixelType)
423 applySubPixelType();
424 if(m_required&HintStyle)
425 applyHintStyle();
426 if(m_required&AntiAlias)
427 applyAntiAliasing();
428 if(m_required&ExcludeRange)
430 applyExcludeRange(false);
431 applyExcludeRange(true);
435 // Check document syntax...
436 static const char * qtXmlHeader = "<?xml version = '1.0'?>";
437 static const char * xmlHeader = "<?xml version=\"1.0\"?>";
438 static const char * qtDocTypeLine = "<!DOCTYPE fontconfig>";
439 static const char * docTypeLine = "<!DOCTYPE fontconfig SYSTEM "
440 "\"fonts.dtd\">";
442 QString str(m_doc.toString());
443 int idx;
445 if(0!=str.indexOf("<?xml"))
446 str.insert(0, xmlHeader);
447 else if(0==str.indexOf(qtXmlHeader))
448 str.replace(0, strlen(qtXmlHeader), xmlHeader);
450 if(-1!=(idx=str.indexOf(qtDocTypeLine)))
451 str.replace(idx, strlen(qtDocTypeLine), docTypeLine);
454 // Write to file...
455 fputs(str.toUtf8(), f);
456 fclose(f);
458 if(FcAtomicReplaceOrig(atomic))
460 ok=true;
461 reset(); // Re-read contents..
463 else
464 FcAtomicDeleteNew(atomic);
466 FcAtomicUnlock(atomic);
468 FcAtomicDestroy(atomic);
473 return ok;
476 bool KXftConfig::getSubPixelType(SubPixel::Type &type)
478 type=m_subPixel.type;
479 return SubPixel::None!=m_subPixel.type;
482 void KXftConfig::setSubPixelType(SubPixel::Type type)
484 if(type!=m_subPixel.type)
486 m_subPixel.type=type;
487 m_madeChanges=true;
491 bool KXftConfig::getHintStyle(Hint::Style &style)
493 if(Hint::NotSet!=m_hint.style && !m_hint.toBeRemoved)
495 style=m_hint.style;
496 return true;
498 else
499 return false;
502 void KXftConfig::setHintStyle(Hint::Style style)
504 if((Hint::NotSet==style && Hint::NotSet!=m_hint.style && !m_hint.toBeRemoved) ||
505 (Hint::NotSet!=style && (style!=m_hint.style || m_hint.toBeRemoved)) )
507 m_hint.toBeRemoved=(Hint::NotSet==style);
508 m_hint.style=style;
509 m_madeChanges=true;
512 if(Hint::NotSet!=style)
513 setHinting(Hint::None!=m_hint.style);
516 void KXftConfig::setHinting(bool set)
518 if(set!=m_hinting.set)
520 m_hinting.set=set;
521 m_madeChanges=true;
525 bool KXftConfig::getExcludeRange(double &from, double &to)
527 if(!equal(0, m_excludeRange.from) || !equal(0,m_excludeRange.to))
529 from=m_excludeRange.from;
530 to=m_excludeRange.to;
531 return true;
533 else
534 return false;
538 void KXftConfig::setExcludeRange(double from, double to)
540 double f=from<to ? from : to,
541 t=from<to ? to : from;
543 if(!equal(f, m_excludeRange.from) || !equal(t,m_excludeRange.to))
545 m_excludeRange.from=f;
546 m_excludeRange.to=t;
547 m_madeChanges=true;
551 void KXftConfig::addDir(const QString &d)
553 QString dir(dirSyntax(d));
555 if(dExists(dir) && !hasDir(dir))
557 m_dirs.append(ListItem(d));
558 m_madeChanges=true;
562 void KXftConfig::removeDir(const QString &d)
564 QList<ListItem>::Iterator it(m_dirs.begin()),
565 end(m_dirs.end());
567 for(; it!=end; )
568 if((*it).str==d)
570 QList<ListItem>::Iterator dir=it;
571 ++it;
573 if((*dir).added())
574 m_dirs.erase(dir);
575 else
576 (*dir).toBeRemoved=true;
577 m_madeChanges=true;
578 break;
582 QString KXftConfig::description(SubPixel::Type t)
584 switch(t)
586 default:
587 case SubPixel::None:
588 return i18n("None");
589 case SubPixel::Rgb:
590 return i18n("RGB");
591 case SubPixel::Bgr:
592 return i18n("BGR");
593 case SubPixel::Vrgb:
594 return i18n("Vertical RGB");
595 case SubPixel::Vbgr:
596 return i18n("Vertical BGR");
600 const char * KXftConfig::toStr(SubPixel::Type t)
602 switch(t)
604 default:
605 case SubPixel::None:
606 return "none";
607 case SubPixel::Rgb:
608 return "rgb";
609 case SubPixel::Bgr:
610 return "bgr";
611 case SubPixel::Vrgb:
612 return "vrgb";
613 case SubPixel::Vbgr:
614 return "vbgr";
618 QString KXftConfig::description(Hint::Style s)
620 switch(s)
622 default:
623 case Hint::Medium:
624 return i18n("Medium");
625 case Hint::NotSet:
626 return "";
627 case Hint::None:
628 return i18n("None");
629 case Hint::Slight:
630 return i18n("Slight");
631 case Hint::Full:
632 return i18n("Full");
636 const char * KXftConfig::toStr(Hint::Style s)
638 switch(s)
640 default:
641 case Hint::Medium:
642 return "hintmedium";
643 case Hint::None:
644 return "hintnone";
645 case Hint::Slight:
646 return "hintslight";
647 case Hint::Full:
648 return "hintfull";
652 bool KXftConfig::hasDir(const QString &d)
654 QString dir(dirSyntax(d));
656 QList<ListItem>::Iterator it(m_dirs.begin()),
657 end(m_dirs.end());
659 for(; it!=end; ++it)
660 if(0==dir.indexOf((*it).str))
661 return true;
663 return false;
666 QStringList KXftConfig::getDirList()
668 QStringList res;
669 QList<ListItem>::Iterator it(m_dirs.begin()),
670 end(m_dirs.end());
672 for(; it!=end; ++it)
673 if(!(*it).toBeRemoved)
674 res.append((*it).str);
676 return res;
679 void KXftConfig::readContents()
681 QDomNode n = m_doc.documentElement().firstChild();
683 while(!n.isNull())
685 QDomElement e = n.toElement();
687 if(!e.isNull())
689 if("dir"==e.tagName())
691 if(m_required&Dirs)
692 m_dirs.append(ListItem(expandHome(dirSyntax(e.text())), n));
694 else if("match"==e.tagName())
696 QString str;
698 switch(e.childNodes().count())
700 case 1:
701 if(m_required&SubPixelType && "font"==e.attribute("target"))
703 QDomElement ene=e.firstChild().toElement();
705 if(!ene.isNull() && "edit"==ene.tagName())
707 if(!(str=getEntry(ene, "const", 2, "name", "rgba", "mode",
708 "assign")).isNull())
710 m_subPixel.node=n;
711 m_subPixel.type=strToType(str.toLatin1());
713 else if(!(str=getEntry(ene, "const", 2, "name", "hintstyle", "mode",
714 "assign")).isNull())
716 m_hint.node=n;
717 m_hint.style=strToStyle(str.toLatin1());
719 else if(!(str=getEntry(ene, "bool", 2, "name", "hinting", "mode",
720 "assign")).isNull())
722 m_hinting.node=n;
723 m_hinting.set=str.toLower()!="false";
725 else if(!(str=getEntry(ene, "bool", 2, "name", "antialias", "mode",
726 "assign")).isNull())
728 m_antiAliasing.node=n;
729 m_antiAliasing.set=str.toLower()!="false";
733 break;
734 case 3: // CPD: Is target "font" or "pattern" ????
735 if(m_required&ExcludeRange && "font"==e.attribute("target"))
737 bool foundFalse=false;
738 QDomNode en=e.firstChild();
739 QString family;
740 double from=-1.0,
741 to=-1.0,
742 pixelFrom=-1.0,
743 pixelTo=-1.0;
745 while(!en.isNull())
747 QDomElement ene=en.toElement();
749 if(!ene.isNull())
751 if("test"==ene.tagName())
753 // kcmfonts used to write incorrectly more or less instead of
754 // more_eq and less_eq, so read both,
755 // first the old (wrong) one then the right one
756 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
757 "size", "compare", "more")).isNull())
758 from=str.toDouble();
759 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
760 "size", "compare", "more_eq")).isNull())
761 from=str.toDouble();
762 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
763 "size", "compare", "less")).isNull())
764 to=str.toDouble();
765 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
766 "size", "compare", "less_eq")).isNull())
767 to=str.toDouble();
768 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
769 "pixelsize", "compare", "more")).isNull())
770 pixelFrom=str.toDouble();
771 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
772 "pixelsize", "compare",
773 "more_eq")).isNull())
774 pixelFrom=str.toDouble();
775 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
776 "pixelsize", "compare", "less")).isNull())
777 pixelTo=str.toDouble();
778 if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
779 "pixelsize", "compare",
780 "less_eq")).isNull())
781 pixelTo=str.toDouble();
783 else if("edit"==ene.tagName() &&
784 "false"==getEntry(ene, "bool", 2, "name", "antialias",
785 "mode", "assign"))
786 foundFalse=true;
789 en=en.nextSibling();
792 if((from>=0 || to>=0) && foundFalse)
794 m_excludeRange.from=from < to ? from : to;
795 m_excludeRange.to =from < to ? to : from;
796 m_excludeRange.node=n;
798 else if((pixelFrom>=0 || pixelTo>=0) && foundFalse)
800 m_excludePixelRange.from=pixelFrom < pixelTo ? pixelFrom : pixelTo;
801 m_excludePixelRange.to =pixelFrom < pixelTo ? pixelTo : pixelFrom;
802 m_excludePixelRange.node=n;
805 break;
806 default:
807 break;
811 n=n.nextSibling();
815 void KXftConfig::applyDirs()
817 QList<ListItem>::Iterator it(m_dirs.begin()),
818 end(m_dirs.end());
820 for(; it!=end; ++it)
821 if(!(*it).toBeRemoved && (*it).node.isNull())
823 QDomElement newNode = m_doc.createElement("dir");
824 QDomText text = m_doc.createTextNode(contractHome(xDirSyntax((*it).str)));
826 newNode.appendChild(text);
827 m_doc.documentElement().appendChild(newNode);
831 void KXftConfig::applySubPixelType()
833 QDomElement matchNode = m_doc.createElement("match"),
834 typeNode = m_doc.createElement("const"),
835 editNode = m_doc.createElement("edit");
836 QDomText typeText = m_doc.createTextNode(toStr(m_subPixel.type));
838 matchNode.setAttribute("target", "font");
839 editNode.setAttribute("mode", "assign");
840 editNode.setAttribute("name", "rgba");
841 editNode.appendChild(typeNode);
842 typeNode.appendChild(typeText);
843 matchNode.appendChild(editNode);
844 if(m_subPixel.node.isNull())
845 m_doc.documentElement().appendChild(matchNode);
846 else
847 m_doc.documentElement().replaceChild(matchNode, m_subPixel.node);
848 m_subPixel.node=matchNode;
851 void KXftConfig::applyHintStyle()
853 applyHinting();
855 if(Hint::NotSet==m_hint.style || m_hint.toBeRemoved)
857 if(!m_hint.node.isNull())
859 m_doc.documentElement().removeChild(m_hint.node);
860 m_hint.node.clear();
863 else
865 QDomElement matchNode = m_doc.createElement("match"),
866 typeNode = m_doc.createElement("const"),
867 editNode = m_doc.createElement("edit");
868 QDomText typeText = m_doc.createTextNode(toStr(m_hint.style));
870 matchNode.setAttribute("target", "font");
871 editNode.setAttribute("mode", "assign");
872 editNode.setAttribute("name", "hintstyle");
873 editNode.appendChild(typeNode);
874 typeNode.appendChild(typeText);
875 matchNode.appendChild(editNode);
876 if(m_hint.node.isNull())
877 m_doc.documentElement().appendChild(matchNode);
878 else
879 m_doc.documentElement().replaceChild(matchNode, m_hint.node);
880 m_hint.node=matchNode;
884 void KXftConfig::applyHinting()
886 QDomElement matchNode = m_doc.createElement("match"),
887 typeNode = m_doc.createElement("bool"),
888 editNode = m_doc.createElement("edit");
889 QDomText typeText = m_doc.createTextNode(m_hinting.set ? "true" : "false");
891 matchNode.setAttribute("target", "font");
892 editNode.setAttribute("mode", "assign");
893 editNode.setAttribute("name", "hinting");
894 editNode.appendChild(typeNode);
895 typeNode.appendChild(typeText);
896 matchNode.appendChild(editNode);
897 if(m_hinting.node.isNull())
898 m_doc.documentElement().appendChild(matchNode);
899 else
900 m_doc.documentElement().replaceChild(matchNode, m_hinting.node);
901 m_hinting.node=matchNode;
904 void KXftConfig::applyExcludeRange(bool pixel)
906 Exclude &range=pixel ? m_excludePixelRange : m_excludeRange;
908 if(equal(range.from, 0) && equal(range.to, 0))
910 if(!range.node.isNull())
912 m_doc.documentElement().removeChild(range.node);
913 range.node.clear();
916 else
918 QString fromString,
919 toString;
921 fromString.setNum(range.from);
922 toString.setNum(range.to);
924 QDomElement matchNode = m_doc.createElement("match"),
925 fromTestNode = m_doc.createElement("test"),
926 fromNode = m_doc.createElement("double"),
927 toTestNode = m_doc.createElement("test"),
928 toNode = m_doc.createElement("double"),
929 editNode = m_doc.createElement("edit"),
930 boolNode = m_doc.createElement("bool");
931 QDomText fromText = m_doc.createTextNode(fromString),
932 toText = m_doc.createTextNode(toString),
933 boolText = m_doc.createTextNode("false");
935 matchNode.setAttribute("target", "font"); // CPD: Is target "font" or "pattern" ????
936 fromTestNode.setAttribute("qual", "any");
937 fromTestNode.setAttribute("name", pixel ? "pixelsize" : "size");
938 fromTestNode.setAttribute("compare", "more_eq");
939 fromTestNode.appendChild(fromNode);
940 fromNode.appendChild(fromText);
941 toTestNode.setAttribute("qual", "any");
942 toTestNode.setAttribute("name", pixel ? "pixelsize" : "size");
943 toTestNode.setAttribute("compare", "less_eq");
944 toTestNode.appendChild(toNode);
945 toNode.appendChild(toText);
946 editNode.setAttribute("mode", "assign");
947 editNode.setAttribute("name", "antialias");
948 editNode.appendChild(boolNode);
949 boolNode.appendChild(boolText);
950 matchNode.appendChild(fromTestNode);
951 matchNode.appendChild(toTestNode);
952 matchNode.appendChild(editNode);
954 if(!m_antiAliasing.node.isNull())
955 m_doc.documentElement().removeChild(range.node);
956 m_doc.documentElement().appendChild(matchNode);
957 range.node=matchNode;
961 void KXftConfig::removeDirs()
963 QDomElement docElem = m_doc.documentElement();
964 QList<ListItem>::Iterator it(m_dirs.begin()),
965 end(m_dirs.end());
967 for(; it!=end; ++it)
968 if((*it).toBeRemoved && !(*it).node.isNull())
969 docElem.removeChild((*it).node);
972 bool KXftConfig::getAntiAliasing() const
974 return m_antiAliasing.set;
977 void KXftConfig::setAntiAliasing( bool set )
979 if(set!=m_antiAliasing.set)
981 m_antiAliasing.set = set;
982 m_madeChanges = true;
986 void KXftConfig::applyAntiAliasing()
988 QDomElement matchNode = m_doc.createElement("match"),
989 typeNode = m_doc.createElement("bool"),
990 editNode = m_doc.createElement("edit");
991 QDomText typeText = m_doc.createTextNode(m_antiAliasing.set ? "true" : "false");
993 matchNode.setAttribute("target", "font");
994 editNode.setAttribute("mode", "assign");
995 editNode.setAttribute("name", "antialias");
996 editNode.appendChild(typeNode);
997 typeNode.appendChild(typeText);
998 matchNode.appendChild(editNode);
999 if(!m_antiAliasing.node.isNull())
1000 m_doc.documentElement().removeChild(m_antiAliasing.node);
1001 m_doc.documentElement().appendChild(matchNode);
1002 m_antiAliasing.node=matchNode;
1005 // KXftConfig only parses one config file, user's .fonts.conf usually.
1006 // If that one doesn't exist, then KXftConfig doesn't know if antialiasing
1007 // is enabled or not. So try to find out the default value from the default font.
1008 // Maybe there's a better way *shrug*.
1009 bool KXftConfig::aliasingEnabled()
1011 FcPattern *pattern = FcPatternCreate();
1012 FcConfigSubstitute(0, pattern, FcMatchPattern);
1013 FcDefaultSubstitute(pattern);
1014 FcResult result;
1015 FcPattern *f = FcFontMatch( 0, pattern, &result );
1016 FcBool antialiased = FcTrue;
1017 FcPatternGetBool( f, FC_ANTIALIAS, 0, &antialiased );
1018 FcPatternDestroy( f );
1019 FcPatternDestroy( pattern );
1020 return antialiased == FcTrue;
1023 #endif