mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-24 19:02:51 +00:00
971 lines
31 KiB
C++
971 lines
31 KiB
C++
/*
|
|
* KFontInst - KDE Font Installer
|
|
*
|
|
* Copyright 2003-2009 Craig Drummond <craig@kde.org>
|
|
*
|
|
* ----
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <QtDBus/QDBusConnection>
|
|
#include <QtCore/QTimer>
|
|
#include <kauth.h>
|
|
#include <KDebug>
|
|
#include <kio/global.h>
|
|
#include <kde_file.h>
|
|
#include <fontconfig/fontconfig.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include "FontInst.h"
|
|
#include "fontinstadaptor.h"
|
|
#include "Misc.h"
|
|
#include "Fc.h"
|
|
#include "WritingSystems.h"
|
|
#include "Utils.h"
|
|
#include "FontinstIface.h"
|
|
|
|
#define KFI_DBUG kDebug() << time(0L)
|
|
|
|
namespace KFI
|
|
{
|
|
|
|
static void decompose(const QString &name, QString &family, QString &style)
|
|
{
|
|
int commaPos=name.lastIndexOf(',');
|
|
|
|
family=-1==commaPos ? name : name.left(commaPos);
|
|
style=-1==commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos+2);
|
|
}
|
|
|
|
static bool isSystem=false;
|
|
static Folder theFolders[FontInst::FOLDER_COUNT];
|
|
static const int constSystemReconfigured=-1;
|
|
static const int constConnectionsTimeout = 30 * 1000;
|
|
static const int constFontListTimeout = 10 * 1000;
|
|
|
|
typedef void (*SignalHandler)(int);
|
|
|
|
static void registerSignalHandler(SignalHandler handler)
|
|
{
|
|
if (!handler)
|
|
handler = SIG_DFL;
|
|
|
|
sigset_t mask;
|
|
sigemptyset(&mask);
|
|
|
|
#ifdef SIGSEGV
|
|
signal(SIGSEGV, handler);
|
|
sigaddset(&mask, SIGSEGV);
|
|
#endif
|
|
#ifdef SIGFPE
|
|
signal(SIGFPE, handler);
|
|
sigaddset(&mask, SIGFPE);
|
|
#endif
|
|
#ifdef SIGILL
|
|
signal(SIGILL, handler);
|
|
sigaddset(&mask, SIGILL);
|
|
#endif
|
|
#ifdef SIGABRT
|
|
signal(SIGABRT, handler);
|
|
sigaddset(&mask, SIGABRT);
|
|
#endif
|
|
|
|
sigprocmask(SIG_UNBLOCK, &mask, 0);
|
|
}
|
|
|
|
void signalHander(int)
|
|
{
|
|
static bool inHandler=false;
|
|
|
|
if(!inHandler)
|
|
{
|
|
inHandler=true;
|
|
theFolders[isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER].saveDisabled();
|
|
inHandler=false;
|
|
}
|
|
}
|
|
|
|
FontInst::FontInst()
|
|
{
|
|
isSystem=Misc::root();
|
|
registerTypes();
|
|
|
|
new FontinstAdaptor(this);
|
|
QDBusConnection bus=QDBusConnection::sessionBus();
|
|
|
|
KFI_DBUG << "Connecting to session bus";
|
|
if(!bus.registerService(OrgKdeFontinstInterface::staticInterfaceName()))
|
|
{
|
|
KFI_DBUG << "Failed to register service!";
|
|
::exit(-1);
|
|
}
|
|
if(!bus.registerObject(FONTINST_PATH, this))
|
|
{
|
|
KFI_DBUG << "Failed to register object!";
|
|
::exit(-1);
|
|
}
|
|
|
|
registerSignalHandler(signalHander);
|
|
itsConnectionsTimer=new QTimer(this);
|
|
itsFontListTimer=new QTimer(this);
|
|
connect(itsConnectionsTimer, SIGNAL(timeout()), SLOT(connectionsTimeout()));
|
|
connect(itsFontListTimer, SIGNAL(timeout()), SLOT(fontListTimeout()));
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
theFolders[i].init(FOLDER_SYS==i, isSystem);
|
|
|
|
updateFontList(false);
|
|
}
|
|
|
|
FontInst::~FontInst()
|
|
{
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
theFolders[i].saveDisabled();
|
|
}
|
|
|
|
void FontInst::list(int folders, int pid)
|
|
{
|
|
KFI_DBUG << folders << pid;
|
|
|
|
itsConnections.insert(pid);
|
|
updateFontList(false);
|
|
QList<KFI::Families> fonts;
|
|
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
if(0==folders || folders&(1<<i))
|
|
fonts+=theFolders[i].list();
|
|
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
emit fontList(pid, fonts);
|
|
}
|
|
|
|
void FontInst::stat(const QString &name, int folders, int pid)
|
|
{
|
|
KFI_DBUG << name << folders << pid;
|
|
|
|
bool checkSystem=0==folders || folders&SYS_MASK || isSystem,
|
|
checkUser=0==folders || (folders&USR_MASK && !isSystem);
|
|
FamilyCont::ConstIterator fam;
|
|
StyleCont::ConstIterator st;
|
|
|
|
itsConnections.insert(pid);
|
|
if( (checkSystem && findFont(name, FOLDER_SYS, fam, st)) ||
|
|
(checkUser && findFont(name, FOLDER_USER, fam, st, !checkSystem)) )
|
|
{
|
|
Family rv((*fam).name());
|
|
rv.add(*st);
|
|
KFI_DBUG << "Found font, emit details...";
|
|
emit fontStat(pid, rv);
|
|
}
|
|
else
|
|
{
|
|
KFI_DBUG << "Font not found, emit empty details...";
|
|
emit fontStat(pid, Family(name));
|
|
}
|
|
}
|
|
|
|
void FontInst::install(const QString &file, bool createAfm, bool toSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG << file << createAfm << toSystem << pid << checkConfig;
|
|
|
|
itsConnections.insert(pid);
|
|
|
|
if(checkConfig)
|
|
updateFontList();
|
|
|
|
EFolder folder=isSystem || toSystem ? FOLDER_SYS : FOLDER_USER;
|
|
Family font;
|
|
Utils::EFileType type=Utils::check(file, font);
|
|
|
|
int result=Utils::FILE_BITMAP==type && !FC::bitmapsEnabled()
|
|
? STATUS_BITMAPS_DISABLED
|
|
: Utils::FILE_INVALID==type
|
|
? STATUS_NOT_FONT_FILE
|
|
: STATUS_OK;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
if(Utils::FILE_AFM!=type && Utils::FILE_PFM!=type)
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT) && STATUS_OK==result; ++i)
|
|
if(theFolders[i].contains(font.name(), (*font.styles().begin()).value()))
|
|
result=STATUS_ALREADY_INSTALLED;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
QString name(Misc::modifyName(Misc::getFile(file))),
|
|
destFolder(Misc::getDestFolder(theFolders[folder].location(), name));
|
|
|
|
result=Utils::FILE_AFM!=type && Utils::FILE_PFM!=type && Misc::fExists(destFolder+name) ? (int)KIO::ERR_FILE_ALREADY_EXIST : (int)STATUS_OK;
|
|
if(STATUS_OK==result)
|
|
{
|
|
if(toSystem && !isSystem)
|
|
{
|
|
KFI_DBUG << "Send request to system helper" << file << destFolder << name;
|
|
QVariantMap args;
|
|
args["method"] = "install";
|
|
args["file"] = file;
|
|
args["name"] = name;
|
|
args["destFolder"] = destFolder;
|
|
args["createAfm"] = createAfm;
|
|
args["type"] = (int)type;
|
|
result=performAction(args);
|
|
}
|
|
else
|
|
{
|
|
if(!Misc::dExists(destFolder))
|
|
result=Misc::createDir(destFolder) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED;
|
|
|
|
if(STATUS_OK==result)
|
|
result=QFile::copy(file, destFolder+name) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
Misc::setFilePerms(QFile::encodeName(destFolder+name));
|
|
if((Utils::FILE_SCALABLE==type || Utils::FILE_PFM==type) && createAfm)
|
|
Utils::createAfm(destFolder+name, type);
|
|
}
|
|
}
|
|
|
|
if(STATUS_OK==result && Utils::FILE_AFM!=type && Utils::FILE_PFM!=type)
|
|
{
|
|
StyleCont::ConstIterator st(font.styles().begin());
|
|
FileCont::ConstIterator f((*st).files().begin());
|
|
File df(destFolder+name, (*f).foundry(), (*f).index());
|
|
|
|
(*st).clearFiles();
|
|
(*st).add(df);
|
|
theFolders[folder].add(font);
|
|
theFolders[folder].addModifiedDir(destFolder);
|
|
emit fontsAdded(Families(font, FOLDER_SYS==folder));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
emit status(pid, result);
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
}
|
|
|
|
void FontInst::uninstall(const QString &family, quint32 style, bool fromSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG << family << style << fromSystem << pid << checkConfig;
|
|
|
|
itsConnections.insert(pid);
|
|
|
|
if(checkConfig)
|
|
updateFontList();
|
|
|
|
EFolder folder=isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER;
|
|
FamilyCont::ConstIterator fam;
|
|
StyleCont::ConstIterator st;
|
|
int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
Family del((*fam).name());
|
|
Style s((*st).value(), (*st).scalable(), (*st).writingSystems());
|
|
FileCont files((*st).files());
|
|
FileCont::ConstIterator it(files.begin()),
|
|
end(files.end());
|
|
|
|
if(fromSystem && !isSystem)
|
|
{
|
|
QStringList fileList;
|
|
bool wasDisabled(false);
|
|
|
|
for(; it!=end; ++it)
|
|
{
|
|
fileList.append((*it).path());
|
|
theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*it).path()));
|
|
if(!wasDisabled && Misc::isHidden(Misc::getFile((*it).path())))
|
|
wasDisabled=true;
|
|
}
|
|
QVariantMap args;
|
|
args["method"] = "uninstall";
|
|
args["files"] = fileList;
|
|
result=performAction(args);
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
FileCont empty;
|
|
s.setFiles(files);
|
|
(*st).setFiles(empty);
|
|
if(wasDisabled)
|
|
theFolders[FOLDER_SYS].setDisabledDirty();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(; it!=end; ++it)
|
|
if(!Misc::fExists((*it).path()) || QFile::remove((*it).path()))
|
|
{
|
|
// Also remove any AFM or PFM files...
|
|
QStringList other;
|
|
Misc::getAssociatedFiles((*it).path(), other);
|
|
QStringList::ConstIterator oit(other.constBegin()),
|
|
oend(other.constEnd());
|
|
for(; oit!=oend; ++oit)
|
|
QFile::remove(*oit);
|
|
|
|
theFolders[folder].addModifiedDir(Misc::getDir((*it).path()));
|
|
(*st).remove(*it);
|
|
s.add(*it);
|
|
if(!theFolders[folder].disabledDirty() && Misc::isHidden(Misc::getFile((*it).path())))
|
|
theFolders[folder].setDisabledDirty();
|
|
}
|
|
}
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
if((*st).files().isEmpty())
|
|
{
|
|
(*fam).remove(*st);
|
|
if((*fam).styles().isEmpty())
|
|
theFolders[folder].removeFont(*fam);
|
|
}
|
|
else
|
|
result=STATUS_PARTIAL_DELETE;
|
|
del.add(s);
|
|
}
|
|
emit fontsRemoved(Families(del, FOLDER_SYS==folder));
|
|
|
|
}
|
|
KFI_DBUG << "status" << result;
|
|
emit status(pid, result);
|
|
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
}
|
|
|
|
void FontInst::uninstall(const QString &name, bool fromSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG << name << fromSystem << pid << checkConfig;
|
|
|
|
FamilyCont::ConstIterator fam;
|
|
StyleCont::ConstIterator st;
|
|
if(findFont(name, fromSystem || isSystem ? FOLDER_SYS : FOLDER_USER, fam, st))
|
|
uninstall((*fam).name(), (*st).value(), fromSystem, pid, checkConfig);
|
|
else
|
|
emit status(pid, KIO::ERR_DOES_NOT_EXIST);
|
|
}
|
|
|
|
void FontInst::move(const QString &family, quint32 style, bool toSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG << family << style << toSystem << pid << checkConfig;
|
|
|
|
itsConnections.insert(pid);
|
|
if(checkConfig)
|
|
updateFontList();
|
|
|
|
if(isSystem)
|
|
emit status(pid, KIO::ERR_UNSUPPORTED_ACTION);
|
|
else
|
|
{
|
|
FamilyCont::ConstIterator fam;
|
|
StyleCont::ConstIterator st;
|
|
EFolder from=toSystem ? FOLDER_USER : FOLDER_SYS,
|
|
to=toSystem ? FOLDER_SYS : FOLDER_USER;
|
|
|
|
if(findFont(family, style, from, fam, st))
|
|
{
|
|
FileCont::ConstIterator it((*st).files().begin()),
|
|
end((*st).files().end());
|
|
QStringList files;
|
|
|
|
for(; it!=end; ++it)
|
|
{
|
|
files.append((*it).path());
|
|
theFolders[from].addModifiedDir(Misc::getDir((*it).path()));
|
|
// Actual 'to' folder does not really matter, as we only want to call fc-cache
|
|
// ...actual folders only matter for xreating fonts.dir, etc, and we wont be doing this...
|
|
theFolders[to].addModifiedDir(theFolders[to].location());
|
|
}
|
|
|
|
QVariantMap args;
|
|
args["method"] = "move";
|
|
args["files"] = files;
|
|
args["toSystem"] = toSystem;
|
|
args["dest"] = theFolders[to].location();
|
|
args["uid"] = getuid();
|
|
args["gid"] = getgid();
|
|
int result=performAction(args);
|
|
|
|
if(STATUS_OK==result)
|
|
updateFontList();
|
|
emit status(pid, result);
|
|
}
|
|
else
|
|
{
|
|
KFI_DBUG << "does not exist";
|
|
emit status(pid, KIO::ERR_DOES_NOT_EXIST);
|
|
}
|
|
}
|
|
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
}
|
|
|
|
static bool renameFontFile(const QString &from, const QString &to, int uid=-1, int gid=-1)
|
|
{
|
|
QByteArray src(QFile::encodeName(from)),
|
|
dest(QFile::encodeName(to));
|
|
|
|
if(KDE_rename(src.data(), dest.data()))
|
|
return false;
|
|
|
|
Misc::setFilePerms(dest);
|
|
if(-1!=uid && -1!=gid)
|
|
::chown(dest.data(), uid, gid);
|
|
return true;
|
|
}
|
|
|
|
void FontInst::enable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG << family << style << inSystem << pid << checkConfig;
|
|
toggle(true, family, style, inSystem, pid, checkConfig);
|
|
}
|
|
|
|
void FontInst::disable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG << family << style << inSystem << pid << checkConfig;
|
|
toggle(false, family, style, inSystem, pid, checkConfig);
|
|
}
|
|
|
|
void FontInst::removeFile(const QString &family, quint32 style, const QString &file, bool fromSystem, int pid,
|
|
bool checkConfig)
|
|
{
|
|
KFI_DBUG << family << style << file << fromSystem << pid << checkConfig;
|
|
|
|
itsConnections.insert(pid);
|
|
|
|
if(checkConfig)
|
|
updateFontList();
|
|
|
|
// First find the family/style
|
|
EFolder folder=isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER;
|
|
FamilyCont::ConstIterator fam;
|
|
StyleCont::ConstIterator st;
|
|
int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
// Family/style found - now check that the requested file is *within* the same folder as one
|
|
// of the files linked to this font...
|
|
FileCont files((*st).files());
|
|
FileCont::ConstIterator it(files.begin()),
|
|
end(files.end());
|
|
QString dir(Misc::getDir(file));
|
|
|
|
result=KIO::ERR_DOES_NOT_EXIST;
|
|
for(; it!=end && STATUS_OK!=result; ++it)
|
|
if(Misc::getDir((*it).path())==dir)
|
|
result=STATUS_OK;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
// OK, found folder - so can now proceed to delete the file...
|
|
if(fromSystem && !isSystem)
|
|
{
|
|
QVariantMap args;
|
|
args["method"] = "removeFile";
|
|
args["file"] = file;
|
|
result=performAction(args);
|
|
}
|
|
else
|
|
{
|
|
result=Misc::fExists(file)
|
|
? QFile::remove(file)
|
|
? (int)STATUS_OK
|
|
: (int)KIO::ERR_WRITE_ACCESS_DENIED
|
|
: (int)KIO::ERR_DOES_NOT_EXIST;
|
|
}
|
|
|
|
if(STATUS_OK==result)
|
|
theFolders[folder].addModifiedDir(dir);
|
|
}
|
|
}
|
|
|
|
emit status(pid, result);
|
|
}
|
|
|
|
void FontInst::reconfigure(int pid, bool force)
|
|
{
|
|
KFI_DBUG << pid << force;
|
|
bool sysModified(theFolders[FOLDER_SYS].isModified());
|
|
|
|
saveDisabled();
|
|
|
|
KFI_DBUG << theFolders[FOLDER_USER].isModified() << sysModified;
|
|
if(!isSystem && (force || theFolders[FOLDER_USER].isModified()))
|
|
theFolders[FOLDER_USER].configure(force);
|
|
|
|
if(sysModified)
|
|
{
|
|
if(isSystem)
|
|
{
|
|
theFolders[FOLDER_SYS].configure();
|
|
}
|
|
else
|
|
{
|
|
QVariantMap args;
|
|
args["method"] = "reconfigure";
|
|
performAction(args);
|
|
theFolders[FOLDER_SYS].clearModified();
|
|
}
|
|
}
|
|
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
|
|
updateFontList();
|
|
emit status(pid, isSystem ? constSystemReconfigured : STATUS_OK);
|
|
}
|
|
|
|
QString FontInst::folderName(bool sys)
|
|
{
|
|
return theFolders[sys || isSystem ? FOLDER_SYS : FOLDER_USER].location();
|
|
}
|
|
|
|
void FontInst::saveDisabled()
|
|
{
|
|
if(isSystem)
|
|
theFolders[FOLDER_SYS].saveDisabled();
|
|
else
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
if(FOLDER_SYS==i && !isSystem)
|
|
{
|
|
if(theFolders[i].disabledDirty())
|
|
{
|
|
QVariantMap args;
|
|
args["method"] = "saveDisabled";
|
|
performAction(args);
|
|
theFolders[i].saveDisabled();
|
|
}
|
|
}
|
|
else
|
|
theFolders[i].saveDisabled();
|
|
}
|
|
|
|
void FontInst::connectionsTimeout()
|
|
{
|
|
bool canExit(true);
|
|
|
|
KFI_DBUG << "exiting";
|
|
checkConnections();
|
|
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
{
|
|
if(theFolders[i].disabledDirty())
|
|
canExit=false;
|
|
theFolders[i].saveDisabled();
|
|
}
|
|
|
|
if(0==itsConnections.count())
|
|
{
|
|
if(canExit)
|
|
qApp->exit(0);
|
|
else // Try again later...
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
}
|
|
}
|
|
|
|
void FontInst::fontListTimeout()
|
|
{
|
|
updateFontList(true);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
}
|
|
|
|
void FontInst::updateFontList(bool emitChanges)
|
|
{
|
|
// For some reason just the "!FcConfigUptoDate(0)" check does not always work :-(
|
|
FcBool fcModified=!FcConfigUptoDate(0);
|
|
|
|
if(fcModified ||
|
|
theFolders[FOLDER_SYS].fonts().isEmpty() ||
|
|
(!isSystem && theFolders[FOLDER_USER].fonts().isEmpty()) ||
|
|
theFolders[FOLDER_SYS].disabledDirty() ||
|
|
(!isSystem && theFolders[FOLDER_USER].disabledDirty()))
|
|
{
|
|
KFI_DBUG << "Need to refresh font lists";
|
|
if(fcModified)
|
|
{
|
|
KFI_DBUG << "Re-init FC";
|
|
if(!FcInitReinitialize())
|
|
KFI_DBUG << "Re-init failed????";
|
|
}
|
|
|
|
Folder::Flat old[FOLDER_COUNT];
|
|
|
|
if(emitChanges)
|
|
{
|
|
KFI_DBUG << "Flatten existing font lists";
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
old[i]=theFolders[i].flatten();
|
|
}
|
|
|
|
saveDisabled();
|
|
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
theFolders[i].clearFonts();
|
|
|
|
KFI_DBUG << "update list of fonts";
|
|
|
|
FcPattern *pat = FcPatternCreate();
|
|
FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_FAMILYLANG,
|
|
FC_WEIGHT, FC_LANG, FC_CHARSET, FC_SCALABLE,
|
|
#ifndef KFI_FC_NO_WIDTHS
|
|
FC_WIDTH,
|
|
#endif
|
|
FC_SLANT, FC_INDEX, FC_FOUNDRY, (void*)0);
|
|
|
|
FcFontSet *list=FcFontList(0, pat, os);
|
|
|
|
FcPatternDestroy(pat);
|
|
FcObjectSetDestroy(os);
|
|
|
|
theFolders[FOLDER_SYS].loadDisabled();
|
|
if(!isSystem)
|
|
theFolders[FOLDER_USER].loadDisabled();
|
|
|
|
if(list)
|
|
{
|
|
QString home(Misc::dirSyntax(QDir::homePath()));
|
|
|
|
for (int i = 0; i < list->nfont; i++)
|
|
{
|
|
QString fileName(Misc::fileSyntax(FC::getFcString(list->fonts[i], FC_FILE)));
|
|
|
|
if(!fileName.isEmpty() && Misc::fExists(fileName)) // && 0!=fileName.indexOf(constDefomaLocation))
|
|
{
|
|
QString family,
|
|
foundry;
|
|
quint32 styleVal;
|
|
int index;
|
|
qulonglong writingSystems(WritingSystems::instance()->get(list->fonts[i]));
|
|
FcBool scalable=FcFalse;
|
|
|
|
if(FcResultMatch!=FcPatternGetBool(list->fonts[i], FC_SCALABLE, 0, &scalable))
|
|
scalable=FcFalse;
|
|
|
|
FC::getDetails(list->fonts[i], family, styleVal, index, foundry);
|
|
FamilyCont::ConstIterator fam=theFolders[isSystem || 0!=fileName.indexOf(home)
|
|
? FOLDER_SYS : FOLDER_USER].addFont(Family(family));
|
|
StyleCont::ConstIterator style=(*fam).add(Style(styleVal));
|
|
FileCont::ConstIterator file=(*style).add(File(fileName, foundry, index));
|
|
|
|
(*style).setWritingSystems((*style).writingSystems()|writingSystems);
|
|
if(scalable)
|
|
(*style).setScalable();
|
|
}
|
|
}
|
|
|
|
FcFontSetDestroy(list);
|
|
}
|
|
|
|
if(emitChanges)
|
|
{
|
|
KFI_DBUG << "Look for differences";
|
|
for(int i=0; i<(isSystem ? 1 : FOLDER_COUNT); ++i)
|
|
{
|
|
KFI_DBUG << "Flatten, and take copies...";
|
|
Folder::Flat newList=theFolders[i].flatten(),
|
|
onlyNew=newList;
|
|
|
|
KFI_DBUG << "Determine differences...";
|
|
onlyNew.subtract(old[i]);
|
|
old[i].subtract(newList);
|
|
|
|
KFI_DBUG << "Emit changes...";
|
|
Families families=onlyNew.build(isSystem || i==FOLDER_SYS);
|
|
|
|
if(!families.items.isEmpty())
|
|
emit fontsAdded(families);
|
|
|
|
families=old[i].build(isSystem || i==FOLDER_SYS);
|
|
if(!families.items.isEmpty())
|
|
emit fontsRemoved(families);
|
|
}
|
|
}
|
|
KFI_DBUG << "updated list of fonts";
|
|
}
|
|
}
|
|
|
|
void FontInst::toggle(bool enable, const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig)
|
|
{
|
|
KFI_DBUG;
|
|
itsConnections.insert(pid);
|
|
|
|
if(checkConfig)
|
|
updateFontList();
|
|
|
|
EFolder folder=isSystem || inSystem ? FOLDER_SYS : FOLDER_USER;
|
|
FamilyCont::ConstIterator fam;
|
|
StyleCont::ConstIterator st;
|
|
int result=findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
FileCont files((*st).files()),
|
|
toggledFiles;
|
|
FileCont::ConstIterator it(files.begin()),
|
|
end(files.end());
|
|
QHash<File, QString> movedFonts;
|
|
QHash<QString, QString> movedAssoc;
|
|
QSet<QString> modifiedDirs;
|
|
|
|
for(; it!=end && STATUS_OK==result; ++it)
|
|
{
|
|
QString to=Misc::getDir((*it).path())+
|
|
QString(enable ? Misc::unhide(Misc::getFile((*it).path()))
|
|
: Misc::hide(Misc::getFile((*it).path())));
|
|
if(to!=(*it).path())
|
|
{
|
|
KFI_DBUG << "MOVE:" << (*it).path() << " to " << to;
|
|
// If the font is a system font, and we're not root, then just go through the actions here - so
|
|
// that we can build the list of changes that would happen...
|
|
if((inSystem && !isSystem) || renameFontFile((*it).path(), to))
|
|
{
|
|
modifiedDirs.insert(Misc::getDir(enable ? to : (*it).path()));
|
|
toggledFiles.insert(File(to, (*it).foundry(), (*it).index()));
|
|
// Now try to move an associated AFM or PFM files...
|
|
QStringList assoc;
|
|
|
|
movedFonts[*it]=to;
|
|
Misc::getAssociatedFiles((*it).path(), assoc);
|
|
|
|
QStringList::ConstIterator ait(assoc.constBegin()),
|
|
aend(assoc.constEnd());
|
|
|
|
for(; ait!=aend && STATUS_OK==result; ++ait)
|
|
{
|
|
to=Misc::getDir(*ait)+
|
|
QString(enable ? Misc::unhide(Misc::getFile(*ait))
|
|
: Misc::hide(Misc::getFile(*ait)));
|
|
|
|
if(to!=*ait)
|
|
{
|
|
if((inSystem && !isSystem) || renameFontFile(*ait, to))
|
|
{
|
|
movedAssoc[*ait]=to;
|
|
}
|
|
else
|
|
{
|
|
result=KIO::ERR_WRITE_ACCESS_DENIED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result=KIO::ERR_WRITE_ACCESS_DENIED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(inSystem && !isSystem)
|
|
{
|
|
Family toggleFam((*fam).name());
|
|
|
|
toggleFam.add(*st);
|
|
QVariantMap args;
|
|
args["method"] = "toggle";
|
|
QString xml;
|
|
QTextStream str(&xml);
|
|
toggleFam.toXml(false, str);
|
|
args["xml"] = xml;
|
|
args["enable"] = enable;
|
|
result=performAction(args);
|
|
}
|
|
|
|
if(STATUS_OK==result)
|
|
{
|
|
Family addFam((*fam).name()),
|
|
delFam((*fam).name());
|
|
Style addStyle((*st).value(), (*st).scalable(), (*st).writingSystems()),
|
|
delStyle((*st).value(), (*st).scalable(), (*st).writingSystems());
|
|
|
|
addStyle.setFiles(toggledFiles);
|
|
addFam.add(addStyle);
|
|
delStyle.setFiles(files);
|
|
delFam.add(delStyle);
|
|
(*st).setFiles(toggledFiles);
|
|
|
|
theFolders[folder].addModifiedDirs(modifiedDirs);
|
|
emit fontsAdded(Families(addFam, FOLDER_SYS==folder));
|
|
emit fontsRemoved(Families(delFam, FOLDER_SYS==folder));
|
|
|
|
theFolders[folder].setDisabledDirty();
|
|
}
|
|
else // un-move fonts!
|
|
{
|
|
QHash<File, QString>::ConstIterator fit(movedFonts.constBegin()),
|
|
fend(movedFonts.constEnd());
|
|
QHash<QString, QString>::ConstIterator ait(movedAssoc.constBegin()),
|
|
aend(movedAssoc.constEnd());
|
|
|
|
for(; fit!=fend; ++fit)
|
|
renameFontFile(fit.value(), fit.key().path());
|
|
for(; ait!=aend; ++ait)
|
|
renameFontFile(ait.value(), ait.key());
|
|
}
|
|
}
|
|
emit status(pid, result);
|
|
|
|
itsConnectionsTimer->start(constConnectionsTimeout);
|
|
itsFontListTimer->start(constFontListTimeout);
|
|
}
|
|
|
|
void FontInst::addModifedSysFolders(const Family &family)
|
|
{
|
|
StyleCont::ConstIterator style(family.styles().begin()),
|
|
styleEnd(family.styles().end());
|
|
|
|
for(; style!=styleEnd; ++style)
|
|
{
|
|
FileCont::ConstIterator file((*style).files().begin()),
|
|
fileEnd((*style).files().end());
|
|
|
|
for(; file!=fileEnd; ++file)
|
|
theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*file).path()));
|
|
}
|
|
}
|
|
|
|
void FontInst::checkConnections()
|
|
{
|
|
KFI_DBUG;
|
|
QSet<int>::ConstIterator it(itsConnections.begin()),
|
|
end(itsConnections.end());
|
|
QSet<int> remove;
|
|
|
|
for(; it!=end; ++it)
|
|
if(0!=kill(*it, 0))
|
|
remove.insert(*it);
|
|
itsConnections.subtract(remove);
|
|
}
|
|
|
|
bool FontInst::findFontReal(const QString &family, const QString &style, EFolder folder,
|
|
FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st)
|
|
{
|
|
KFI_DBUG;
|
|
Family f(family);
|
|
fam=theFolders[folder].fonts().find(f);
|
|
if(theFolders[folder].fonts().end()==fam)
|
|
return false;
|
|
|
|
StyleCont::ConstIterator end((*fam).styles().end());
|
|
for(st=(*fam).styles().begin(); st!=end; ++st)
|
|
if(FC::createStyleName((*st).value())==style)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FontInst::findFont(const QString &font, EFolder folder,
|
|
FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st,
|
|
bool updateList)
|
|
{
|
|
KFI_DBUG;
|
|
QString family,
|
|
style;
|
|
|
|
decompose(font, family, style);
|
|
|
|
if(!findFontReal(family, style, folder, fam, st))
|
|
{
|
|
if(updateList)
|
|
{
|
|
// Not found, so refresh font list and try again...
|
|
updateFontList();
|
|
return findFontReal(family, style, folder, fam, st);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FontInst::findFontReal(const QString &family, quint32 style, EFolder folder,
|
|
FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st)
|
|
{
|
|
KFI_DBUG;
|
|
fam=theFolders[folder].fonts().find(Family(family));
|
|
|
|
if(theFolders[folder].fonts().end()==fam)
|
|
return false;
|
|
else
|
|
{
|
|
st=(*fam).styles().find(style);
|
|
|
|
return (*fam).styles().end()!=st;
|
|
}
|
|
}
|
|
|
|
bool FontInst::findFont(const QString &family, quint32 style, EFolder folder,
|
|
FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st,
|
|
bool updateList)
|
|
{
|
|
KFI_DBUG;
|
|
if(!findFontReal(family, style, folder, fam, st))
|
|
{
|
|
if(updateList)
|
|
{
|
|
// Not found, so refresh font list and try again...
|
|
updateFontList();
|
|
return findFontReal(family, style, folder, fam, st);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int FontInst::performAction(const QVariantMap &args)
|
|
{
|
|
KAuth::Action action("org.kde.fontinst.manage");
|
|
|
|
action.setHelperID("org.kde.fontinst");
|
|
action.setArguments(args);
|
|
KFI_DBUG << "Call " << args["method"].toString() << " on helper";
|
|
itsFontListTimer->stop();
|
|
itsConnectionsTimer->stop();
|
|
KAuth::ActionReply reply = action.execute();
|
|
|
|
switch(reply.type())
|
|
{
|
|
case KAuth::ActionReply::KAuthError:
|
|
KFI_DBUG << "KAuth failed - error code:" << reply.errorCode();
|
|
return KIO::ERR_COULD_NOT_AUTHENTICATE;
|
|
case KAuth::ActionReply::HelperError:
|
|
KFI_DBUG << "Helper failed - error code:" << reply.errorCode();
|
|
return (int)reply.errorCode();
|
|
}
|
|
|
|
KFI_DBUG << "Success!";
|
|
return STATUS_OK;
|
|
}
|
|
|
|
}
|