Fix crash on exit (bug 2549) by correct usage of QApplication

* src/lyx_cb.C
	(quitLyX): lyx_gui::exit takes now an argument

	* src/frontends/{gtk,xforms}/lyx_gui.C
	(lyx_gui::parse_init): rename to lyx_gui::exec and call LyX::exec2
	(void lyx_gui::exit): add exit status argument

	* src/frontends/qt{3,4}/lyx_gui.C
	(cleanup): new function for pointer cleanup
	(lyx_gui::parse_init): rename to lyx_gui::exec and call LyX::exec2,
	turn static variables into automatic variables
	(void lyx_gui::exit): add exit status argument
	(start): Use cleanup()
	(exit): ditto

	* src/frontends/lyx_gui.h
	(parse_init): remove
	(exec): new
	(exit): Take exist status argument

	* src/lyx_main.[Ch]
	(LyX::priv_exec): split into LyX::priv_exec and LyX::exec2

	* src/lyx_main.C
	(lyx_exit): New, choose the right exit function
	(showFileError): call lyx_exit
	(LyX::queryUserLyXDir): ditto
	(LyX::init): ditto
	(LyX::priv_exec): ditto
	(LyX::priv_exec): Replace want_gui by lyx_gui::use_gui
	(LyX::priv_exec): replace lyx_gui::parse_init by lyx_gui::exec and
	exec2
	(LyX::init): Replace gui argument by lyx_gui::use_gui


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@14036 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Georg Baum 2006-06-07 20:08:37 +00:00
parent 459303729c
commit 042d5a0242
8 changed files with 123 additions and 102 deletions

View File

@ -100,7 +100,7 @@ int getDPI()
} // namespace anon } // namespace anon
void lyx_gui::parse_init(int & argc, char * argv[]) void lyx_gui::exec(int & argc, char * argv[])
{ {
new Gtk::Main(argc, argv); new Gtk::Main(argc, argv);
@ -112,6 +112,8 @@ void lyx_gui::parse_init(int & argc, char * argv[])
// must do this /before/ lyxrc gets read // must do this /before/ lyxrc gets read
lyxrc.dpi = getDPI(); lyxrc.dpi = getDPI();
LyX::ref().exec2(argc, argv);
} }
@ -152,8 +154,9 @@ void lyx_gui::start(string const & batch, std::vector<string> const & files,
} }
void lyx_gui::exit() void lyx_gui::exit(int /*status*/)
{ {
// FIXME: Don't ignore status
Gtk::Main::quit(); Gtk::Main::quit();
} }

View File

