3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
21 #include "ConverterCache.h"
23 #include "buffer_funcs.h"
24 #include "BufferList.h"
25 #include "Converter.h"
26 #include "CutAndPaste.h"
29 #include "ErrorList.h"
36 #include "LyXAction.h"
40 #include "ModuleList.h"
42 #include "ServerSocket.h"
43 #include "TextClassList.h"
44 #include "MenuBackend.h"
47 #include "ToolbarBackend.h"
49 #include "frontends/alert.h"
50 #include "frontends/Application.h"
51 #include "frontends/Dialogs.h"
52 #include "frontends/Gui.h"
53 #include "frontends/LyXView.h"
55 #include "support/environment.h"
56 #include "support/filetools.h"
57 #include "support/lstrings.h"
58 #include "support/lyxlib.h"
59 #include "support/convert.h"
60 #include "support/ExceptionMessage.h"
61 #include "support/os.h"
62 #include "support/Package.h"
63 #include "support/Path.h"
64 #include "support/Systemcall.h"
66 #include <boost/bind.hpp>
67 #include <boost/scoped_ptr.hpp>
83 #ifndef CXX_GLOBAL_CSTD
91 using support::addName;
92 using support::addPath;
93 using support::bformat;
94 using support::changeExtension;
95 using support::createLyXTmpDir;
96 using support::FileName;
97 using support::fileSearch;
98 using support::getEnv;
99 using support::i18nLibFileSearch;
100 using support::libFileSearch;
101 using support::package;
102 using support::prependEnvPath;
103 using support::rtrim;
104 using support::Systemcall;
105 using frontend::LyXView;
107 namespace Alert = frontend::Alert;
108 namespace os = support::os;
112 // Are we using the GUI at all? We default to true and this is changed
113 // to false when the export feature is used.
117 bool quitting; // flag, that we are quitting the program
121 // Filled with the command line arguments "foo" of "-sysdir foo" or
123 string cl_system_support;
124 string cl_user_support;
126 std::string geometryArg;
128 LyX * singleton_ = 0;
130 void showFileError(string const & error)
132 Alert::warning(_("Could not read configuration file"),
133 bformat(_("Error while reading the configuration file\n%1$s.\n"
134 "Please check your installation."), from_utf8(error)));
138 void reconfigureUserLyXDir()
140 string const configure_command = package().configure_command();
142 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
143 support::PathChanger p(package().user_support());
145 one.startscript(Systemcall::Wait, configure_command);
146 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
152 /// The main application class private implementation.
153 struct LyX::Singletons
157 // Set the default User Interface language as soon as possible.
158 // The language used will be derived from the environment
160 messages_["GUI"] = Messages();
162 /// our function handler
165 BufferList buffer_list_;
167 boost::scoped_ptr<KeyMap> toplevel_keymap_;
169 boost::scoped_ptr<CmdDef> toplevel_cmddef_;
171 boost::scoped_ptr<Server> lyx_server_;
173 boost::scoped_ptr<ServerSocket> lyx_socket_;
175 boost::scoped_ptr<frontend::Application> application_;
176 /// lyx session, containing lastfiles, lastfilepos, and lastopened
177 boost::scoped_ptr<Session> session_;
179 /// Files to load at start.
180 vector<FileName> files_to_load_;
182 /// The messages translators.
183 map<string, Messages> messages_;
185 /// The file converters.
186 Converters converters_;
188 // The system converters copy after reading lyxrc.defaults.
189 Converters system_converters_;
195 Movers system_movers_;
199 frontend::Application * theApp()
202 return singleton_->pimpl_->application_.get();
216 BOOST_ASSERT(singleton_);
221 LyX const & LyX::cref()
223 BOOST_ASSERT(singleton_);
232 pimpl_ = new Singletons;
236 BufferList & LyX::bufferList()
238 return pimpl_->buffer_list_;
242 BufferList const & LyX::bufferList() const
244 return pimpl_->buffer_list_;
248 Session & LyX::session()
250 BOOST_ASSERT(pimpl_->session_.get());
251 return *pimpl_->session_.get();
255 Session const & LyX::session() const
257 BOOST_ASSERT(pimpl_->session_.get());
258 return *pimpl_->session_.get();
262 LyXFunc & LyX::lyxFunc()
264 return pimpl_->lyxfunc_;
268 LyXFunc const & LyX::lyxFunc() const
270 return pimpl_->lyxfunc_;
274 Server & LyX::server()
276 BOOST_ASSERT(pimpl_->lyx_server_.get());
277 return *pimpl_->lyx_server_.get();
281 Server const & LyX::server() const
283 BOOST_ASSERT(pimpl_->lyx_server_.get());
284 return *pimpl_->lyx_server_.get();
288 ServerSocket & LyX::socket()
290 BOOST_ASSERT(pimpl_->lyx_socket_.get());
291 return *pimpl_->lyx_socket_.get();
295 ServerSocket const & LyX::socket() const
297 BOOST_ASSERT(pimpl_->lyx_socket_.get());
298 return *pimpl_->lyx_socket_.get();
302 frontend::Application & LyX::application()
304 BOOST_ASSERT(pimpl_->application_.get());
305 return *pimpl_->application_.get();
309 frontend::Application const & LyX::application() const
311 BOOST_ASSERT(pimpl_->application_.get());
312 return *pimpl_->application_.get();
316 KeyMap & LyX::topLevelKeymap()
318 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
319 return *pimpl_->toplevel_keymap_.get();
323 CmdDef & LyX::topLevelCmdDef()
325 BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
326 return *pimpl_->toplevel_cmddef_.get();
330 Converters & LyX::converters()
332 return pimpl_->converters_;
336 Converters & LyX::systemConverters()
338 return pimpl_->system_converters_;
342 KeyMap const & LyX::topLevelKeymap() const
344 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
345 return *pimpl_->toplevel_keymap_.get();
349 Messages & LyX::getMessages(std::string const & language)
351 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
353 if (it != pimpl_->messages_.end())
356 std::pair<map<string, Messages>::iterator, bool> result =
357 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
359 BOOST_ASSERT(result.second);
360 return result.first->second;
364 Messages & LyX::getGuiMessages()
366 return pimpl_->messages_["GUI"];
370 void LyX::setGuiLanguage(std::string const & language)
372 pimpl_->messages_["GUI"] = Messages(language);
376 Buffer const * LyX::updateInset(Inset const * inset) const
378 if (quitting || !inset)
381 Buffer const * buffer_ptr = 0;
382 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
383 vector<int>::const_iterator it = view_ids.begin();
384 vector<int>::const_iterator const end = view_ids.end();
385 for (; it != end; ++it) {
387 pimpl_->application_->gui().view(*it).updateInset(inset);
395 void LyX::hideDialogs(std::string const & name, Inset * inset) const
397 if (quitting || !use_gui)
400 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
401 vector<int>::const_iterator it = view_ids.begin();
402 vector<int>::const_iterator const end = view_ids.end();
403 for (; it != end; ++it)
404 pimpl_->application_->gui().view(*it).getDialogs().
409 int LyX::exec(int & argc, char * argv[])
411 // Here we need to parse the command line. At least
412 // we need to parse for "-dbg" and "-help"
413 easyParse(argc, argv);
416 support::init_package(to_utf8(from_local8bit(argv[0])),
417 cl_system_support, cl_user_support,
418 support::top_build_dir_is_one_level_up);
419 } catch (support::ExceptionMessage const & message) {
420 if (message.type_ == support::ErrorException) {
421 Alert::error(message.title_, message.details_);
423 } else if (message.type_ == support::WarningException) {
424 Alert::warning(message.title_, message.details_);
428 // Reinit the messages machinery in case package() knows
429 // something interesting about the locale directory.
433 // FIXME: create a ConsoleApplication
434 int exit_status = init(argc, argv);
442 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
447 BufferList::iterator begin = pimpl_->buffer_list_.begin();
449 bool final_success = false;
450 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
452 if (buf != buf->masterBuffer())
454 bool success = false;
455 buf->dispatch(batch_command, &success);
456 final_success |= success;
459 return !final_success;
462 // Let the frontend parse and remove all arguments that it knows
463 pimpl_->application_.reset(createApplication(argc, argv));
467 // Parse and remove all known arguments in the LyX singleton
468 // Give an error for all remaining ones.
469 int exit_status = init(argc, argv);
471 // Kill the application object before exiting.
472 pimpl_->application_.reset();
479 /* Create a CoreApplication class that will provide the main event loop
480 * and the socket callback registering. With Qt4, only QtCore
481 * library would be needed.
482 * When this is done, a server_mode could be created and the following two
483 * line would be moved out from here.
485 // Note: socket callback must be registered after init(argc, argv)
486 // such that package().temp_dir() is properly initialized.
487 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
488 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
489 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
491 // Start the real execution loop.
492 exit_status = pimpl_->application_->exec();
500 void LyX::prepareExit()
502 // Clear the clipboard and selection stack:
503 cap::clearCutStack();
504 cap::clearSelection();
506 // Set a flag that we do quitting from the program,
507 // so no refreshes are necessary.
510 // close buffers first
511 pimpl_->buffer_list_.closeAll();
513 // do any other cleanup procedures now
514 if (package().temp_dir() != package().system_temp_dir()) {
515 LYXERR(Debug::INFO) << "Deleting tmp dir "
516 << package().temp_dir().absFilename() << endl;
518 if (!package().temp_dir().destroyDirectory()) {
519 docstring const msg =
520 bformat(_("Unable to remove the temporary directory %1$s"),
521 from_utf8(package().temp_dir().absFilename()));
522 Alert::warning(_("Unable to remove temporary directory"), msg);
527 if (pimpl_->session_)
528 pimpl_->session_->writeFile();
529 pimpl_->session_.reset();
530 pimpl_->lyx_server_.reset();
531 pimpl_->lyx_socket_.reset();
534 // Kill the application object before exiting. This avoids crashes
535 // when exiting on Linux.
536 if (pimpl_->application_)
537 pimpl_->application_.reset();
541 void LyX::earlyExit(int status)
543 BOOST_ASSERT(pimpl_->application_.get());
544 // LyX::pimpl_::application_ is not initialised at this
545 // point so it's safe to just exit after some cleanup.
551 int LyX::init(int & argc, char * argv[])
553 // check for any spurious extra arguments
554 // other than documents
555 for (int argi = 1; argi < argc ; ++argi) {
556 if (argv[argi][0] == '-') {
558 bformat(_("Wrong command line option `%1$s'. Exiting."),
559 from_utf8(argv[argi]))) << endl;
564 // Initialization of LyX (reads lyxrc and more)
565 LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
566 bool success = init();
567 LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
571 for (int argi = argc - 1; argi >= 1; --argi) {
572 // get absolute path of file and add ".lyx" to
573 // the filename if necessary
574 pimpl_->files_to_load_.push_back(fileSearch(string(),
575 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
576 "lyx", support::allow_unreadable));
580 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
586 void LyX::addFileToLoad(FileName const & fname)
588 vector<FileName>::const_iterator cit = std::find(
589 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
592 if (cit == pimpl_->files_to_load_.end())
593 pimpl_->files_to_load_.push_back(fname);
597 void LyX::loadFiles()
599 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
600 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
602 for (; it != end; ++it) {
606 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
607 if (buf->loadLyXFile(*it)) {
608 ErrorList const & el = buf->errorList("Parse");
610 for_each(el.begin(), el.end(),
611 boost::bind(&LyX::printError, this, _1));
614 pimpl_->buffer_list_.release(buf);
619 void LyX::execBatchCommands()
621 // The advantage of doing this here is that the event loop
622 // is already started. So any need for interaction will be
626 // if reconfiguration is needed.
627 if (textclasslist.empty()) {
628 switch (Alert::prompt(
629 _("No textclass is found"),
630 _("LyX cannot continue because no textclass is found. "
631 "You can either reconfigure normally, or reconfigure using "
632 "default textclasses, or quit LyX."),
639 // regular reconfigure
640 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
643 // reconfigure --without-latex-config
644 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
645 " --without-latex-config"));
648 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
652 // Execute batch commands if available
653 if (batch_command.empty())
656 LYXERR(Debug::INIT) << "About to handle -x '"
657 << batch_command << '\'' << endl;
659 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
663 void LyX::restoreGuiSession()
665 LyXView * view = newLyXView();
667 // if there is no valid class list, do not load any file.
668 if (textclasslist.empty())
671 // if some files were specified at command-line we assume that the
672 // user wants to edit *these* files and not to restore the session.
673 if (!pimpl_->files_to_load_.empty()) {
674 for_each(pimpl_->files_to_load_.begin(),
675 pimpl_->files_to_load_.end(),
676 bind(&LyXView::loadLyXFile, view, _1, true));
677 // clear this list to save a few bytes of RAM
678 pimpl_->files_to_load_.clear();
679 pimpl_->session_->lastOpened().clear();
681 } else if (lyxrc.load_session) {
682 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
683 // do not add to the lastfile list since these files are restored from
684 // last session, and should be already there (regular files), or should
685 // not be added at all (help files).
686 for_each(lastopened.begin(), lastopened.end(),
687 bind(&LyXView::loadLyXFile, view, _1, false));
689 // clear this list to save a few bytes of RAM
690 pimpl_->session_->lastOpened().clear();
693 BufferList::iterator I = pimpl_->buffer_list_.begin();
694 BufferList::iterator end = pimpl_->buffer_list_.end();
695 for (; I != end; ++I) {
697 if (buf != buf->masterBuffer())
702 // FIXME: Switch to the last loaded Buffer. This must not be the first one
703 // because the Buffer won't be connected in this case. The correct solution
704 // would be to avoid the manual connection of the current Buffer in LyXView.
705 if (!pimpl_->buffer_list_.empty())
706 view->setBuffer(pimpl_->buffer_list_.last());
710 LyXView * LyX::newLyXView()
715 // FIXME: transfer all this geometry stuff to the frontend.
717 // determine windows size and position, from lyxrc and/or session
719 unsigned int width = 690;
720 unsigned int height = 510;
721 // default icon size, will be overwritten by stored session value
722 unsigned int iconSizeXY = 0;
723 // FIXME: 0 means GuiView::NotMaximized by default!
726 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
727 width = lyxrc.geometry_width;
728 height = lyxrc.geometry_height;
730 // if lyxrc returns (0,0), then use session info
732 string val = session().sessionInfo().load("WindowWidth");
734 width = convert<unsigned int>(val);
735 val = session().sessionInfo().load("WindowHeight");
737 height = convert<unsigned int>(val);
738 val = session().sessionInfo().load("WindowMaximized");
740 maximized = convert<int>(val);
741 val = session().sessionInfo().load("IconSizeXY");
743 iconSizeXY = convert<unsigned int>(val);
746 // if user wants to restore window position
749 if (lyxrc.geometry_xysaved) {
750 string val = session().sessionInfo().load("WindowPosX");
752 posx = convert<int>(val);
753 val = session().sessionInfo().load("WindowPosY");
755 posy = convert<int>(val);
758 if (!geometryArg.empty())
764 // create the main window
765 LyXView * view = &pimpl_->application_->createView(width, height,
766 posx, posy, maximized, iconSizeXY, geometryArg);
774 The SIGHUP signal does not exist on Windows and does not need to be handled.
776 Windows handles SIGFPE and SIGSEGV signals as expected.
778 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
779 cause a new thread to be spawned. This may well result in unexpected
780 behaviour by the single-threaded LyX.
782 SIGTERM signals will come only from another process actually sending
783 that signal using 'raise' in Windows' POSIX compatability layer. It will
784 not come from the general "terminate process" methods that everyone
785 actually uses (and which can't be trapped). Killing an app 'politely' on
786 Windows involves first sending a WM_CLOSE message, something that is
787 caught already by the Qt frontend.
789 For more information see:
791 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
792 ...signals are mostly useless on Windows for a variety of reasons that are
795 'UNIX Application Migration Guide, Chapter 9'
796 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
798 'How To Terminate an Application "Cleanly" in Win32'
799 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
803 static void error_handler(int err_sig)
805 // Throw away any signals other than the first one received.
806 static sig_atomic_t handling_error = false;
809 handling_error = true;
811 // We have received a signal indicating a fatal error, so
812 // try and save the data ASAP.
813 LyX::cref().emergencyCleanup();
815 // These lyxerr calls may or may not work:
817 // Signals are asynchronous, so the main program may be in a very
818 // fragile state when a signal is processed and thus while a signal
819 // handler function executes.
820 // In general, therefore, we should avoid performing any
821 // I/O operations or calling most library and system functions from
824 // This shouldn't matter here, however, as we've already invoked
829 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
833 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
836 lyxerr << "\nlyx: SIGSEGV signal caught\n"
837 "Sorry, you have found a bug in LyX. "
838 "Please read the bug-reporting instructions "
839 "in Help->Introduction and send us a bug report, "
840 "if necessary. Thanks !\nBye." << endl;
848 // Deinstall the signal handlers
850 signal(SIGHUP, SIG_DFL);
852 signal(SIGINT, SIG_DFL);
853 signal(SIGFPE, SIG_DFL);
854 signal(SIGSEGV, SIG_DFL);
855 signal(SIGTERM, SIG_DFL);
858 if (err_sig == SIGSEGV ||
859 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
861 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
870 void LyX::printError(ErrorItem const & ei)
872 docstring tmp = _("LyX: ") + ei.error + char_type(':')
874 std::cerr << to_utf8(tmp) << std::endl;
878 void LyX::initGuiFont()
880 if (lyxrc.roman_font_name.empty())
881 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
883 if (lyxrc.sans_font_name.empty())
884 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
886 if (lyxrc.typewriter_font_name.empty())
887 lyxrc.typewriter_font_name
888 = pimpl_->application_->typewriterFontName();
895 signal(SIGHUP, error_handler);
897 signal(SIGFPE, error_handler);
898 signal(SIGSEGV, error_handler);
899 signal(SIGINT, error_handler);
900 signal(SIGTERM, error_handler);
901 // SIGPIPE can be safely ignored.
903 lyxrc.tempdir_path = package().temp_dir().absFilename();
904 lyxrc.document_path = package().document_dir().absFilename();
906 if (lyxrc.template_path.empty()) {
907 lyxrc.template_path = addPath(package().system_support().absFilename(),
912 // Read configuration files
915 // This one may have been distributed along with LyX.
916 if (!readRcFile("lyxrc.dist"))
919 // Set the language defined by the distributor.
920 //setGuiLanguage(lyxrc.gui_language);
922 // Set the PATH correctly.
923 #if !defined (USE_POSIX_PACKAGING)
924 // Add the directory containing the LyX executable to the path
925 // so that LyX can find things like tex2lyx.
926 if (package().build_support().empty())
927 prependEnvPath("PATH", package().binary_dir().absFilename());
929 if (!lyxrc.path_prefix.empty())
930 prependEnvPath("PATH", lyxrc.path_prefix);
932 // Check that user LyX directory is ok.
933 if (queryUserLyXDir(package().explicit_user_support()))
934 reconfigureUserLyXDir();
936 // no need for a splash when there is no GUI
941 // This one is generated in user_support directory by lib/configure.py.
942 if (!readRcFile("lyxrc.defaults"))
945 // Query the OS to know what formats are viewed natively
946 formats.setAutoOpen();
948 // Read lyxrc.dist again to be able to override viewer auto-detection.
949 readRcFile("lyxrc.dist");
951 system_lyxrc = lyxrc;
952 system_formats = formats;
953 pimpl_->system_converters_ = pimpl_->converters_;
954 pimpl_->system_movers_ = pimpl_->movers_;
955 system_lcolor = lcolor;
957 // This one is edited through the preferences dialog.
958 if (!readRcFile("preferences"))
961 if (!readEncodingsFile("encodings", "unicodesymbols"))
963 if (!readLanguagesFile("languages"))
967 LYXERR(Debug::INIT) << "Reading layouts..." << endl;
973 // read keymap and ui files in batch mode as well
974 // because InsetInfo needs to know these to produce
975 // the correct output
977 // Set the language defined by the user.
978 //setGuiLanguage(lyxrc.gui_language);
980 // Set up command definitions
981 pimpl_->toplevel_cmddef_.reset(new CmdDef);
982 pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
985 pimpl_->toplevel_keymap_.reset(new KeyMap);
986 pimpl_->toplevel_keymap_->read("site");
987 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
988 // load user bind file user.bind
989 pimpl_->toplevel_keymap_->read("user");
991 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
994 if (!readUIFile(lyxrc.ui_file))
997 if (lyxerr.debugging(Debug::LYXRC))
1000 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
1001 if (!lyxrc.path_prefix.empty())
1002 prependEnvPath("PATH", lyxrc.path_prefix);
1004 FileName const document_path(lyxrc.document_path);
1005 if (document_path.exists() && document_path.isDirectory())
1006 package().document_dir() = document_path;
1008 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
1009 if (package().temp_dir().empty()) {
1010 Alert::error(_("Could not create temporary directory"),
1011 bformat(_("Could not create a temporary directory in\n"
1012 "%1$s. Make sure that this\n"
1013 "path exists and is writable and try again."),
1014 from_utf8(lyxrc.tempdir_path)));
1015 // createLyXTmpDir() tries sufficiently hard to create a
1016 // usable temp dir, so the probability to come here is
1017 // close to zero. We therefore don't try to overcome this
1018 // problem with e.g. asking the user for a new path and
1019 // trying again but simply exit.
1023 LYXERR(Debug::INIT) << "LyX tmp dir: `"
1024 << package().temp_dir().absFilename()
1027 LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
1028 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
1030 // This must happen after package initialization and after lyxrc is
1031 // read, therefore it can't be done by a static object.
1032 ConverterCache::init();
1038 void LyX::emergencyCleanup() const
1040 // what to do about tmpfiles is non-obvious. we would
1041 // like to delete any we find, but our lyxdir might
1042 // contain documents etc. which might be helpful on
1045 pimpl_->buffer_list_.emergencyWriteAll();
1047 if (pimpl_->lyx_server_)
1048 pimpl_->lyx_server_->emergencyCleanup();
1049 pimpl_->lyx_server_.reset();
1050 pimpl_->lyx_socket_.reset();
1055 void LyX::deadKeyBindings(KeyMap * kbmap)
1057 // bindKeyings for transparent handling of deadkeys
1058 // The keysyms are gotten from XFree86 X11R6
1059 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1060 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1061 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1062 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1063 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1064 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1065 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1066 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1067 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1068 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1069 // nothing with this name
1070 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1071 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1072 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1073 // nothing with this name either...
1074 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1075 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1076 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1077 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1081 // return true if file does not exist or is older than configure.py.
1082 static bool needsUpdate(string const & file)
1084 // We cannot initialize configure_script directly because the package
1085 // is not initialized yet when static objects are constructed.
1086 static FileName configure_script;
1087 static bool firstrun = true;
1090 FileName(addName(package().system_support().absFilename(),
1096 FileName(addName(package().user_support().absFilename(), file));
1097 return !absfile.exists()
1098 || configure_script.lastModified() > absfile.lastModified();
1102 bool LyX::queryUserLyXDir(bool explicit_userdir)
1104 // Does user directory exist?
1105 FileName const sup = package().user_support();
1106 if (sup.exists() && sup.isDirectory()) {
1107 first_start = false;
1109 return needsUpdate("lyxrc.defaults")
1110 || needsUpdate("lyxmodules.lst")
1111 || needsUpdate("textclass.lst")
1112 || needsUpdate("packages.lst");
1115 first_start = !explicit_userdir;
1117 // If the user specified explicitly a directory, ask whether
1118 // to create it. If the user says "no", then exit.
1119 if (explicit_userdir &&
1121 _("Missing user LyX directory"),
1122 bformat(_("You have specified a non-existent user "
1123 "LyX directory, %1$s.\n"
1124 "It is needed to keep your own configuration."),
1125 from_utf8(package().user_support().absFilename())),
1127 _("&Create directory"),
1129 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1130 earlyExit(EXIT_FAILURE);
1133 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1134 from_utf8(sup.absFilename()))) << endl;
1136 if (!sup.createDirectory(0755)) {
1137 // Failed, so let's exit.
1138 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1140 earlyExit(EXIT_FAILURE);
1147 bool LyX::readRcFile(string const & name)
1149 LYXERR(Debug::INIT) << "About to read " << name << "... ";
1151 FileName const lyxrc_path = libFileSearch(string(), name);
1152 if (!lyxrc_path.empty()) {
1154 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1156 if (lyxrc.read(lyxrc_path) < 0) {
1157 showFileError(name);
1161 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1167 // Read the ui file `name'
1168 bool LyX::readUIFile(string const & name, bool include)
1178 struct keyword_item uitags[ui_last - 1] = {
1179 { "include", ui_include },
1180 { "menuset", ui_menuset },
1181 { "toolbars", ui_toolbars },
1182 { "toolbarset", ui_toolbarset }
1185 // Ensure that a file is read only once (prevents include loops)
1186 static std::list<string> uifiles;
1187 std::list<string>::const_iterator it = uifiles.begin();
1188 std::list<string>::const_iterator end = uifiles.end();
1189 it = std::find(it, end, name);
1191 LYXERR(Debug::INIT) << "UI file '" << name
1192 << "' has been read already. "
1193 << "Is this an include loop?"
1198 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1203 ui_path = libFileSearch("ui", name, "inc");
1204 if (ui_path.empty())
1205 ui_path = libFileSearch("ui",
1206 changeExtension(name, "inc"));
1209 ui_path = libFileSearch("ui", name, "ui");
1211 if (ui_path.empty()) {
1212 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1213 showFileError(name);
1217 uifiles.push_back(name);
1219 LYXERR(Debug::INIT) << "Found " << name
1220 << " in " << ui_path << endl;
1221 Lexer lex(uitags, ui_last - 1);
1222 lex.setFile(ui_path);
1224 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1228 if (lyxerr.debugging(Debug::PARSER))
1229 lex.printTable(lyxerr);
1231 while (lex.isOK()) {
1232 switch (lex.lex()) {
1235 string const file = lex.getString();
1236 if (!readUIFile(file, true))
1241 menubackend.read(lex);
1245 toolbarbackend.readToolbars(lex);
1249 toolbarbackend.readToolbarSettings(lex);
1253 if (!rtrim(lex.getString()).empty())
1254 lex.printError("LyX::ReadUIFile: "
1255 "Unknown menu tag: `$$Token'");
1263 // Read the languages file `name'
1264 bool LyX::readLanguagesFile(string const & name)
1266 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1268 FileName const lang_path = libFileSearch(string(), name);
1269 if (lang_path.empty()) {
1270 showFileError(name);
1273 languages.read(lang_path);
1278 // Read the encodings file `name'
1279 bool LyX::readEncodingsFile(string const & enc_name,
1280 string const & symbols_name)
1282 LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1283 << symbols_name << "..." << endl;
1285 FileName const symbols_path = libFileSearch(string(), symbols_name);
1286 if (symbols_path.empty()) {
1287 showFileError(symbols_name);
1291 FileName const enc_path = libFileSearch(string(), enc_name);
1292 if (enc_path.empty()) {
1293 showFileError(enc_name);
1296 encodings.read(enc_path, symbols_path);
1305 /// return the the number of arguments consumed
1306 typedef boost::function<int(string const &, string const &)> cmd_helper;
1308 int parse_dbg(string const & arg, string const &)
1311 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1312 Debug::showTags(lyxerr);
1315 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1317 lyxerr.level(Debug::value(arg));
1318 Debug::showLevel(lyxerr, lyxerr.level());
1323 int parse_help(string const &, string const &)
1326 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1327 "Command line switches (case sensitive):\n"
1328 "\t-help summarize LyX usage\n"
1329 "\t-userdir dir set user directory to dir\n"
1330 "\t-sysdir dir set system directory to dir\n"
1331 "\t-geometry WxH+X+Y set geometry of the main window\n"
1332 "\t-dbg feature[,feature]...\n"
1333 " select the features to debug.\n"
1334 " Type `lyx -dbg' to see the list of features\n"
1335 "\t-x [--execute] command\n"
1336 " where command is a lyx command.\n"
1337 "\t-e [--export] fmt\n"
1338 " where fmt is the export format of choice.\n"
1339 "\t-i [--import] fmt file.xxx\n"
1340 " where fmt is the import format of choice\n"
1341 " and file.xxx is the file to be imported.\n"
1342 "\t-version summarize version and build info\n"
1343 "Check the LyX man page for more details.")) << endl;
1349 int parse_version(string const &, string const &)
1351 lyxerr << "LyX " << lyx_version
1352 << " (" << lyx_release_date << ")" << endl;
1353 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1355 lyxerr << lyx_version_info << endl;
1361 int parse_sysdir(string const & arg, string const &)
1364 Alert::error(_("No system directory"),
1365 _("Missing directory for -sysdir switch"));
1368 cl_system_support = arg;
1373 int parse_userdir(string const & arg, string const &)
1376 Alert::error(_("No user directory"),
1377 _("Missing directory for -userdir switch"));
1380 cl_user_support = arg;
1385 int parse_execute(string const & arg, string const &)
1388 Alert::error(_("Incomplete command"),
1389 _("Missing command string after --execute switch"));
1397 int parse_export(string const & type, string const &)
1400 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1401 "--export switch")) << endl;
1404 batch = "buffer-export " + type;
1410 int parse_import(string const & type, string const & file)
1413 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1414 "--import switch")) << endl;
1418 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1422 batch = "buffer-import " + type + ' ' + file;
1427 int parse_geometry(string const & arg1, string const &)
1430 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1431 // remove also the arg
1434 // don't remove "-geometry"
1443 void LyX::easyParse(int & argc, char * argv[])
1445 std::map<string, cmd_helper> cmdmap;
1447 cmdmap["-dbg"] = parse_dbg;
1448 cmdmap["-help"] = parse_help;
1449 cmdmap["--help"] = parse_help;
1450 cmdmap["-version"] = parse_version;
1451 cmdmap["--version"] = parse_version;
1452 cmdmap["-sysdir"] = parse_sysdir;
1453 cmdmap["-userdir"] = parse_userdir;
1454 cmdmap["-x"] = parse_execute;
1455 cmdmap["--execute"] = parse_execute;
1456 cmdmap["-e"] = parse_export;
1457 cmdmap["--export"] = parse_export;
1458 cmdmap["-i"] = parse_import;
1459 cmdmap["--import"] = parse_import;
1460 cmdmap["-geometry"] = parse_geometry;
1462 for (int i = 1; i < argc; ++i) {
1463 std::map<string, cmd_helper>::const_iterator it
1464 = cmdmap.find(argv[i]);
1466 // don't complain if not found - may be parsed later
1467 if (it == cmdmap.end())
1471 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1473 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1475 int const remove = 1 + it->second(arg, arg2);
1477 // Now, remove used arguments by shifting
1478 // the following ones remove places down.
1481 for (int j = i; j < argc; ++j)
1482 argv[j] = argv[j + remove];
1487 batch_command = batch;
1491 FuncStatus getStatus(FuncRequest const & action)
1493 return LyX::ref().lyxFunc().getStatus(action);
1497 void dispatch(FuncRequest const & action)
1499 LyX::ref().lyxFunc().dispatch(action);
1503 BufferList & theBufferList()
1505 return LyX::ref().bufferList();
1509 LyXFunc & theLyXFunc()
1511 return LyX::ref().lyxFunc();
1515 Server & theServer()
1517 // FIXME: this should not be use_gui dependent
1518 BOOST_ASSERT(use_gui);
1519 return LyX::ref().server();
1523 ServerSocket & theServerSocket()
1525 // FIXME: this should not be use_gui dependent
1526 BOOST_ASSERT(use_gui);
1527 return LyX::ref().socket();
1531 KeyMap & theTopLevelKeymap()
1533 return LyX::ref().topLevelKeymap();
1537 Converters & theConverters()
1539 return LyX::ref().converters();
1543 Converters & theSystemConverters()
1545 return LyX::ref().systemConverters();
1549 Movers & theMovers()
1551 return LyX::ref().pimpl_->movers_;
1555 Mover const & getMover(std::string const & fmt)
1557 return LyX::ref().pimpl_->movers_(fmt);
1561 void setMover(std::string const & fmt, std::string const & command)
1563 LyX::ref().pimpl_->movers_.set(fmt, command);
1567 Movers & theSystemMovers()
1569 return LyX::ref().pimpl_->system_movers_;
1573 Messages & getMessages(std::string const & language)
1575 return LyX::ref().getMessages(language);
1579 Messages & getGuiMessages()
1581 return LyX::ref().getGuiMessages();