Use QtConcurrentRun to initialize FontConfig in a separate thread.

master
Torsten Paul 2014-12-21 03:46:13 +01:00
parent abdf80c494
commit 98a9ea7e12
4 changed files with 60 additions and 28 deletions

View File

@ -127,7 +127,7 @@ mingw* {
} }
CONFIG += qt CONFIG += qt
QT += opengl QT += opengl concurrent
# see http://fedoraproject.org/wiki/UnderstandingDSOLinkChange # see http://fedoraproject.org/wiki/UnderstandingDSOLinkChange
# and https://github.com/openscad/openscad/pull/119 # and https://github.com/openscad/openscad/pull/119

View File

@ -81,11 +81,20 @@ const std::string &FontInfo::get_file() const
} }
FontCache * FontCache::self = NULL; FontCache * FontCache::self = NULL;
FontCache::ProgressHandlerFunc *FontCache::start_cb = NULL; FontCache::InitHandlerFunc *FontCache::cb_handler = FontCache::defaultInitHandler;
FontCache::ProgressHandlerFunc *FontCache::end_cb = NULL;
void *FontCache::cb_userdata = NULL; void *FontCache::cb_userdata = NULL;
const std::string FontCache::DEFAULT_FONT("XXX"); const std::string FontCache::DEFAULT_FONT("XXX");
/**
* Default implementation for the font cache initialization. In case no other
* handler is registered, the cache build is just called synchronously in the
* current thread by this handler.
*/
void FontCache::defaultInitHandler(FontCacheInitializer *initializer, void *)
{
initializer->run();
}
FontCache::FontCache() FontCache::FontCache()
{ {
this->init_ok = false; this->init_ok = false;
@ -134,9 +143,8 @@ FontCache::FontCache()
} }
} }
if (FontCache::start_cb) FontCache::start_cb(FontCache::cb_userdata); FontCacheInitializer initializer(this->config);
FcConfigBuildFonts(this->config); cb_handler(&initializer, cb_userdata);
if (FontCache::end_cb) FontCache::end_cb(FontCache::cb_userdata);
// For use by LibraryInfo // For use by LibraryInfo
FcStrList *dirs = FcConfigGetFontDirs(this->config); FcStrList *dirs = FcConfigGetFontDirs(this->config);
@ -166,10 +174,9 @@ FontCache * FontCache::instance()
return self; return self;
} }
void FontCache::registerProgressHandler(ProgressHandlerFunc *start, ProgressHandlerFunc *end, void *userdata) void FontCache::registerProgressHandler(InitHandlerFunc *handler, void *userdata)
{ {
FontCache::start_cb = start; FontCache::cb_handler = handler;
FontCache::end_cb = end;
FontCache::cb_userdata = userdata; FontCache::cb_userdata = userdata;
} }

View File

@ -59,6 +59,19 @@ private:
typedef std::vector<FontInfo> FontInfoList; typedef std::vector<FontInfo> FontInfoList;
/**
* Slow call of the font cache initialization. This is separated here so it
* can be passed to the GUI to run in a separate thread while showing a
* progress dialog.
*/
class FontCacheInitializer {
public:
FontCacheInitializer(FcConfig *config) : config(config) { }
void run() { FcConfigBuildFonts(config); }
private:
FcConfig *config;
};
class FontCache { class FontCache {
public: public:
const static std::string DEFAULT_FONT; const static std::string DEFAULT_FONT;
@ -76,17 +89,19 @@ public:
static FontCache *instance(); static FontCache *instance();
typedef void (ProgressHandlerFunc)(void *userdata); typedef void (InitHandlerFunc)(FontCacheInitializer *initializer, void *userdata);
static void registerProgressHandler(ProgressHandlerFunc *start, ProgressHandlerFunc *end, void *userdata = NULL); static void registerProgressHandler(InitHandlerFunc *handler, void *userdata = NULL);
private: private:
typedef std::pair<FT_Face, time_t> cache_entry_t; typedef std::pair<FT_Face, time_t> cache_entry_t;
typedef std::map<std::string, cache_entry_t> cache_t; typedef std::map<std::string, cache_entry_t> cache_t;
static FontCache *self; static FontCache *self;
static ProgressHandlerFunc *start_cb; static InitHandlerFunc *cb_handler;
static ProgressHandlerFunc *end_cb; static void *cb_userdata;
static void *cb_userdata;
static void defaultInitHandler(FontCacheInitializer *delegate, void *userdata);
bool init_ok; bool init_ok;
cache_t cache; cache_t cache;
FcConfig *config; FcConfig *config;

View File

@ -549,6 +549,9 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#include <QFileInfo> #include <QFileInfo>
#include <QMetaType> #include <QMetaType>
#include <QTextCodec> #include <QTextCodec>
#include <QProgressDialog>
#include <QFutureWatcher>
#include <QtConcurrentRun>
Q_DECLARE_METATYPE(shared_ptr<const Geometry>); Q_DECLARE_METATYPE(shared_ptr<const Geometry>);
@ -578,20 +581,29 @@ bool QtUseGUI()
return useGUI; return useGUI;
} }
void dialogThreadFunc(FontCacheInitializer *initializer)
#include <QProgressDialog>
QProgressDialog *fontCacheProgress = NULL;
void fontCacheStart(void *userdata)
{ {
fontCacheProgress = new QProgressDialog("Fontconfig needs to update its font cache.\nThis can take up to a couple of minutes.", QString(), 0, 0); initializer->run();
fontCacheProgress->show();
} }
void fontCacheEnd(void *userdata) void dialogInitHandler(FontCacheInitializer *initializer, void *)
{ {
delete fontCacheProgress; QProgressDialog dialog;
fontCacheProgress = NULL; dialog.setLabelText("Fontconfig needs to update its font cache.\nThis can take up to a couple of minutes.");
dialog.setCancelButton(0);
QFutureWatcher<void> futureWatcher;
QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset()));
QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel()));
QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int,int)), &dialog, SLOT(setRange(int,int)));
QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int)));
QFuture<void> future = QtConcurrent::run(boost::bind(dialogThreadFunc, initializer));
futureWatcher.setFuture(future);
dialog.exec();
futureWatcher.waitForFinished();
} }
int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv) int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, char ** argv)
@ -624,9 +636,7 @@ int gui(vector<string> &inputFiles, const fs::path &original_path, int argc, cha
const QString &app_path = app.applicationDirPath(); const QString &app_path = app.applicationDirPath();
PlatformUtils::registerApplicationPath(app_path.toLocal8Bit().constData()); PlatformUtils::registerApplicationPath(app_path.toLocal8Bit().constData());
FontCache::registerProgressHandler(fontCacheStart, fontCacheEnd); FontCache::registerProgressHandler(dialogInitHandler);
parser_init(); parser_init();