@ -46,9 +46,6 @@ std::string const sans_font_name();
/// return a suitable monospaced font name (called from non-gui context too !) /// return a suitable monospaced font name (called from non-gui context too !)
std::string const typewriter_font_name(); std::string const typewriter_font_name();
/// parse command line and do basic initialisation
void parse_init(int & argc, char * argv[]);
/** /**
* set up GUI parameters. At this point lyxrc may * set up GUI parameters. At this point lyxrc may
* be used. * be used.
@ -60,7 +57,12 @@ void parse_lyxrc();
* batch commands, and loading the given documents * batch commands, and loading the given documents
*/ */
void start(std::string const & batch, std::vector<std::string> const & files, void start(std::string const & batch, std::vector<std::string> const & files,
unsigned int width, unsigned int height, int posx, int posy); unsigned int width, unsigned int height, int posx, int posy);
/**
* Enter the main event loop (\sa LyX::exec2)
*/
void exec(int & argc, char * argv[]);
/** /**
* Synchronise all pending events. * Synchronise all pending events.
@ -70,7 +72,7 @@ void sync_events();
/** /**
* quit running LyX * quit running LyX
*/ */
void exit(); void exit(int);
/** /**
* return the status flag for a given action. This can be used to tell * return the status flag for a given action. This can be used to tell

View File

@ -79,6 +79,10 @@ using std::string;
extern BufferList bufferlist; extern BufferList bufferlist;
// FIXME: wrong place !
LyXServer * lyxserver;
LyXServerSocket * lyxsocket;
namespace { namespace {
int getDPI() int getDPI()
@ -90,11 +94,15 @@ int getDPI()
map<int, shared_ptr<socket_callback> > socket_callbacks; map<int, shared_ptr<socket_callback> > socket_callbacks;
} // namespace anon void cleanup()
{
delete lyxsocket;
lyxsocket = 0;
delete lyxserver;
lyxserver = 0;
}
// FIXME: wrong place ! } // namespace anon
LyXServer * lyxserver;
LyXServerSocket * lyxsocket;
// in QLyXKeySym.C // in QLyXKeySym.C
extern void initEncodings(); extern void initEncodings();
@ -104,7 +112,6 @@ extern bool lyxX11EventFilter(XEvent * xev);
#endif #endif
#ifdef Q_WS_MACX #ifdef Q_WS_MACX
extern bool macEventFilter(EventRef event);
extern pascal OSErr extern pascal OSErr
handleOpenDocuments(const AppleEvent* inEvent, AppleEvent* /*reply*/, handleOpenDocuments(const AppleEvent* inEvent, AppleEvent* /*reply*/,
long /*refCon*/); long /*refCon*/);
@ -153,22 +160,23 @@ namespace lyx_gui {
bool use_gui = true; bool use_gui = true;
void parse_init(int & argc, char * argv[])
void exec(int & argc, char * argv[])
{ {
// Force adding of font path _before_ QApplication is initialized // Force adding of font path _before_ QApplication is initialized
FontLoader::initFontPath(); FontLoader::initFontPath();
static LQApplication app(argc, argv); LQApplication app(argc, argv);
#if QT_VERSION >= 0x030200 #if QT_VERSION >= 0x030200
// install translation file for Qt built-in dialogs // install translation file for Qt built-in dialogs
// These are only installed since Qt 3.2.x // These are only installed since Qt 3.2.x
static QTranslator qt_trans(0); QTranslator qt_trans(0);
if (qt_trans.load(QString("qt_") + QTextCodec::locale(), if (qt_trans.load(QString("qt_") + QTextCodec::locale(),
qInstallPathTranslations())) { qInstallPathTranslations())) {
app.installTranslator(&qt_trans); qApp->installTranslator(&qt_trans);
// even if the language calls for RtL, don't do that // even if the language calls for RtL, don't do that
app.setReverseLayout(false); qApp->setReverseLayout(false);
lyxerr[Debug::GUI] lyxerr[Debug::GUI]
<< "Successfully installed Qt translations for locale " << "Successfully installed Qt translations for locale "
<< QTextCodec::locale() << std::endl; << QTextCodec::locale() << std::endl;
@ -182,7 +190,7 @@ void parse_init(int & argc, char * argv[])
// These translations are meant to break Qt/Mac menu merging // These translations are meant to break Qt/Mac menu merging
// algorithm on some entries. It lists the menu names that // algorithm on some entries. It lists the menu names that
// should not be moved to the LyX menu // should not be moved to the LyX menu
static QTranslator aqua_trans(0); QTranslator aqua_trans(0);
aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setting", 0, aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setting", 0,
"do_not_merge_me")); "do_not_merge_me"));
aqua_trans.insert(QTranslatorMessage("QMenuBar", "Config", 0, aqua_trans.insert(QTranslatorMessage("QMenuBar", "Config", 0,
@ -192,7 +200,7 @@ void parse_init(int & argc, char * argv[])
aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setup", 0, aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setup", 0,
"do_not_merge_me")); "do_not_merge_me"));
app.installTranslator(&aqua_trans); qApp->installTranslator(&aqua_trans);
#endif #endif
using namespace lyx::graphics; using namespace lyx::graphics;
@ -204,6 +212,8 @@ void parse_init(int & argc, char * argv[])
lyxrc.dpi = getDPI(); lyxrc.dpi = getDPI();
LoaderQueue::setPriority(10,100); LoaderQueue::setPriority(10,100);
LyX::ref().exec2(argc, argv);
} }
@ -245,9 +255,7 @@ void start(string const & batch, vector<string> const & files,
qApp->exec(); qApp->exec();
// FIXME // FIXME
delete lyxsocket; cleanup();
delete lyxserver;
lyxserver = 0;
} }
@ -263,18 +271,16 @@ void sync_events()
} }
void exit() void exit(int status)
{ {
delete lyxsocket; cleanup();
delete lyxserver;
lyxserver = 0;
// we cannot call qApp->exit(0) - that could return us // we cannot call QApplication::exit(status) - that could return us
// into a static dialog return in the lyx code (for example, // into a static dialog return in the lyx code (for example,
// load autosave file QMessageBox. We have to just get the hell // load autosave file QMessageBox. We have to just get the hell
// out. // out.
::exit(0); ::exit(status);
} }

