diff options
Diffstat (limited to 'kcontrol/kfontinst/lib')
-rw-r--r-- | kcontrol/kfontinst/lib/FcEngine.cpp | 1179 | ||||
-rw-r--r-- | kcontrol/kfontinst/lib/FcEngine.h | 118 | ||||
-rw-r--r-- | kcontrol/kfontinst/lib/KfiConstants.h | 73 | ||||
-rw-r--r-- | kcontrol/kfontinst/lib/Makefile.am | 14 | ||||
-rw-r--r-- | kcontrol/kfontinst/lib/Misc.cpp | 238 | ||||
-rw-r--r-- | kcontrol/kfontinst/lib/Misc.h | 76 |
6 files changed, 1698 insertions, 0 deletions
diff --git a/kcontrol/kfontinst/lib/FcEngine.cpp b/kcontrol/kfontinst/lib/FcEngine.cpp new file mode 100644 index 000000000..0b3e51767 --- /dev/null +++ b/kcontrol/kfontinst/lib/FcEngine.cpp @@ -0,0 +1,1179 @@ +#include <qpainter.h> +#include <qpixmap.h> +#include <qfontmetrics.h> +#include <qfile.h> +#include <qtextstream.h> +#include <kurl.h> +#include <kconfig.h> +#include <kglobalsettings.h> +#include <kio/netaccess.h> +#include <math.h> +#include "FcEngine.h" +#include "KfiConstants.h" +#ifdef HAVE_XFT +#include <X11/Xlib.h> +#include <X11/Xft/Xft.h> +#include <fixx11h.h> +#endif + +#define KFI_HAVE_OBLIQUE // Do we differentiate between Italic and Oblique? +#define KFI_HAVE_MEDIUM_WEIGHT // Do we differentiate between Medium and Normal weights? + +#define KFI_PREVIEW_GROUP "Preview Settings" +#define KFI_PREVIEW_STRING_KEY "String" + +#ifdef HAVE_XFT +#define KFI_DISPLAY(pix) (pix ? pix->x11Display() : QPaintDevice::x11AppDisplay()) +#endif + +namespace KFI +{ + +const int CFcEngine::constScalableSizes[]={8, 10, 12, 24, 36, 48, 64, 72, 96, 0 }; +const int CFcEngine::constDefaultAlphaSize=24; + +static int fcWeight(int weight) +{ + if(weight<FC_WEIGHT_ULTRALIGHT) + return FC_WEIGHT_THIN; + + if(weight<(FC_WEIGHT_ULTRALIGHT+FC_WEIGHT_LIGHT)/2) + return FC_WEIGHT_ULTRALIGHT; + + if(weight<(FC_WEIGHT_LIGHT+FC_WEIGHT_NORMAL)/2) + return FC_WEIGHT_LIGHT; + +#ifdef KFI_HAVE_MEDIUM_WEIGHT + if(weight<(FC_WEIGHT_NORMAL+FC_WEIGHT_MEDIUM)/2) + return FC_WEIGHT_NORMAL; + + if(weight<(FC_WEIGHT_MEDIUM+FC_WEIGHT_SEMIBOLD)/2) + return FC_WEIGHT_MEDIUM; +#else + if(weight<(FC_WEIGHT_NORMAL+FC_WEIGHT_SEMIBOLD)/2) + return FC_WEIGHT_NORMAL; +#endif + + if(weight<(FC_WEIGHT_SEMIBOLD+FC_WEIGHT_BOLD)/2) + return FC_WEIGHT_SEMIBOLD; + + if(weight<(FC_WEIGHT_BOLD+FC_WEIGHT_ULTRABOLD)/2) + return FC_WEIGHT_BOLD; + + if(weight<(FC_WEIGHT_ULTRABOLD+FC_WEIGHT_HEAVY)/2) + return FC_WEIGHT_ULTRABOLD; + + return FC_WEIGHT_HEAVY; +} + +static int fcToQtWeight(int weight) +{ + switch(weight) + { + case FC_WEIGHT_THIN: + return 0; + case FC_WEIGHT_ULTRALIGHT: + return QFont::Light>>1; + case FC_WEIGHT_LIGHT: + return QFont::Light; + default: + case FC_WEIGHT_NORMAL: + return QFont::Normal; + case FC_WEIGHT_MEDIUM: +#ifdef KFI_HAVE_MEDIUM_WEIGHT + return (QFont::Normal+QFont::DemiBold)>>1; +#endif + return QFont::Normal; + case FC_WEIGHT_SEMIBOLD: + return QFont::DemiBold; + case FC_WEIGHT_BOLD: + return QFont::Bold; + case FC_WEIGHT_ULTRABOLD: + return (QFont::Bold+QFont::Black)>>1; + case FC_WEIGHT_HEAVY: + return QFont::Black; + } +} + +#ifndef KFI_FC_NO_WIDTHS +static int fcWidth(int width) +{ + if(width<FC_WIDTH_EXTRACONDENSED) + return FC_WIDTH_ULTRACONDENSED; + + if(width<(FC_WIDTH_EXTRACONDENSED+FC_WIDTH_CONDENSED)/2) + return FC_WIDTH_EXTRACONDENSED; + + if(width<(FC_WIDTH_CONDENSED+FC_WIDTH_SEMICONDENSED)/2) + return FC_WIDTH_CONDENSED; + + if(width<(FC_WIDTH_SEMICONDENSED+FC_WIDTH_NORMAL)/2) + return FC_WIDTH_SEMICONDENSED; + + if(width<(FC_WIDTH_NORMAL+FC_WIDTH_SEMIEXPANDED)/2) + return FC_WIDTH_NORMAL; + + if(width<(FC_WIDTH_SEMIEXPANDED+FC_WIDTH_EXPANDED)/2) + return FC_WIDTH_SEMIEXPANDED; + + if(width<(FC_WIDTH_EXPANDED+FC_WIDTH_EXTRAEXPANDED)/2) + return FC_WIDTH_EXPANDED; + + if(width<(FC_WIDTH_EXTRAEXPANDED+FC_WIDTH_ULTRAEXPANDED)/2) + return FC_WIDTH_EXTRAEXPANDED; + + return FC_WIDTH_ULTRAEXPANDED; +} + +static int fcToQtWidth(int weight) +{ + switch(weight) + { + case FC_WIDTH_ULTRACONDENSED: + return QFont::UltraCondensed; + case FC_WIDTH_EXTRACONDENSED: + return QFont::ExtraCondensed; + case FC_WIDTH_CONDENSED: + return QFont::Condensed; + case FC_WIDTH_SEMICONDENSED: + return QFont::SemiCondensed; + default: + case FC_WIDTH_NORMAL: + return QFont::Unstretched; + case FC_WIDTH_SEMIEXPANDED: + return QFont::SemiExpanded; + case FC_WIDTH_EXPANDED: + return QFont::Expanded; + case FC_WIDTH_EXTRAEXPANDED: + return QFont::ExtraExpanded; + case FC_WIDTH_ULTRAEXPANDED: + return QFont::UltraExpanded; + } +} +#endif + +static int fcSlant(int slant) +{ + if(slant<FC_SLANT_ITALIC) + return FC_SLANT_ROMAN; + +#ifdef KFI_HAVE_OBLIQUE + if(slant<(FC_SLANT_ITALIC+FC_SLANT_OBLIQUE)/2) + return FC_SLANT_ITALIC; + + return FC_SLANT_OBLIQUE; +#else + return FC_SLANT_ITALIC; +#endif +} + +static bool fcToQtSlant(int slant) +{ + return FC_SLANT_ROMAN==slant ? false : true; +} + +static int fcSpacing(int spacing) +{ + if(spacing<FC_MONO) + return FC_PROPORTIONAL; + + if(spacing<(FC_MONO+FC_CHARCELL)/2) + return FC_MONO; + + return FC_CHARCELL; +} + +static int strToWeight(const QString &str, QString &newStr) +{ + if(0==str.find(i18n(KFI_WEIGHT_THIN), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_THIN).length()); + return FC_WEIGHT_THIN; + } + if(0==str.find(i18n(KFI_WEIGHT_EXTRALIGHT), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_EXTRALIGHT).length()); + return FC_WEIGHT_EXTRALIGHT; + } + if(0==str.find(i18n(KFI_WEIGHT_ULTRALIGHT), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_ULTRALIGHT).length()); + return FC_WEIGHT_ULTRALIGHT; + } + if(0==str.find(i18n(KFI_WEIGHT_LIGHT), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_LIGHT).length()); + return FC_WEIGHT_LIGHT; + } + if(0==str.find(i18n(KFI_WEIGHT_REGULAR), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_REGULAR).length()); + return FC_WEIGHT_REGULAR; + } + if(0==str.find(i18n(KFI_WEIGHT_NORMAL), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_NORMAL).length()); + return FC_WEIGHT_NORMAL; + } + if(0==str.find(i18n(KFI_WEIGHT_MEDIUM), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_MEDIUM).length()); + return FC_WEIGHT_MEDIUM; + } + if(0==str.find(i18n(KFI_WEIGHT_DEMIBOLD), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_DEMIBOLD).length()); + return FC_WEIGHT_SEMIBOLD; + } + if(0==str.find(i18n(KFI_WEIGHT_SEMIBOLD), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_SEMIBOLD).length()); + return FC_WEIGHT_SEMIBOLD; + } + if(0==str.find(i18n(KFI_WEIGHT_BOLD), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_BOLD).length()); + return FC_WEIGHT_BOLD; + } + if(0==str.find(i18n(KFI_WEIGHT_EXTRABOLD), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_EXTRABOLD).length()); + return FC_WEIGHT_EXTRABOLD; + } + if(0==str.find(i18n(KFI_WEIGHT_ULTRABOLD), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_ULTRABOLD).length()); + return FC_WEIGHT_ULTRABOLD; + } + if(0==str.find(i18n(KFI_WEIGHT_BLACK), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_BLACK).length()); + return FC_WEIGHT_BLACK; + } + if(0==str.find(i18n(KFI_WEIGHT_HEAVY), 0, false)) + { + newStr=str.mid(i18n(KFI_WEIGHT_HEAVY).length()); + return FC_WEIGHT_HEAVY; + } + + newStr=str; + return FC_WEIGHT_REGULAR; +} + +#ifndef KFI_FC_NO_WIDTHS +static int strToWidth(const QString &str, QString &newStr) +{ + if(0==str.find(i18n(KFI_WIDTH_ULTRACONDENSED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_ULTRACONDENSED).length()); + return FC_WIDTH_ULTRACONDENSED; + } + if(0==str.find(i18n(KFI_WIDTH_EXTRACONDENSED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_EXTRACONDENSED).length()); + return FC_WIDTH_EXTRACONDENSED; + } + if(0==str.find(i18n(KFI_WIDTH_CONDENSED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_CONDENSED).length()); + return FC_WIDTH_CONDENSED; + } + if(0==str.find(i18n(KFI_WIDTH_SEMICONDENSED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_SEMICONDENSED).length()); + return FC_WIDTH_SEMICONDENSED; + } + if(0==str.find(i18n(KFI_WIDTH_NORMAL), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_NORMAL).length()); + return FC_WIDTH_NORMAL; + } + if(0==str.find(i18n(KFI_WIDTH_SEMIEXPANDED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_SEMIEXPANDED).length()); + return FC_WIDTH_SEMIEXPANDED; + } + if(0==str.find(i18n(KFI_WIDTH_EXPANDED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_EXPANDED).length()); + return FC_WIDTH_EXPANDED; + } + if(0==str.find(i18n(KFI_WIDTH_EXTRAEXPANDED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_EXTRAEXPANDED).length()); + return FC_WIDTH_EXTRAEXPANDED; + } + if(0==str.find(i18n(KFI_WIDTH_ULTRAEXPANDED), 0, false)) + { + newStr=str.mid(i18n(KFI_WIDTH_ULTRAEXPANDED).length()); + return FC_WIDTH_ULTRAEXPANDED; + } + + newStr=str; + return FC_WIDTH_NORMAL; +} +#endif + +static int strToSlant(const QString &str) +{ + if(-1!=str.find(i18n(KFI_SLANT_ITALIC))) + return FC_SLANT_ITALIC; + if(-1!=str.find(i18n(KFI_SLANT_OBLIQUE))) + return FC_SLANT_OBLIQUE; + return FC_SLANT_ROMAN; +} + +static void drawText(QPainter &painter, int x, int y, int width, const QString &str) +{ + QString s(str); + bool addedElipses=false; + + width-=x*2; + while(s.length()>3 && painter.fontMetrics().size(0, s).width()>width) + { + if(!addedElipses) + { + s.remove(s.length()-2, 2); + s.append("..."); + addedElipses=true; + } + else + s.remove(s.length()-4, 1); + } + painter.drawText(x, y, s); +} + +inline bool equal(double d1, double d2) +{ + return (fabs(d1 - d2) < 0.0001); +} + +inline bool equalWeight(int a, int b) +{ + return a==b || fcWeight(a)==fcWeight(b); +} + +#ifndef KFI_FC_NO_WIDTHS +inline bool equalWidth(int a, int b) +{ + return a==b || fcWidth(a)==fcWidth(b); +} +#endif + +inline bool equalSlant(int a, int b) +{ + return a==b || fcSlant(a)==fcSlant(b); +} + +#ifdef HAVE_XFT +static bool drawChar(QPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, const QString &text, int pos, + int &x, int &y, int w, int h, int fSize, int offset) +{ + XGlyphInfo extents; + const FcChar16 *str=(FcChar16 *)(&(text.ucs2()[pos])); + + XftTextExtents16(pix.x11Display(), xftFont, str, 1, &extents); + + if(x+extents.width+2>w) + { + x=offset; + y+=fSize; + } + + if(y+offset<h) + { + XftDrawString16(xftDraw, xftCol, xftFont, x, y, str, 1); + x+=extents.width+2; + return true; + } + return false; +} + +static bool drawString(QPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, const QString &text, + int x, int &y, int h, int offset) +{ + XGlyphInfo extents; + const FcChar16 *str=(FcChar16 *)(text.ucs2()); + + XftTextExtents16(pix.x11Display(), xftFont, str, text.length(), &extents); + if(y+extents.height<h) + XftDrawString16(xftDraw, xftCol, xftFont, x, y+extents.y, str, text.length()); + if(extents.height>0) + { + y+=extents.height+offset; + return true; + } + return false; +} + +static bool drawGlyph(QPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, FT_UInt i, + int &x, int &y, int &w, int &h, int fSize, int offset) +{ + XGlyphInfo extents; + + XftGlyphExtents(pix.x11Display(), xftFont, &i, 1, &extents); + + if(x+extents.width+2>w) + { + x=offset; + y+=fSize; + } + + if(y+offset<h) + { + XftDrawGlyphs(xftDraw, xftCol, xftFont, x, y, &i, 1); + x+=extents.width+2; + return true; + } + return false; +} + +inline int point2Pixel(int point) +{ + return (point*QPaintDevice::x11AppDpiX()+36)/72; +} + +static bool hasStr(XftFont *font, QString &str) +{ + unsigned int slen=str.length(), + ch; + + for(ch=0; ch<slen; ++ch) + if(!FcCharSetHasChar(font->charset, str[ch].unicode())) + return false; + return true; +} +#endif + +CFcEngine::CFcEngine() + : itsIndex(-1), + itsIndexCount(1) +{ +} + +CFcEngine::~CFcEngine() +{ + // Clear any fonts that may have been added... + FcConfigAppFontClear(FcConfigGetCurrent()); +} + +QString CFcEngine::getName(const KURL &url, int faceNo) +{ + if(url!=itsLastUrl || faceNo!=itsIndex) + parseUrl(url, faceNo); + + return itsDescriptiveName; +} + +#ifdef HAVE_XFT +bool CFcEngine::draw(const KURL &url, int w, int h, QPixmap &pix, int faceNo, bool thumb) +{ + bool rv=false; + + if((url==itsLastUrl && faceNo==itsIndex) || parseUrl(url, faceNo)) + { + rv=true; + + if(!itsInstalled) // Then add to fontconfig's list, so that Xft can display it... + { + FcInitReinitialize(); + FcConfigAppFontAddFile(FcConfigGetCurrent(), (const FcChar8 *)(itsName.utf8().data())); + } + + if(thumb && (w!=h || h>128)) + thumb=false; + + int offset=thumb + ? h<=32 + ? 2 + : 3 + : 4, + x=offset, y=offset; + + pix.resize(w, h); + pix.fill(Qt::white); + + QPainter painter(&pix); + + getSizes(&pix); + + if(itsSizes.size()) + { + XRenderColor xrenderCol; + XftColor xftCol; + + xrenderCol.red=xrenderCol.green=xrenderCol.blue=0; + xrenderCol.alpha=0xffff; + XftColorAllocValue(pix.x11Display(), DefaultVisual(pix.x11Display(), + pix.x11Screen()), + DefaultColormap(pix.x11Display(), pix.x11Screen()), + &xrenderCol, &xftCol); + + XftDraw *xftDraw=XftDrawCreate(pix.x11Display(), (Pixmap)(pix.handle()), + (Visual*)(pix.x11Visual()), pix.x11Colormap()); + + if(xftDraw) + { + XftFont *xftFont=NULL; + bool drawGlyphs=false; + + if(thumb) + { + QString text(i18n("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789")); + + // + // Calculate size of text... + int fSize= h <= 32 + ? h-(offset*2) // 1 line of chars... + : h <= 64 + ? (h-(offset*3))/2 // 2 lines... + : (h-(offset*4))/3; // 3 lines or more + + if(!itsScalable) // Then need to get nearest size... + { + int bSize=fSize; + + for(unsigned int s=0; s<itsSizes.size(); ++s) + if (itsSizes[s]<=fSize) + bSize=itsSizes[s]; + fSize=bSize; + } + + unsigned int ch; + + xftFont=getFont(fSize, &pix); + + y=fSize; + if(xftFont) + { + drawGlyphs=!hasStr(xftFont, text); + + if(!drawGlyphs) + for(ch=0; ch<text.length(); ++ch) // Display char by char so that it wraps... + if(!drawChar(pix, xftDraw, xftFont, &xftCol, text, ch, x, y, w, h, fSize, offset)) + break; + if(drawGlyphs) + { + FT_Face face=XftLockFace(xftFont); + + if(face) + { + for(int i=1; i<face->num_glyphs && y<w; ++i) // Glyph 0 is the NULL glyph + if(!drawGlyph(pix, xftDraw, xftFont, &xftCol, i, x, y, w, h, fSize, offset)) + break; + + XftUnlockFace(xftFont); + } + } + } + } + else + { + QString lowercase(getLowercaseLetters()), + uppercase(getUppercaseLetters()), + punctuation(getPunctuation()), + title(itsDescriptiveName.isEmpty() + ? i18n("ERROR: Could not determine font's name.") + : itsDescriptiveName); + + if(1==itsSizes.size()) + title=i18n("%1 [1 pixel]", "%1 [%n pixels]", itsSizes[0]).arg(title); + + painter.setFont(KGlobalSettings::generalFont()); + painter.setPen(Qt::black); + y=painter.fontMetrics().height(); + drawText(painter, x, y, w-offset, title); + y+=4; + painter.drawLine(offset, y, w-(offset+1), y); + y+=8; + + bool lc=true, + uc=true, + punc=true; + + xftFont=getFont(itsAlphaSize, &pix); + if(xftFont) + { + lc=hasStr(xftFont, lowercase); + uc=hasStr(xftFont, uppercase); + punc=hasStr(xftFont, punctuation); + + drawGlyphs=!lc && !uc; + + if(!drawGlyphs) + { + if(lc) + drawString(pix, xftDraw, xftFont, &xftCol, lowercase, x, y, h, offset); + if(uc) + drawString(pix, xftDraw, xftFont, &xftCol, uppercase, x, y, h, offset); + if(punc) + drawString(pix, xftDraw, xftFont, &xftCol, punctuation, x, y, h, offset); + XftFontClose(pix.x11Display(), xftFont); + if(lc || uc || punc) + painter.drawLine(offset, y, w-(offset+1), y); + y+=8; + } + + QString previewString(getPreviewString()); + bool stop=false; + + if(!drawGlyphs) + { + if(!lc && uc) + previewString=previewString.upper(); + if(!uc && lc) + previewString=previewString.lower(); + } + + for(unsigned int s=0; s<itsSizes.size(); ++s) + { + xftFont=getFont(itsSizes[s], &pix); + + if(xftFont) + { + if(drawGlyphs) + { + FT_Face face=XftLockFace(xftFont); + + if(face) + { + int space=itsSizes[s]/10; + XGlyphInfo extents; + + if(!space) + space=1; + + for(int i=1; i<face->num_glyphs && y<w && !stop; ++i) + { + XftGlyphExtents(pix.x11Display(), xftFont, (const FT_UInt *)&i, 1, &extents); + + if(y+extents.height>h) + stop=true; + else + { + if(x+extents.width<w) + XftDrawGlyphs(xftDraw, &xftCol, xftFont, x, y+extents.y, + (const FT_UInt *)&i, 1); + if(extents.width>0) + x+=extents.width+space; + } + if(x>=w || i==face->num_glyphs-1) + { + y+=itsSizes[s]+offset; + x=offset; + break; + } + } + + XftUnlockFace(xftFont); + } + } + else + drawString(pix, xftDraw, xftFont, &xftCol, previewString, x, y, h, offset); + XftFontClose(pix.x11Display(), xftFont); + } + } + } + } + + XftDrawDestroy(xftDraw); + } + } + } + + return rv; +} +#endif + +QString CFcEngine::getPreviewString() +{ + KConfig cfg(KFI_UI_CFG_FILE); + + cfg.setGroup(KFI_PREVIEW_GROUP); + + QString str(cfg.readEntry(KFI_PREVIEW_STRING_KEY)); + + return str.isEmpty() ? i18n("A sentence that uses all of the letters of the alphabet", + "The quick brown fox jumps over the lazy dog") + : str; +} + +void CFcEngine::setPreviewString(const QString &str) +{ + KConfig cfg(KFI_UI_CFG_FILE); + + cfg.setGroup(KFI_PREVIEW_GROUP); + cfg.writeEntry(KFI_PREVIEW_STRING_KEY, str); +} + +QString CFcEngine::getUppercaseLetters() +{ + return i18n("All of the letters of the alphabet, uppercase", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); +} + +QString CFcEngine::getLowercaseLetters() +{ + return i18n("All of the letters of the alphabet, lowercase", "abcdefghijklmnopqrstuvwxyz"); +} + +QString CFcEngine::getPunctuation() +{ + return i18n("Numbers and characters", "0123456789.:,;(*!?'/\\\")£$€%^&-+@~#<>{}[]"); +} + +QString CFcEngine::getFcString(FcPattern *pat, const char *val, int faceNo) +{ + QString rv; + FcChar8 *fcStr; + + if(FcResultMatch==FcPatternGetString(pat, val, faceNo, &fcStr)) + rv=QString::fromUtf8((char *)fcStr); + + return rv; +} + +QString CFcEngine::createName(FcPattern *pat, int faceNo) +{ +//CPD: TODO: the names *need* to match up with kfontchooser's... + QString name(getFcString(pat, FC_FAMILY, faceNo)), + str; + int intVal; + bool comma=false; + + if (FcResultMatch==FcPatternGetInteger(pat, FC_WEIGHT, faceNo, &intVal)) + { + str=weightStr(intVal); + if(!str.isEmpty()) + { + name+=QString(", ")+str; + comma=true; + } + } + + if (FcResultMatch==FcPatternGetInteger(pat, FC_SLANT, faceNo, &intVal)) + { + str=slantStr(intVal); + if(!str.isEmpty()) + { + if(!comma) + { + name+=QChar(','); + comma=true; + } + name+=QChar(' ')+str; + } + } + +#ifndef KFI_FC_NO_WIDTHS + if (FcResultMatch==FcPatternGetInteger(pat, FC_WIDTH, faceNo, &intVal)) + { + str=widthStr(intVal); + if(!str.isEmpty()) + name+=QChar(' ')+str; + } +#endif + + return name; +} + +QString CFcEngine::weightStr(int weight, bool emptyNormal) +{ + switch(fcWeight(weight)) + { + case FC_WEIGHT_THIN: + return i18n(KFI_WEIGHT_THIN); + case FC_WEIGHT_ULTRALIGHT: + return i18n(KFI_WEIGHT_ULTRALIGHT); + case FC_WEIGHT_LIGHT: + return i18n(KFI_WEIGHT_LIGHT); + case FC_WEIGHT_NORMAL: + return emptyNormal ? QString::null : i18n(KFI_WEIGHT_NORMAL); + case FC_WEIGHT_MEDIUM: + return i18n(KFI_WEIGHT_MEDIUM); + case FC_WEIGHT_DEMIBOLD: + return i18n(KFI_WEIGHT_SEMIBOLD); + case FC_WEIGHT_BOLD: + return i18n(KFI_WEIGHT_BOLD); + case FC_WEIGHT_ULTRABOLD: + return i18n(KFI_WEIGHT_ULTRABOLD); + default: + return i18n(KFI_WEIGHT_HEAVY); + } +} + +#ifndef KFI_FC_NO_WIDTHS +QString CFcEngine::widthStr(int width, bool emptyNormal) +{ + switch(fcWidth(width)) + { + case FC_WIDTH_ULTRACONDENSED: + return i18n(KFI_WIDTH_ULTRACONDENSED); + case FC_WIDTH_EXTRACONDENSED: + return i18n(KFI_WIDTH_EXTRACONDENSED); + case FC_WIDTH_CONDENSED: + return i18n(KFI_WIDTH_CONDENSED); + case FC_WIDTH_SEMICONDENSED: + return i18n(KFI_WIDTH_SEMICONDENSED); + case FC_WIDTH_NORMAL: + return emptyNormal ? QString::null : i18n(KFI_WIDTH_NORMAL); + case FC_WIDTH_SEMIEXPANDED: + return i18n(KFI_WIDTH_SEMIEXPANDED); + case FC_WIDTH_EXPANDED: + return i18n(KFI_WIDTH_EXPANDED); + case FC_WIDTH_EXTRAEXPANDED: + return i18n(KFI_WIDTH_EXTRAEXPANDED); + default: + return i18n(KFI_WIDTH_ULTRAEXPANDED); + } +} +#endif + +QString CFcEngine::slantStr(int slant, bool emptyNormal) +{ + switch(fcSlant(slant)) + { + case FC_SLANT_OBLIQUE: + return i18n(KFI_SLANT_OBLIQUE); + case FC_SLANT_ITALIC: + return i18n(KFI_SLANT_ITALIC); + default: + return emptyNormal ? QString::null : i18n(KFI_SLANT_ROMAN); + } +} + +QString CFcEngine::spacingStr(int spacing) +{ + switch(fcSpacing(spacing)) + { + case FC_MONO: + return i18n(KFI_SPACING_MONO); + case FC_CHARCELL: + return i18n(KFI_SPACING_CHARCELL); + default: + return i18n(KFI_SPACING_PROPORTIONAL); + } +} + +bool CFcEngine::getInfo(const KURL &url, int faceNo, QString &full, QString &family, QString &foundry, QString &weight, +#ifndef KFI_FC_NO_WIDTHS + QString &width, +#endif + QString &spacing, QString &slant) +{ + if(parseUrl(url, faceNo, true)) + { + full=itsDescriptiveName; + if(url.isLocalFile()) + { + int pos; + + if(-1==(pos=itsDescriptiveName.find(", "))) // No style information... + family=itsDescriptiveName; + else + family=itsDescriptiveName.left(pos); + } + else + family=itsName; + weight=weightStr(itsWeight, false); +#ifndef KFI_FC_NO_WIDTHS + width=widthStr(itsWidth, false); +#endif + slant=slantStr(itsSlant, false); + spacing=spacingStr(itsSpacing); + foundry=itsFoundry; + return true; + } + + return false; +} + +QFont CFcEngine::getQFont(const QString &name, int size) +{ + parseName(name, 0, false); + + QFont font(itsName, size, fcToQtWeight(itsWeight), fcToQtSlant(itsSlant)); + +#ifndef KFI_FC_NO_WIDTHS + font.setStretch(fcToQtWidth(itsWidth)); +#endif + return font; +} + +bool CFcEngine::parseUrl(const KURL &url, int faceNo, bool all) +{ + FcInitLoadConfigAndFonts(); + + // Possible urls: + // + // fonts:/times.ttf + // fonts:/System/times.ttf + // file:/home/wibble/hmm.ttf + // + if(KFI_KIO_FONTS_PROTOCOL==url.protocol()) + { + KIO::UDSEntry udsEntry; + QString name; + + FcInitReinitialize(); + if(KIO::NetAccess::stat(url, udsEntry, NULL)) // Need to stat the url to get its font name... + { + KIO::UDSEntry::Iterator it(udsEntry.begin()), + end(udsEntry.end()); + + for( ; it != end; ++it) + if (KIO::UDS_NAME==(*it).m_uds) + { + name=(*it).m_str; + break; + } + } + + if(!name.isEmpty()) + { + parseName(name, faceNo, all); + itsInstalled=true; + } + else + return false; + } + else if(url.isLocalFile()) + { + // Now lets see if its from the thumbnail job! if so, then file will just contain the URL! + QFile file(url.path()); + bool isThumbnailUrl=false; + + if(file.size()<2048 && file.open(IO_ReadOnly)) // Urls should be less than 2k, and fonts usually above! + { + QString thumbUrl; + QTextStream stream(&file); + + thumbUrl=stream.readLine(); + isThumbnailUrl=0==thumbUrl.find(KFI_KIO_FONTS_PROTOCOL) && parseUrl(KURL(thumbUrl), faceNo, all); + file.close(); + } + + if(!isThumbnailUrl) // Its not a thumbnail, so read the real font file... + { + itsName=url.path(); + + int count; + FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(itsName).data()), 0, NULL, &count); + + itsWeight=FC_WEIGHT_NORMAL; +#ifndef KFI_FC_NO_WIDTHS + itsWidth=FC_WIDTH_NORMAL; +#endif + itsSlant=FC_SLANT_ROMAN; + itsSpacing=FC_PROPORTIONAL; + + if(pat) + { + itsDescriptiveName=createName(pat, faceNo); + + if(all) + { + FcPatternGetInteger(pat, FC_WEIGHT, faceNo, &itsWeight); + FcPatternGetInteger(pat, FC_SLANT, faceNo, &itsSlant); +#ifndef KFI_FC_NO_WIDTHS + FcPatternGetInteger(pat, FC_WIDTH, faceNo, &itsWidth); +#endif + FcPatternGetInteger(pat, FC_SPACING, faceNo, &itsSpacing); + itsFoundry=getFcString(pat, FC_FOUNDRY, faceNo); + } + + FcPatternDestroy(pat); + } + else + itsDescriptiveName=QString::null; + + itsInstalled=false; + itsIndex=faceNo; + } + } + else + return false; + + itsLastUrl=url; + return true; +} + +void CFcEngine::parseName(const QString &name, int faceNo, bool all) +{ + int pos; + + itsDescriptiveName=name; + itsSpacing=FC_PROPORTIONAL; + if(-1==(pos=name.find(", "))) // No style information... + { + itsWeight=FC_WEIGHT_NORMAL; +#ifndef KFI_FC_NO_WIDTHS + itsWidth=FC_WIDTH_NORMAL; +#endif + itsSlant=FC_SLANT_ROMAN; + itsName=name; + } + else + { + QString style(name.mid(pos+2)); + + itsWeight=strToWeight(style, style); +#ifndef KFI_FC_NO_WIDTHS + itsWidth=strToWidth(style, style); +#endif + itsSlant=strToSlant(style); + itsName=name.left(pos); + } + + if(all) + { + FcObjectSet *os = FcObjectSetBuild(FC_SPACING, FC_FOUNDRY, (void *)0); + FcPattern *pat = FcPatternBuild(NULL, + FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.utf8().data()), + FC_WEIGHT, FcTypeInteger, itsWeight, + FC_SLANT, FcTypeInteger, itsSlant, +#ifndef KFI_FC_NO_WIDTHS + FC_WIDTH, FcTypeInteger, itsWidth, +#endif + NULL); + FcFontSet *set = FcFontList(0, pat, os); + + FcPatternDestroy(pat); + FcObjectSetDestroy(os); + + if(set && set->nfont) + { + FcPatternGetInteger(set->fonts[0], FC_SPACING, faceNo, &itsSpacing); + itsFoundry=getFcString(set->fonts[0], FC_FOUNDRY, faceNo); + } + } + + itsIndex=0; // Doesn't matter, as we're gonna use font name! + itsLastUrl=KURL(); +} + +#ifdef HAVE_XFT +XftFont * CFcEngine::getFont(int size, QPixmap *pix) +{ + if(itsInstalled) + return XftFontOpen(KFI_DISPLAY(pix), 0, + FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.utf8().data()), + FC_WEIGHT, FcTypeInteger, itsWeight, + FC_SLANT, FcTypeInteger, itsSlant, +#ifndef KFI_FC_NO_WIDTHS + FC_WIDTH, FcTypeInteger, itsWidth, +#endif + FC_PIXEL_SIZE, FcTypeDouble, (double)size, + NULL); + else + { + FcPattern *pattern = FcPatternBuild(NULL, + FC_FILE, FcTypeString, QFile::encodeName(itsName).data(), + FC_INDEX, FcTypeInteger, itsIndex, + FC_PIXEL_SIZE, FcTypeDouble, (double)size, + NULL); + return XftFontOpenPattern(KFI_DISPLAY(pix), pattern); + } +} + +void CFcEngine::getSizes(QPixmap *pix) +{ + static const int constNumSizes=11; + static const int constNumSizeRanges=2; + static const int constSizes[constNumSizeRanges][constNumSizes]= { {8, 10, 12, 14, 16, 18, 24, 36, 48, 72, 96}, + {7, 9, 11, 13, 15, 17, 23, 35, 47, 71, 95} }; + XftFont *f=getFont(8, pix); + + itsScalable=FcTrue; + + itsSizes.clear(); + itsAlphaSize=0; + + if(f) + { + bool gotSizes=false; + + if(itsInstalled) + { + if(FcResultMatch!=FcPatternGetBool(f->pattern, FC_SCALABLE, 0, &itsScalable)) + itsScalable=FcFalse; + } + else + { + FT_Face face=XftLockFace(f); + + if(face) + { + itsIndexCount=face->num_faces; + if(!(itsScalable=FT_IS_SCALABLE(face))) + { + int numSizes=face->num_fixed_sizes, + size; + + gotSizes=true; + + itsSizes.reserve(numSizes); + + for (size=0; size<numSizes; size++) + { + itsSizes.push_back(face->available_sizes[size].height); + if (face->available_sizes[size].height<=constDefaultAlphaSize) + itsAlphaSize=face->available_sizes[size].height; + } + } + XftUnlockFace(f); + } + } + + XftFontClose(KFI_DISPLAY(pix), f); + + // + // Hmm... its not a scalable font, and its installed. So to get list of sizes, iterate through a list of standard + // sizes, and ask fontconfig for a font of that sizes. Then check the retured size, family, etc is what was asked + // for! + if(!itsScalable && !gotSizes) + { + itsSizes.reserve(constNumSizes); + + for(int l=0; l<constNumSizeRanges && !gotSizes; ++l) + for(int i=0; i<constNumSizes; ++i) + { + double px; + int iv; + FcChar8 *str; + + f=getFont(constSizes[l][i], pix); + + if(f) + { + if(FcResultMatch==FcPatternGetDouble(f->pattern, FC_PIXEL_SIZE, 0, &px) && equal(constSizes[l][i], px) && + FcResultMatch==FcPatternGetInteger(f->pattern, FC_WEIGHT, 0, &iv) && equalWeight(iv,itsWeight) && + FcResultMatch==FcPatternGetInteger(f->pattern, FC_SLANT, 0, &iv) && equalSlant(iv, itsSlant) && +#ifndef KFI_FC_NO_WIDTHS + FcResultMatch==FcPatternGetInteger(f->pattern, FC_WIDTH, 0, &iv) && equalWidth(iv, itsWidth) && +#endif + FcResultMatch==FcPatternGetString(f->pattern, FC_FAMILY, 0, &str) && str && + QString::fromUtf8((char *)str)==itsName) + { + itsSizes.push_back(constSizes[l][i]); + gotSizes=true; + if(constSizes[l][i]<=constDefaultAlphaSize) + itsAlphaSize=constSizes[l][i]; + } + XftFontClose(KFI_DISPLAY(pix), f); + } + } + } + } + + if(itsScalable) + { + itsSizes.reserve(constNumSizes); + + for (int i=0; constScalableSizes[i]; ++i) + itsSizes.push_back(point2Pixel(constScalableSizes[i])); + itsAlphaSize=constDefaultAlphaSize; + } +} +#endif + +} diff --git a/kcontrol/kfontinst/lib/FcEngine.h b/kcontrol/kfontinst/lib/FcEngine.h new file mode 100644 index 000000000..4a09b8a55 --- /dev/null +++ b/kcontrol/kfontinst/lib/FcEngine.h @@ -0,0 +1,118 @@ +#ifndef __FC_ENGINE_H__ +#define __FC_ENGINE_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <qstring.h> +#include <qvaluevector.h> +#include <qfont.h> +#include <kurl.h> +#include <kdeversion.h> +#include <fontconfig/fontconfig.h> + +#if (FC_VERSION<20200) + +#define KFI_FC_NO_WIDTHS +#define KFI_FC_LIMITED_WEIGHTS + +#endif + +#ifdef KFI_FC_LIMITED_WEIGHTS + +#undef FC_WEIGHT_LIGHT +#define FC_WEIGHT_THIN 0 +#define FC_WEIGHT_EXTRALIGHT 40 +#define FC_WEIGHT_ULTRALIGHT FC_WEIGHT_EXTRALIGHT +#define FC_WEIGHT_LIGHT 50 +#define FC_WEIGHT_BOOK 75 +#define FC_WEIGHT_REGULAR 80 +#define FC_WEIGHT_NORMAL FC_WEIGHT_REGULAR +#define FC_WEIGHT_SEMIBOLD FC_WEIGHT_DEMIBOLD +#define FC_WEIGHT_EXTRABOLD 205 +#define FC_WEIGHT_ULTRABOLD FC_WEIGHT_EXTRABOLD +#define FC_WEIGHT_HEAVY FC_WEIGHT_BLACK + +#endif + +class QPixmap; + +#ifdef HAVE_XFT +typedef struct _XftFont XftFont; +#endif + +namespace KFI +{ + +class KDE_EXPORT CFcEngine +{ + public: + + CFcEngine(); + ~CFcEngine(); + +#ifdef HAVE_XFT + bool draw(const KURL &url, int w, int h, QPixmap &pix, int faceNo, bool thumb); +#endif + int getNumIndexes() { return itsIndexCount; } // Only valid after draw has been called! + QString getName(const KURL &url, int faceNo=0); + bool getInfo(const KURL &url, int faceNo, QString &full, QString &family, QString &foundry, QString &weight, +#ifndef KFI_FC_NO_WIDTHS + QString &width, +#endif + QString &spacing, QString &slant); + QFont getQFont(const QString &name, int size); + + const QValueVector<int> & sizes() const { return itsSizes; } + int alphaSize() const { return itsAlphaSize; } + + static QString getPreviewString(); + static void setPreviewString(const QString &str); + static QString getUppercaseLetters(); + static QString getLowercaseLetters(); + static QString getPunctuation(); + static QString getFcString(FcPattern *pat, const char *val, int faceNo=0); + static QString createName(FcPattern *pat, int faceNo=0); + static QString weightStr(int weight, bool emptyNormal=true); +#ifndef KFI_FC_NO_WIDTHS + static QString widthStr(int width, bool emptyNormal=true); +#endif + static QString slantStr(int slant, bool emptyNormal=true); + static QString spacingStr(int spacing); + + static const int constScalableSizes[]; + static const int constDefaultAlphaSize; + + private: + + bool parseUrl(const KURL &url, int faceNo, bool all=false); + void parseName(const QString &name, int faceNo, bool all=false); +#ifdef HAVE_XFT + XftFont * getFont(int size, QPixmap *pix=NULL); + void getSizes(QPixmap *pix=NULL); +#endif + + private: + + bool itsInstalled; + QString itsName, + itsDescriptiveName, + itsFoundry; + int itsIndex, + itsIndexCount, + itsWeight, +#ifndef KFI_FC_NO_WIDTHS + itsWidth, +#endif + itsSlant, + itsSpacing, + itsAlphaSize; + QValueVector<int> itsSizes; + KURL itsLastUrl; + FcBool itsScalable; +}; + +} + +#endif diff --git a/kcontrol/kfontinst/lib/KfiConstants.h b/kcontrol/kfontinst/lib/KfiConstants.h new file mode 100644 index 000000000..fa7f6f1a0 --- /dev/null +++ b/kcontrol/kfontinst/lib/KfiConstants.h @@ -0,0 +1,73 @@ +#ifndef __KFI_CONSTANTS_H__ +#define __KFI_CONSTANTS_H__ + +#include <klocale.h> + +#define KFI_CATALOGUE "kfontinst" + +// io-slave +#define KFI_KIO_FONTS_PROTOCOL "fonts" +#define KFI_KIO_FONTS_USER I18N_NOOP("Personal") +#define KFI_KIO_FONTS_SYS I18N_NOOP("System") +#define KFI_KIO_NO_CLEAR "?noclear" + +// Config +#define KFI_UI_CFG_FILE KFI_CATALOGUE"uirc" +#define KFI_CFG_FILE KFI_CATALOGUE"rc" +#define KFI_ROOT_CFG_DIR "/etc/fonts/" +#define KFI_ROOT_CFG_FILE KFI_ROOT_CFG_DIR KFI_CFG_FILE +#define KFI_CFG_X_KEY "ConfigureX" +#define KFI_CFG_GS_KEY "ConfigureGS" +#define KFI_DEFAULT_CFG_X true +#define KFI_DEFAULT_CFG_GS false + +// KIO::special + +namespace KFI +{ + +enum ESpecial +{ + SPECIAL_RECONFIG = 0, + SPECIAL_RESCAN = 1 +}; + +} + +// Font name... +#define KFI_WEIGHT_THIN I18N_NOOP("Thin") +#define KFI_WEIGHT_EXTRALIGHT I18N_NOOP("ExtraLight") +#define KFI_WEIGHT_ULTRALIGHT I18N_NOOP("UltraLight") +#define KFI_WEIGHT_LIGHT I18N_NOOP("Light") +#define KFI_WEIGHT_REGULAR I18N_NOOP("Regular") +#define KFI_WEIGHT_NORMAL I18N_NOOP("Normal") +#define KFI_WEIGHT_MEDIUM I18N_NOOP("Medium") +#define KFI_WEIGHT_DEMIBOLD I18N_NOOP("DemiBold") +#define KFI_WEIGHT_SEMIBOLD I18N_NOOP("SemiBold") +#define KFI_WEIGHT_BOLD I18N_NOOP("Bold") +#define KFI_WEIGHT_EXTRABOLD I18N_NOOP("ExtraBold") +#define KFI_WEIGHT_ULTRABOLD I18N_NOOP("UltraBold") +#define KFI_WEIGHT_BLACK I18N_NOOP("Black") +#define KFI_WEIGHT_HEAVY I18N_NOOP("Heavy") + +#define KFI_SLANT_ROMAN I18N_NOOP("Roman") +#define KFI_SLANT_ITALIC I18N_NOOP("Italic") +#define KFI_SLANT_OBLIQUE I18N_NOOP("Oblique") + +#define KFI_WIDTH_ULTRACONDENSED I18N_NOOP("UltraCondensed") +#define KFI_WIDTH_EXTRACONDENSED I18N_NOOP("ExtraCondensed") +#define KFI_WIDTH_CONDENSED I18N_NOOP("Condensed") +#define KFI_WIDTH_SEMICONDENSED I18N_NOOP("SemiCondensed") +#define KFI_WIDTH_NORMAL I18N_NOOP("Normal") +#define KFI_WIDTH_SEMIEXPANDED I18N_NOOP("SemiExpanded") +#define KFI_WIDTH_EXPANDED I18N_NOOP("Expanded") +#define KFI_WIDTH_EXTRAEXPANDED I18N_NOOP("ExtraExpanded") +#define KFI_WIDTH_ULTRAEXPANDED I18N_NOOP("UltraExpanded") + +#define KFI_SPACING_MONO I18N_NOOP("Monospaced") +#define KFI_SPACING_CHARCELL I18N_NOOP("Charcell") +#define KFI_SPACING_PROPORTIONAL I18N_NOOP("Proportional") + +#define KFI_UNKNOWN_FOUNDRY I18N_NOOP("Unknown") + +#endif diff --git a/kcontrol/kfontinst/lib/Makefile.am b/kcontrol/kfontinst/lib/Makefile.am new file mode 100644 index 000000000..55349b149 --- /dev/null +++ b/kcontrol/kfontinst/lib/Makefile.am @@ -0,0 +1,14 @@ +lib_LTLIBRARIES = libkfontinst.la + +libkfontinst_la_SOURCES = \ +Misc.cpp \ +FcEngine.cpp + +noinst_HEADERS = \ +Misc.h \ +FcEngine.h \ +KfiConstants.h + +libkfontinst_la_LIBADD = $(LIB_KDECORE) $(LIBFONTCONFIG_LIBS) $(LIBFREETYPE_LIBS) $(LIB_KIO) $(LIBXFT_LIB) +libkfontinst_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIBFONTCONFIG_RPATH) $(LIBFREETYPE_RPATH) -no-undefined +AM_CPPFLAGS= $(all_includes) $(LIBFREETYPE_CFLAGS) $(LIBFONTCONFIG_CFLAGS) -D_LARGEFILE64_SOURCE diff --git a/kcontrol/kfontinst/lib/Misc.cpp b/kcontrol/kfontinst/lib/Misc.cpp new file mode 100644 index 000000000..4606ad0ca --- /dev/null +++ b/kcontrol/kfontinst/lib/Misc.cpp @@ -0,0 +1,238 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Namespace : KFI::Misc +// Author : Craig Drummond +// Project : K Font Installer +// Creation Date : 01/05/2001 +// Version : $Revision$ $Date$ +// +//////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// +// (C) Craig Drummond, 2001, 2002, 2003, 2004 +//////////////////////////////////////////////////////////////////////////////// + +#include "Misc.h" +#include <qfile.h> +#include <kprocess.h> +#include <kstandarddirs.h> +#include <klargefile.h> +#include <kio/netaccess.h> +#include <unistd.h> + +namespace KFI +{ + +namespace Misc +{ + +QString linkedTo(const QString &i) +{ + QString d; + + if(isLink(i)) + { + char buffer[1000]; + int n=readlink(QFile::encodeName(i), buffer, 1000); + + if(n!=-1) + { + buffer[n]='\0'; + d=buffer; + } + } + + return d; +} + +QString dirSyntax(const QString &d) +{ + if(!d.isEmpty()) + { + QString ds(d); + + ds.replace("//", "/"); + + int slashPos=ds.findRev('/'); + + if(slashPos!=(((int)ds.length())-1)) + ds.append('/'); + + return ds; + } + + return d; +} + +QString xDirSyntax(const QString &d) +{ + if(!d.isEmpty()) + { + QString ds(d); + + ds.replace("//", "/"); + + int slashPos=ds.findRev('/'); + + 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.findRev('/'); + + if(slashPos!=-1) + d.remove(slashPos+1, d.length()); + + return dirSyntax(d); +} + +QString getFile(const QString &f) +{ + QString d(f); + + int slashPos=d.findRev('/'); + + if(slashPos!=-1) + d.remove(0, slashPos+1); + + return d; +} + +bool createDir(const QString &dir) +{ + // + // Clear any umask before dir is created + mode_t oldMask=umask(0000); + bool status=KStandardDirs::makeDir(dir, DIR_PERMS); + // Reset umask + ::umask(oldMask); + return status; +} + +bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3) +{ + KProcess proc; + + proc << cmd; + + if(!p1.isEmpty()) + proc << p1; + if(!p2.isEmpty()) + proc << p2; + if(!p3.isEmpty()) + proc << p3; + + proc.start(KProcess::Block); + + return proc.normalExit() && proc.exitStatus()==0; +} + +QString changeExt(const QString &f, const QString &newExt) +{ + QString newStr(f); + int dotPos=newStr.findRev('.'); + + if(-1==dotPos) + newStr+=QChar('.')+newExt; + else + { + newStr.remove(dotPos+1, newStr.length()); + newStr+=newExt; + } + return newStr; +} + +void createBackup(const QString &f) +{ + const QString constExt(".bak"); + + if(!fExists(f+constExt) && fExists(f)) + doCmd("cp", "-f", f, f+constExt); +} + +// +// 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 getAssociatedUrls(const KURL &url, KURL::List &list, bool afmAndPfm, QWidget *widget) +{ + const char *afm[]={"afm", "AFM", "Afm", "AFm", "AfM", "aFM", "aFm", "afM", NULL}, + *pfm[]={"pfm", "PFM", "Pfm", "PFm", "PfM", "pFM", "pFm", "pfM", NULL}; + bool gotAfm=false, + localFile=url.isLocalFile(); + int e; + + for(e=0; afm[e]; ++e) + { + KURL statUrl(url); + KIO::UDSEntry uds; + + statUrl.setPath(changeExt(url.path(), afm[e])); + + if(localFile ? fExists(statUrl.path()) : KIO::NetAccess::stat(statUrl, uds, widget)) + { + list.append(statUrl); + gotAfm=true; + break; + } + } + + if(afmAndPfm || !gotAfm) + for(e=0; pfm[e]; ++e) + { + KURL statUrl(url); + KIO::UDSEntry uds; + + statUrl.setPath(changeExt(url.path(), pfm[e])); + if(localFile ? fExists(statUrl.path()) : KIO::NetAccess::stat(statUrl, uds, widget)) + { + list.append(statUrl); + break; + } + } +} + +time_t getTimeStamp(const QString &item) +{ + KDE_struct_stat info; + + return !item.isEmpty() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0; +} + + +bool check(const QString &path, unsigned int fmt, bool checkW) +{ + KDE_struct_stat info; + QCString pathC(QFile::encodeName(path)); + + return 0==KDE_lstat(pathC, &info) && (info.st_mode&S_IFMT)==fmt && (!checkW || 0==::access(pathC, W_OK)); +} + +} + +} diff --git a/kcontrol/kfontinst/lib/Misc.h b/kcontrol/kfontinst/lib/Misc.h new file mode 100644 index 000000000..a624f44f9 --- /dev/null +++ b/kcontrol/kfontinst/lib/Misc.h @@ -0,0 +1,76 @@ +#ifndef __MISC_H__ +#define __MISC_H__ + +//////////////////////////////////////////////////////////////////////////////// +// +// Namespace : KFI::Misc +// Author : Craig Drummond +// Project : K Font Installer +// Creation Date : 01/05/2001 +// Version : $Revision$ $Date$ +// +//////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// +// (C) Craig Drummond, 2001, 2002, 2003 +//////////////////////////////////////////////////////////////////////////////// + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <qstring.h> +#include <qstringlist.h> +#include <kurl.h> + +class QWidget; + +namespace KFI +{ + +namespace Misc +{ + enum EConstants + { + FILE_PERMS = 0644, + DIR_PERMS = 0755 + }; + + extern KDE_EXPORT bool check(const QString &path, unsigned int fmt, bool checkW=false); + inline KDE_EXPORT bool fExists(const QString &p) { return check(p, S_IFREG, false); } + inline KDE_EXPORT bool dExists(const QString &p) { return check(p, S_IFDIR, false); } + inline KDE_EXPORT bool fWritable(const QString &p) { return check(p, S_IFREG, true); } + inline KDE_EXPORT bool dWritable(const QString &p) { return check(p, S_IFDIR, true); } + inline KDE_EXPORT bool isLink(const QString &i) { return check(i, S_IFLNK, false); } + extern KDE_EXPORT QString linkedTo(const QString &i); + extern KDE_EXPORT QString dirSyntax(const QString &d); // Has trailing slash: /file/path/ + extern KDE_EXPORT QString xDirSyntax(const QString &d); // No trailing slash: /file/path + inline KDE_EXPORT QString fileSyntax(const QString &f) { return xDirSyntax(f); } + extern KDE_EXPORT QString getDir(const QString &f); + extern KDE_EXPORT QString getFile(const QString &f); + extern KDE_EXPORT bool createDir(const QString &dir); + extern KDE_EXPORT QString changeExt(const QString &f, const QString &newExt); + extern KDE_EXPORT bool doCmd(const QString &cmd, const QString &p1=QString::null, const QString &p2=QString::null, const QString &p3=QString::null); + inline KDE_EXPORT bool root() { return 0==getuid(); } + extern KDE_EXPORT void getAssociatedUrls(const KURL &url, KURL::List &list, bool afmAndPfm=true, QWidget *widget=NULL); + extern KDE_EXPORT void createBackup(const QString &f); + extern KDE_EXPORT time_t getTimeStamp(const QString &item); +} + +} + +#endif |