From c259957b6967b1a49fb188437aabb4bcaf0ccb64 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Peter=20K=C3=BCmmel?= Date: Wed, 20 Oct 2010 23:50:49 +0000 Subject: [PATCH] add generic helper class for calling functions in gui thread git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@35735 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/frontends/qt4/GuiAlert.cpp | 69 +++++++++++-- src/support/InGuiThread.cpp | 52 ++++++++++ src/support/InGuiThread.h | 172 +++++++++++++++++++++++++++++++++ src/support/Makefile.am | 3 + src/support/functional.h | 41 ++++++++ 5 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 src/support/InGuiThread.cpp create mode 100644 src/support/InGuiThread.h create mode 100644 src/support/functional.h diff --git a/src/frontends/qt4/GuiAlert.cpp b/src/frontends/qt4/GuiAlert.cpp index 70bca4151e..e04b301e59 100644 --- a/src/frontends/qt4/GuiAlert.cpp +++ b/src/frontends/qt4/GuiAlert.cpp @@ -14,7 +14,6 @@ #include "alert.h" - #include "frontends/Application.h" #include "qt_helpers.h" @@ -25,6 +24,7 @@ #include "support/docstring.h" #include "support/lstrings.h" #include "support/ProgressInterface.h" +#include "support/InGuiThread.h" #include #include @@ -37,6 +37,11 @@ #include #include + +// sync with GuiView.cpp +#define EXPORT_in_THREAD 0 + + using namespace std; using namespace lyx::support; @@ -124,7 +129,8 @@ void noAppDialog(QString const & title, QString const & msg, QMessageBox::Icon m namespace Alert { -int prompt(docstring const & title0, docstring const & question, + +int doPrompt(docstring const & title0, docstring const & question, int default_button, int cancel_button, docstring const & b1, docstring const & b2, docstring const & b3, docstring const & b4) @@ -178,8 +184,21 @@ int prompt(docstring const & title0, docstring const & question, return res; } +int prompt(docstring const & title0, docstring const & question, + int default_button, int cancel_button, + docstring const & b1, docstring const & b2, + docstring const & b3, docstring const & b4) +{ +#ifdef EXPORT_in_THREAD + return InGuiThread().call(&doPrompt, +#else + return doPrompt( +#endif + title0, question, default_button, + cancel_button, b1, b2, b3, b4); +} -void warning(docstring const & title0, docstring const & message, +void doWarning(docstring const & title0, docstring const & message, bool const & askshowagain) { lyxerr << "Warning: " << title0 << '\n' @@ -213,8 +232,18 @@ void warning(docstring const & title0, docstring const & message, qApp->restoreOverrideCursor(); } +void warning(docstring const & title0, docstring const & message, + bool const & askshowagain) +{ +#ifdef EXPORT_in_THREAD + InGuiThread().call(&doWarning, +#else + doWarning( +#endif + title0, message, askshowagain); +} -void error(docstring const & title0, docstring const & message) +void doError(docstring const & title0, docstring const & message) { lyxerr << "Error: " << title0 << '\n' << "----------------------------------------\n" @@ -240,8 +269,17 @@ void error(docstring const & title0, docstring const & message) qApp->restoreOverrideCursor(); } +void error(docstring const & title0, docstring const & message) +{ +#ifdef EXPORT_in_THREAD + InGuiThread().call(&doError, +#else + doError( +#endif + title0, message); +} -void information(docstring const & title0, docstring const & message) +void doInformation(docstring const & title0, docstring const & message) { if (!use_gui || lyxerr.debugging()) lyxerr << title0 << '\n' @@ -268,8 +306,17 @@ void information(docstring const & title0, docstring const & message) qApp->restoreOverrideCursor(); } +void information(docstring const & title0, docstring const & message) +{ +#ifdef EXPORT_in_THREAD + InGuiThread().call(&doInformation, +#else + doInformation( +#endif + title0, message); +} -bool askForText(docstring & response, docstring const & msg, +bool doAskForText(docstring & response, docstring const & msg, docstring const & dflt) { if (!use_gui || lyxerr.debugging()) { @@ -300,6 +347,16 @@ bool askForText(docstring & response, docstring const & msg, return false; } +bool askForText(docstring & response, docstring const & msg, + docstring const & dflt) +{ +#ifdef EXPORT_in_THREAD + return InGuiThread().call(&doAskForText, +#else + return doAskGForText( +#endif + response, msg, dflt); +} } // namespace Alert } // namespace frontend diff --git a/src/support/InGuiThread.cpp b/src/support/InGuiThread.cpp new file mode 100644 index 0000000000..2ffbc7e317 --- /dev/null +++ b/src/support/InGuiThread.cpp @@ -0,0 +1,52 @@ +/** + * \file InGuiThread.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#include "InGuiThread.h" + +#include +#include +#include + +namespace lyx { +namespace frontend { + + +IntoGuiThreadMover::IntoGuiThreadMover() +{ + moveToThread(QApplication::instance()->thread()); + connect(this, SIGNAL(triggerCall()), this, SLOT(doFunctionCall()), + Qt::QueuedConnection); +} + + +void IntoGuiThreadMover::callInGuiThread() +{ + if (QThread::currentThread() == QApplication::instance()->thread()) { + synchronousFunctionCall(); + } else { + QEventLoop loop; + connect(this, SIGNAL(called()), &loop, SLOT(quit())); + Q_EMIT triggerCall(); + loop.exec(); + } +} + + +void IntoGuiThreadMover::doFunctionCall() +{ + synchronousFunctionCall(); + Q_EMIT called(); +} + + +} // namespace frontend +} // namespace lyx + + diff --git a/src/support/InGuiThread.h b/src/support/InGuiThread.h new file mode 100644 index 0000000000..6d3b778a04 --- /dev/null +++ b/src/support/InGuiThread.h @@ -0,0 +1,172 @@ +// -*- C++ -*- +/** + * \file InGuiThread.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef INGUITHREAD_H +#define INGUITHREAD_H + +#include + +#include "support/bind.h" +#include "support/functional.h" + +namespace lyx { +namespace frontend { + + +class IntoGuiThreadMover : public QObject +{ + Q_OBJECT + +protected: + + IntoGuiThreadMover(); + + void callInGuiThread(); + +Q_SIGNALS: + void triggerCall(); + void called(); + +private Q_SLOTS: + void doFunctionCall(); + +private: + virtual void synchronousFunctionCall() = 0; +}; + + +template +class InGuiThread : private IntoGuiThreadMover +{ +public: + + InGuiThread() {} + + template + R call(F f) + { + func_ = f; + callInGuiThread(); + return return_value_; + } + + template + R call(F f, P1 p1) + { + return call(bind(f, p1)); + } + + template + R call(F f, P1 p1, P2 p2) + { + return call(bind(f, p1, p2)); + } + + template + R call(F f, P1 p1, P2 p2, P3 p3) + { + return call(bind(f, p1, p2, p3)); + } + + template + R call(F f, P1 p1, P2 p2, P3 p3, P4 p4) + { + return call(bind(f, p1, p2, p3, p4)); + } + + /* + ... + */ + + template + R call(F f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) + { + return call(bind(f, p1, p2, p3, p4, p5, p6, p7, p8)); + } + +private: + + void synchronousFunctionCall() + { + return_value_ = func_(); + } + +private: + R return_value_; + function func_; +}; + + +// void specialisation +template<> +class InGuiThread : private IntoGuiThreadMover +{ +public: + + InGuiThread() {} + + template + void call(F f) + { + func_ = f; + callInGuiThread(); + } + + template + void call(F f, P1 p1) + { + call(bind(f, p1)); + } + + template + void call(F f, P1 p1, P2 p2) + { + call(bind(f, p1, p2)); + } + + template + void call(F f, P1 p1, P2 p2, P3 p3) + { + call(bind(f, p1, p2, p3)); + } + + template + void call(F f, P1 p1, P2 p2, P3 p3, P4 p4) + { + call(bind(f, p1, p2, p3, p4)); + } + + /* + ... + */ + + template + void call(F f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) + { + call(bind(f, p1, p2, p3, p4, p5, p6, p7, p8)); + } + +private: + + void synchronousFunctionCall() + { + func_(); + } + +private: + function func_; +}; + + +} // namespace frontend +} // namespace lyx + +#endif // GUIABOUT_H diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 31993949fb..a60554dafd 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -56,10 +56,13 @@ liblyxsupport_a_SOURCES = \ foreach.h \ ForkedCalls.cpp \ ForkedCalls.h \ + functional.h \ gettext.cpp \ gettext.h \ gzstream.cpp \ gzstream.h \ + InGuiThread.h \ + InGuiThread.cpp \ kill.cpp \ lassert.h \ lassert.cpp \ diff --git a/src/support/functional.h b/src/support/functional.h new file mode 100644 index 0000000000..47d9c45966 --- /dev/null +++ b/src/support/functional.h @@ -0,0 +1,41 @@ +// -*- C++ -*- +/** + * \file functional.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef LYX_FUNCTIONAL_H +#define LYX_FUNCTIONAL_H + +#ifdef LYX_USE_TR1 + +#include + +#ifdef __GNUC__ +#include +#endif + +namespace lyx +{ + using std::tr1::function; +} + +#else + +#include +#include + +namespace lyx +{ + using boost::function; +} + +#endif + + +#endif -- 2.39.2