View File

@ -76,6 +76,10 @@ using std::string;
extern BufferList bufferlist; extern BufferList bufferlist;
// FIXME: wrong place !
LyXServer * lyxserver;
LyXServerSocket * lyxsocket;
namespace { namespace {
int getDPI() int getDPI()
@ -86,11 +90,15 @@ int getDPI()
map<int, shared_ptr<socket_callback> > socket_callbacks; map<int, shared_ptr<socket_callback> > socket_callbacks;
} // namespace anon void cleanup()
{
delete lyxsocket;
lyxsocket = 0;
delete lyxserver;
lyxserver = 0;
}
// FIXME: wrong place ! } // namespace anon
LyXServer * lyxserver;
LyXServerSocket * lyxsocket;
// in QLyXKeySym.C // in QLyXKeySym.C
extern void initEncodings(); extern void initEncodings();
@ -145,50 +153,21 @@ bool LQApplication::macEventFilter(EventRef event)
#endif #endif
namespace {
LQApplication * app = 0;
}
namespace lyx_gui { namespace lyx_gui {
bool use_gui = true; bool use_gui = true;
void parse_init(int & argc, char * argv[])
void exec(int & argc, char * argv[])
{ {
/*
FIXME : Abdel 29/05/2006 (younes.a@free.fr)
reorganize this code. In particular make sure that this
advise from Qt documentation is respected:
Since the QApplication object does so much initialization, it
must be created before any other objects related to the user
interface are created.
Right now this is not the case. For example, the call to
"FontLoader::initFontPath()" below is doned before the QApplication
creation. Moreover, I suspect that a number of global variables
contains Qt object that are initialized before the passage through
parse_init(). This might also explain the message displayed by Qt
that caused the hanging:
QObject::killTimer: timers cannot be stopped from another thread
*/
// Force adding of font path _before_ QApplication is initialized // Force adding of font path _before_ QApplication is initialized
FontLoader::initFontPath(); FontLoader::initFontPath();
#ifdef Q_WS_WIN LQApplication app(argc, argv);
static QApplication win_app(argc, argv);
#else
app = new LQApplication(argc, argv);
#endif
// install translation file for Qt built-in dialogs // install translation file for Qt built-in dialogs
// These are only installed since Qt 3.2.x // These are only installed since Qt 3.2.x
static QTranslator qt_trans(0); QTranslator qt_trans(0);
if (qt_trans.load(QString("qt_") + QTextCodec::locale(), if (qt_trans.load(QString("qt_") + QTextCodec::locale(),
qInstallPathTranslations())) { qInstallPathTranslations())) {
qApp->installTranslator(&qt_trans); qApp->installTranslator(&qt_trans);
@ -206,7 +185,7 @@ void parse_init(int & argc, char * argv[])
// These translations are meant to break Qt/Mac menu merging // These translations are meant to break Qt/Mac menu merging
// algorithm on some entries. It lists the menu names that // algorithm on some entries. It lists the menu names that
// should not be moved to the LyX menu // should not be moved to the LyX menu
static QTranslator aqua_trans(0); QTranslator aqua_trans(0);
aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setting", 0, aqua_trans.insert(QTranslatorMessage("QMenuBar", "Setting", 0,
"do_not_merge_me")); "do_not_merge_me"));
aqua_trans.insert(QTranslatorMessage("QMenuBar", "Config", 0, aqua_trans.insert(QTranslatorMessage("QMenuBar", "Config", 0,
@ -228,6 +207,8 @@ void parse_init(int & argc, char * argv[])
lyxrc.dpi = getDPI(); lyxrc.dpi = getDPI();
LoaderQueue::setPriority(10,100); LoaderQueue::setPriority(10,100);
LyX::ref().exec2(argc, argv);
} }
@ -269,10 +250,7 @@ void start(string const & batch, vector<string> const & files,
qApp->exec(); qApp->exec();
// FIXME // FIXME
delete lyxsocket; cleanup();
delete lyxserver;
lyxserver = 0;
delete app;
} }
@ -288,18 +266,16 @@ void sync_events()
} }
void exit() void exit(int status)
{ {
delete lyxsocket; cleanup();
delete lyxserver;
lyxserver = 0;
// we cannot call qApp->exit(0) - that could return us // we cannot call QApplication::exit(status) - that could return us
// into a static dialog return in the lyx code (for example, // into a static dialog return in the lyx code (for example,
// load autosave file QMessageBox. We have to just get the hell // load autosave file QMessageBox. We have to just get the hell
// out. // out.
::exit(0); ::exit(status);
} }

View File

@ -83,6 +83,7 @@ namespace {
/// quit lyx /// quit lyx
bool finished = false; bool finished = false;
int exit_status = 0;
/// estimate DPI from X server /// estimate DPI from X server
int getDPI() int getDPI()
@ -152,7 +153,7 @@ namespace lyx_gui {
bool use_gui = true; bool use_gui = true;
void parse_init(int & argc, char * argv[]) void exec(int & argc, char * argv[])
{ {
setDefaults(); setDefaults();
@ -197,6 +198,8 @@ void parse_init(int & argc, char * argv[])
lyxrc.dpi = getDPI(); lyxrc.dpi = getDPI();
LoaderQueue::setPriority(10,100); LoaderQueue::setPriority(10,100);
LyX::ref().exec2(argc, argv);
} }
@ -313,12 +316,14 @@ void start(string const & batch, vector<string> const & files,
// FIXME: breaks emergencyCleanup // FIXME: breaks emergencyCleanup
delete lyxsocket; delete lyxsocket;
delete lyxserver; delete lyxserver;
::exit(exit_status);
} }
void exit() void exit(int status)
{ {
finished = true; finished = true;
exit_status = status;
} }

View File

@ -216,7 +216,7 @@ void quitLyX(bool noask)
Alert::warning(_("Unable to remove temporary directory"), msg); Alert::warning(_("Unable to remove temporary directory"), msg);
} }
lyx_gui::exit(); lyx_gui::exit(0);
} }

View File

@ -107,12 +107,23 @@ string cl_system_support;
string cl_user_support; string cl_user_support;
void lyx_exit(int status)
{
// FIXME: We should not directly call exit(), since it only
// guarantees a return to the system, no application cleanup.
// This may cause troubles with not executed destructors.
if (lyx_gui::use_gui)
lyx_gui::exit(status);
exit(status);
}
void showFileError(string const & error) void showFileError(string const & error)
{ {
Alert::warning(_("Could not read configuration file"), Alert::warning(_("Could not read configuration file"),
bformat(_("Error while reading the configuration file\n%1$s.\n" bformat(_("Error while reading the configuration file\n%1$s.\n"
"Please check your installation."), error)); "Please check your installation."), error));
exit(EXIT_FAILURE); lyx_exit(EXIT_FAILURE);
} }
@ -204,14 +215,21 @@ void LyX::priv_exec(int & argc, char * argv[])
{ {
// Here we need to parse the command line. At least // Here we need to parse the command line. At least
// we need to parse for "-dbg" and "-help" // we need to parse for "-dbg" and "-help"
bool const want_gui = easyParse(argc, argv); lyx_gui::use_gui = easyParse(argc, argv);
lyx::support::init_package(argv[0], cl_system_support, cl_user_support, lyx::support::init_package(argv[0], cl_system_support, cl_user_support,
lyx::support::top_build_dir_is_one_level_up); lyx::support::top_build_dir_is_one_level_up);
if (want_gui) // Start the real execution loop.
lyx_gui::parse_init(argc, argv); if (lyx_gui::use_gui)
lyx_gui::exec(argc, argv);
else
exec2(argc, argv);
}
void LyX::exec2(int & argc, char * argv[])
{
// check for any spurious extra arguments // check for any spurious extra arguments
// other than documents // other than documents
for (int argi = 1; argi < argc ; ++argi) { for (int argi = 1; argi < argc ; ++argi) {
@ -224,10 +242,10 @@ void LyX::priv_exec(int & argc, char * argv[])
// Initialization of LyX (reads lyxrc and more) // Initialization of LyX (reads lyxrc and more)
lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl; lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
init(want_gui); init();
lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl; lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
if (want_gui) if (lyx_gui::use_gui)
lyx_gui::parse_lyxrc(); lyx_gui::parse_lyxrc();
vector<string> files; vector<string> files;
@ -278,13 +296,13 @@ void LyX::priv_exec(int & argc, char * argv[])
bool success = false; bool success = false;
if (last_loaded->dispatch(batch_command, &success)) { if (last_loaded->dispatch(batch_command, &success)) {
quitLyX(false); quitLyX(false);
exit(!success); lyx_exit(!success);
} }
} }
files.clear(); // the files are already loaded files.clear(); // the files are already loaded
} }
if (want_gui) { if (lyx_gui::use_gui) {
// determine windows size and position, from lyxrc and/or session // determine windows size and position, from lyxrc and/or session
// initial geometry // initial geometry
unsigned int width = 690; unsigned int width = 690;
@ -296,10 +314,10 @@ void LyX::priv_exec(int & argc, char * argv[])
} }
// if lyxrc returns (0,0), then use session info // if lyxrc returns (0,0), then use session info
else { else {
string val = LyX::ref().session().loadSessionInfo("WindowWidth"); string val = session().loadSessionInfo("WindowWidth");
if (!val.empty()) if (!val.empty())
width = convert<unsigned int>(val); width = convert<unsigned int>(val);
val = LyX::ref().session().loadSessionInfo("WindowHeight"); val = session().loadSessionInfo("WindowHeight");
if (!val.empty()) if (!val.empty())
height = convert<unsigned int>(val); height = convert<unsigned int>(val);
} }
@ -307,10 +325,10 @@ void LyX::priv_exec(int & argc, char * argv[])
int posx = -1; int posx = -1;
int posy = -1; int posy = -1;
if (lyxrc.geometry_xysaved) { if (lyxrc.geometry_xysaved) {
string val = LyX::ref().session().loadSessionInfo("WindowPosX"); string val = session().loadSessionInfo("WindowPosX");
if (!val.empty()) if (!val.empty())
posx = convert<int>(val); posx = convert<int>(val);
val = LyX::ref().session().loadSessionInfo("WindowPosY"); val = session().loadSessionInfo("WindowPosY");
if (!val.empty()) if (!val.empty())
posy = convert<int>(val); posy = convert<int>(val);
} }
@ -318,7 +336,7 @@ void LyX::priv_exec(int & argc, char * argv[])
} else { } else {
// Something went wrong above // Something went wrong above
quitLyX(false); quitLyX(false);
exit(EXIT_FAILURE); lyx_exit(EXIT_FAILURE);
} }
} }
@ -430,7 +448,7 @@ void LyX::printError(ErrorItem const & ei)
} }
void LyX::init(bool gui) void LyX::init()
{ {
#ifdef SIGHUP #ifdef SIGHUP
signal(SIGHUP, error_handler); signal(SIGHUP, error_handler);
@ -441,9 +459,6 @@ void LyX::init(bool gui)
signal(SIGTERM, error_handler); signal(SIGTERM, error_handler);
// SIGPIPE can be safely ignored. // SIGPIPE can be safely ignored.
// Disable gui when easyparse says so
lyx_gui::use_gui = gui;
lyxrc.tempdir_path = package().temp_dir(); lyxrc.tempdir_path = package().temp_dir();
lyxrc.document_path = package().document_dir(); lyxrc.document_path = package().document_dir();
@ -478,7 +493,7 @@ void LyX::init(bool gui)
// Check that user LyX directory is ok. We don't do that if // Check that user LyX directory is ok. We don't do that if
// running in batch mode. // running in batch mode.
if (gui) { if (lyx_gui::use_gui) {
if (queryUserLyXDir(package().explicit_user_support())) if (queryUserLyXDir(package().explicit_user_support()))
reconfigureUserLyXDir(); reconfigureUserLyXDir();
} else { } else {
@ -507,7 +522,7 @@ void LyX::init(bool gui)
lyxerr[Debug::INIT] << "Reading layouts..." << endl; lyxerr[Debug::INIT] << "Reading layouts..." << endl;
LyXSetStyle(); LyXSetStyle();
if (gui) { if (lyx_gui::use_gui) {
// Set up bindings // Set up bindings
toplevel_keymap.reset(new kb_keymap); toplevel_keymap.reset(new kb_keymap);
defaultKeyBindings(toplevel_keymap.get()); defaultKeyBindings(toplevel_keymap.get());
@ -540,7 +555,7 @@ void LyX::init(bool gui)
// close to zero. We therefore don't try to overcome this // close to zero. We therefore don't try to overcome this
// problem with e.g. asking the user for a new path and // problem with e.g. asking the user for a new path and
// trying again but simply exit. // trying again but simply exit.
exit(EXIT_FAILURE); lyx_exit(EXIT_FAILURE);
} }
if (lyxerr.debugging(Debug::INIT)) { if (lyxerr.debugging(Debug::INIT)) {
@ -688,7 +703,7 @@ bool LyX::queryUserLyXDir(bool explicit_userdir)
_("&Create directory"), _("&Create directory"),
_("&Exit LyX"))) { _("&Exit LyX"))) {
lyxerr << _("No user LyX directory. Exiting.") << endl; lyxerr << _("No user LyX directory. Exiting.") << endl;
exit(1); lyx_exit(EXIT_FAILURE);
} }
lyxerr << bformat(_("LyX: Creating directory %1$s"), lyxerr << bformat(_("LyX: Creating directory %1$s"),
@ -699,7 +714,7 @@ bool LyX::queryUserLyXDir(bool explicit_userdir)
// Failed, so let's exit. // Failed, so let's exit.
lyxerr << _("Failed to create directory. Exiting.") lyxerr << _("Failed to create directory. Exiting.")
<< endl; << endl;
exit(1); lyx_exit(EXIT_FAILURE);
} }
return true; return true;

View File

@ -34,7 +34,21 @@ namespace lyx {
/// initial startup /// initial startup
class LyX : boost::noncopyable { class LyX : boost::noncopyable {
public: public:
/**
* Execute LyX. The startup sequence is as follows:
* -# LyX::exec()
* -# LyX::priv_exec()
* -# lyx_gui::exec()
* -# LyX::exec2()
* Step 3 is omitted if no gui is wanted. We need lyx_gui::exec()
* only to create the QApplication object in the qt frontend. All
* attempts with static and dynamically allocated QApplication
* objects lead either to harmless error messages on exit
* ("Mutex destroy failure") or crashes (OS X).
*/
static void exec(int & argc, char * argv[]); static void exec(int & argc, char * argv[]);
/// Execute LyX (inner execution loop, \sa exec)
void exec2(int & argc, char * argv[]);
static LyX & ref(); static LyX & ref();
static LyX const & cref(); static LyX const & cref();
@ -58,7 +72,7 @@ private:
void priv_exec(int & argc, char * argv[]); void priv_exec(int & argc, char * argv[]);
/// initial LyX set up /// initial LyX set up
void init(bool); void init();
/// set up the default key bindings /// set up the default key bindings
void defaultKeyBindings(kb_keymap * kbmap); void defaultKeyBindings(kb_keymap * kbmap);
/// set up the default dead key bindings if requested /// set up the default dead key bindings if requested