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/lyxlib.h"
58 #include "support/convert.h"
59 #include "support/ExceptionMessage.h"
60 #include "support/os.h"
61 #include "support/Package.h"
62 #include "support/Path.h"
63 #include "support/Systemcall.h"
65 #include <boost/bind.hpp>
66 #include <boost/scoped_ptr.hpp>
82 #ifndef CXX_GLOBAL_CSTD
90 using support::addName;
91 using support::addPath;
92 using support::bformat;
93 using support::changeExtension;
94 using support::createLyXTmpDir;
95 using support::FileName;
96 using support::fileSearch;
97 using support::getEnv;
98 using support::i18nLibFileSearch;
99 using support::libFileSearch;
100 using support::package;
101 using support::prependEnvPath;
102 using support::rtrim;
103 using support::Systemcall;
104 using frontend::LyXView;
106 namespace Alert = frontend::Alert;
107 namespace os = support::os;
111 // Are we using the GUI at all? We default to true and this is changed
112 // to false when the export feature is used.
116 bool quitting; // flag, that we are quitting the program
120 // Filled with the command line arguments "foo" of "-sysdir foo" or
122 string cl_system_support;
123 string cl_user_support;
125 std::string geometryArg;
127 LyX * singleton_ = 0;
129 void showFileError(string const & error)
131 Alert::warning(_("Could not read configuration file"),
132 bformat(_("Error while reading the configuration file\n%1$s.\n"
133 "Please check your installation."), from_utf8(error)));
137 void reconfigureUserLyXDir()
139 string const configure_command = package().configure_command();
141 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
142 support::PathChanger p(package().user_support());
144 one.startscript(Systemcall::Wait, configure_command);
145 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
151 /// The main application class private implementation.
152 struct LyX::Singletons
156 // Set the default User Interface language as soon as possible.
157 // The language used will be derived from the environment
159 messages_["GUI"] = Messages();
161 /// our function handler
164 BufferList buffer_list_;
166 boost::scoped_ptr<KeyMap> toplevel_keymap_;
168 boost::scoped_ptr<CmdDef> toplevel_cmddef_;
170 boost::scoped_ptr<Server> lyx_server_;
172 boost::scoped_ptr<ServerSocket> lyx_socket_;
174 boost::scoped_ptr<frontend::Application> application_;
175 /// lyx session, containing lastfiles, lastfilepos, and lastopened
176 boost::scoped_ptr<Session> session_;
178 /// Files to load at start.
179 vector<FileName> files_to_load_;
181 /// The messages translators.
182 map<string, Messages> messages_;
184 /// The file converters.
185 Converters converters_;
187 // The system converters copy after reading lyxrc.defaults.
188 Converters system_converters_;
194 Movers system_movers_;
198 frontend::Application * theApp()
201 return singleton_->pimpl_->application_.get();
215 BOOST_ASSERT(singleton_);
220 LyX const & LyX::cref()
222 BOOST_ASSERT(singleton_);
231 pimpl_ = new Singletons;
235 BufferList & LyX::bufferList()
237 return pimpl_->buffer_list_;
241 BufferList const & LyX::bufferList() const
243 return pimpl_->buffer_list_;
247 Session & LyX::session()
249 BOOST_ASSERT(pimpl_->session_.get());
250 return *pimpl_->session_.get();
254 Session const & LyX::session() const
256 BOOST_ASSERT(pimpl_->session_.get());
257 return *pimpl_->session_.get();
261 LyXFunc & LyX::lyxFunc()
263 return pimpl_->lyxfunc_;
267 LyXFunc const & LyX::lyxFunc() const
269 return pimpl_->lyxfunc_;
273 Server & LyX::server()
275 BOOST_ASSERT(pimpl_->lyx_server_.get());
276 return *pimpl_->lyx_server_.get();
280 Server const & LyX::server() const
282 BOOST_ASSERT(pimpl_->lyx_server_.get());
283 return *pimpl_->lyx_server_.get();
287 ServerSocket & LyX::socket()
289 BOOST_ASSERT(pimpl_->lyx_socket_.get());
290 return *pimpl_->lyx_socket_.get();
294 ServerSocket const & LyX::socket() const
296 BOOST_ASSERT(pimpl_->lyx_socket_.get());
297 return *pimpl_->lyx_socket_.get();
301 frontend::Application & LyX::application()
303 BOOST_ASSERT(pimpl_->application_.get());
304 return *pimpl_->application_.get();
308 frontend::Application const & LyX::application() const
310 BOOST_ASSERT(pimpl_->application_.get());
311 return *pimpl_->application_.get();
315 KeyMap & LyX::topLevelKeymap()
317 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
318 return *pimpl_->toplevel_keymap_.get();
322 CmdDef & LyX::topLevelCmdDef()
324 BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
325 return *pimpl_->toplevel_cmddef_.get();
329 Converters & LyX::converters()
331 return pimpl_->converters_;
335 Converters & LyX::systemConverters()
337 return pimpl_->system_converters_;
341 KeyMap const & LyX::topLevelKeymap() const
343 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
344 return *pimpl_->toplevel_keymap_.get();
348 Messages & LyX::getMessages(std::string const & language)
350 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
352 if (it != pimpl_->messages_.end())
355 std::pair<map<string, Messages>::iterator, bool> result =
356 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
358 BOOST_ASSERT(result.second);
359 return result.first->second;
363 Messages & LyX::getGuiMessages()
365 return pimpl_->messages_["GUI"];
369 void LyX::setGuiLanguage(std::string const & language)
371 pimpl_->messages_["GUI"] = Messages(language);
375 Buffer const * LyX::updateInset(Inset const * inset) const
377 if (quitting || !inset)
380 Buffer const * buffer_ptr = 0;
381 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
382 vector<int>::const_iterator it = view_ids.begin();
383 vector<int>::const_iterator const end = view_ids.end();
384 for (; it != end; ++it) {
386 pimpl_->application_->gui().view(*it).updateInset(inset);
394 void LyX::hideDialogs(std::string const & name, Inset * inset) const
396 if (quitting || !use_gui)
399 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
400 vector<int>::const_iterator it = view_ids.begin();
401 vector<int>::const_iterator const end = view_ids.end();
402 for (; it != end; ++it)
403 pimpl_->application_->gui().view(*it).getDialogs().
408 int LyX::exec(int & argc, char * argv[])
410 // Here we need to parse the command line. At least
411 // we need to parse for "-dbg" and "-help"
412 easyParse(argc, argv);
415 support::init_package(to_utf8(from_local8bit(argv[0])),
416 cl_system_support, cl_user_support,
417 support::top_build_dir_is_one_level_up);
418 } catch (support::ExceptionMessage const & message) {
419 if (message.type_ == support::ErrorException) {
420 Alert::error(message.title_, message.details_);
422 } else if (message.type_ == support::WarningException) {
423 Alert::warning(message.title_, message.details_);
427 // Reinit the messages machinery in case package() knows
428 // something interesting about the locale directory.
432 // FIXME: create a ConsoleApplication
433 int exit_status = init(argc, argv);
441 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
446 BufferList::iterator begin = pimpl_->buffer_list_.begin();
448 bool final_success = false;
449 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
451 if (buf != buf->masterBuffer())
453 bool success = false;
454 buf->dispatch(batch_command, &success);
455 final_success |= success;
458 return !final_success;
461 // Let the frontend parse and remove all arguments that it knows
462 pimpl_->application_.reset(createApplication(argc, argv));
466 // Parse and remove all known arguments in the LyX singleton
467 // Give an error for all remaining ones.
468 int exit_status = init(argc, argv);
470 // Kill the application object before exiting.
471 pimpl_->application_.reset();
478 /* Create a CoreApplication class that will provide the main event loop
479 * and the socket callback registering. With Qt4, only QtCore
480 * library would be needed.
481 * When this is done, a server_mode could be created and the following two
482 * line would be moved out from here.
484 // Note: socket callback must be registered after init(argc, argv)
485 // such that package().temp_dir() is properly initialized.
486 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
487 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
488 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
490 // Start the real execution loop.
491 exit_status = pimpl_->application_->exec();
499 void LyX::prepareExit()
501 // Clear the clipboard and selection stack:
502 cap::clearCutStack();
503 cap::clearSelection();
505 // Set a flag that we do quitting from the program,
506 // so no refreshes are necessary.
509 // close buffers first
510 pimpl_->buffer_list_.closeAll();
512 // do any other cleanup procedures now
513 if (package().temp_dir() != package().system_temp_dir()) {
514 LYXERR(Debug::INFO) << "Deleting tmp dir "
515 << package().temp_dir().absFilename() << endl;
517 if (!package().temp_dir().destroyDirectory()) {
518 docstring const msg =
519 bformat(_("Unable to remove the temporary directory %1$s"),
520 from_utf8(package().temp_dir().absFilename()));
521 Alert::warning(_("Unable to remove temporary directory"), msg);
526 if (pimpl_->session_)
527 pimpl_->session_->writeFile();
528 pimpl_->session_.reset();
529 pimpl_->lyx_server_.reset();
530 pimpl_->lyx_socket_.reset();
533 // Kill the application object before exiting. This avoids crashes
534 // when exiting on Linux.
535 if (pimpl_->application_)
536 pimpl_->application_.reset();
540 void LyX::earlyExit(int status)
542 BOOST_ASSERT(pimpl_->application_.get());
543 // LyX::pimpl_::application_ is not initialised at this
544 // point so it's safe to just exit after some cleanup.
550 int LyX::init(int & argc, char * argv[])
552 // check for any spurious extra arguments
553 // other than documents
554 for (int argi = 1; argi < argc ; ++argi) {
555 if (argv[argi][0] == '-') {
557 bformat(_("Wrong command line option `%1$s'. Exiting."),
558 from_utf8(argv[argi]))) << endl;
563 // Initialization of LyX (reads lyxrc and more)
564 LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
565 bool success = init();
566 LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
570 for (int argi = argc - 1; argi >= 1; --argi) {
571 // get absolute path of file and add ".lyx" to
572 // the filename if necessary
573 pimpl_->files_to_load_.push_back(fileSearch(string(),
574 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
575 "lyx", support::allow_unreadable));
579 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
585 void LyX::addFileToLoad(FileName const & fname)
587 vector<FileName>::const_iterator cit = std::find(
588 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
591 if (cit == pimpl_->files_to_load_.end())
592 pimpl_->files_to_load_.push_back(fname);
596 void LyX::loadFiles()
598 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
599 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
601 for (; it != end; ++it) {
605 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
606 if (buf->loadLyXFile(*it)) {
607 ErrorList const & el = buf->errorList("Parse");
609 for_each(el.begin(), el.end(),
610 boost::bind(&LyX::printError, this, _1));
613 pimpl_->buffer_list_.release(buf);
618 void LyX::execBatchCommands()
620 // The advantage of doing this here is that the event loop
621 // is already started. So any need for interaction will be
625 // if reconfiguration is needed.
626 if (textclasslist.empty()) {
627 switch (Alert::prompt(
628 _("No textclass is found"),
629 _("LyX cannot continue because no textclass is found. "
630 "You can either reconfigure normally, or reconfigure using "
631 "default textclasses, or quit LyX."),
638 // regular reconfigure
639 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
642 // reconfigure --without-latex-config
643 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
644 " --without-latex-config"));
647 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
651 // Execute batch commands if available
652 if (batch_command.empty())
655 LYXERR(Debug::INIT) << "About to handle -x '"
656 << batch_command << '\'' << endl;
658 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
662 void LyX::restoreGuiSession()
664 LyXView * view = newLyXView();
666 // if there is no valid class list, do not load any file.
667 if (textclasslist.empty())
670 // if some files were specified at command-line we assume that the
671 // user wants to edit *these* files and not to restore the session.
672 if (!pimpl_->files_to_load_.empty()) {
673 for_each(pimpl_->files_to_load_.begin(),
674 pimpl_->files_to_load_.end(),
675 bind(&LyXView::loadLyXFile, view, _1, true));
676 // clear this list to save a few bytes of RAM
677 pimpl_->files_to_load_.clear();
678 pimpl_->session_->lastOpened().clear();
680 } else if (lyxrc.load_session) {
681 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
682 // do not add to the lastfile list since these files are restored from
683 // last session, and should be already there (regular files), or should
684 // not be added at all (help files).
685 for_each(lastopened.begin(), lastopened.end(),
686 bind(&LyXView::loadLyXFile, view, _1, false));
688 // clear this list to save a few bytes of RAM
689 pimpl_->session_->lastOpened().clear();
692 BufferList::iterator I = pimpl_->buffer_list_.begin();
693 BufferList::iterator end = pimpl_->buffer_list_.end();
694 for (; I != end; ++I) {
696 if (buf != buf->masterBuffer())
701 // FIXME: Switch to the last loaded Buffer. This must not be the first one
702 // because the Buffer won't be connected in this case. The correct solution
703 // would be to avoid the manual connection of the current Buffer in LyXView.
704 if (!pimpl_->buffer_list_.empty())
705 view->setBuffer(pimpl_->buffer_list_.last());
709 LyXView * LyX::newLyXView()
714 // FIXME: transfer all this geometry stuff to the frontend.
716 // determine windows size and position, from lyxrc and/or session
718 unsigned int width = 690;
719 unsigned int height = 510;
720 // default icon size, will be overwritten by stored session value
721 unsigned int iconSizeXY = 0;
722 // FIXME: 0 means GuiView::NotMaximized by default!
725 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
726 width = lyxrc.geometry_width;
727 height = lyxrc.geometry_height;
729 // if lyxrc returns (0,0), then use session info
731 string val = session().sessionInfo().load("WindowWidth");
733 width = convert<unsigned int>(val);
734 val = session().sessionInfo().load("WindowHeight");
736 height = convert<unsigned int>(val);
737 val = session().sessionInfo().load("WindowMaximized");
739 maximized = convert<int>(val);
740 val = session().sessionInfo().load("IconSizeXY");
742 iconSizeXY = convert<unsigned int>(val);
745 // if user wants to restore window position
748 if (lyxrc.geometry_xysaved) {
749 string val = session().sessionInfo().load("WindowPosX");
751 posx = convert<int>(val);
752 val = session().sessionInfo().load("WindowPosY");
754 posy = convert<int>(val);
757 if (!geometryArg.empty())
763 // create the main window
764 LyXView * view = &pimpl_->application_->createView(width, height,
765 posx, posy, maximized, iconSizeXY, geometryArg);
773 The SIGHUP signal does not exist on Windows and does not need to be handled.
775 Windows handles SIGFPE and SIGSEGV signals as expected.
777 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
778 cause a new thread to be spawned. This may well result in unexpected
779 behaviour by the single-threaded LyX.
781 SIGTERM signals will come only from another process actually sending
782 that signal using 'raise' in Windows' POSIX compatability layer. It will
783 not come from the general "terminate process" methods that everyone
784 actually uses (and which can't be trapped). Killing an app 'politely' on
785 Windows involves first sending a WM_CLOSE message, something that is
786 caught already by the Qt frontend.
788 For more information see:
790 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
791 ...signals are mostly useless on Windows for a variety of reasons that are
794 'UNIX Application Migration Guide, Chapter 9'
795 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
797 'How To Terminate an Application "Cleanly" in Win32'
798 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
802 static void error_handler(int err_sig)
804 // Throw away any signals other than the first one received.
805 static sig_atomic_t handling_error = false;
808 handling_error = true;
810 // We have received a signal indicating a fatal error, so
811 // try and save the data ASAP.
812 LyX::cref().emergencyCleanup();
814 // These lyxerr calls may or may not work:
816 // Signals are asynchronous, so the main program may be in a very
817 // fragile state when a signal is processed and thus while a signal
818 // handler function executes.
819 // In general, therefore, we should avoid performing any
820 // I/O operations or calling most library and system functions from
823 // This shouldn't matter here, however, as we've already invoked
828 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
832 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
835 lyxerr << "\nlyx: SIGSEGV signal caught\n"
836 "Sorry, you have found a bug in LyX. "
837 "Please read the bug-reporting instructions "
838 "in Help->Introduction and send us a bug report, "
839 "if necessary. Thanks !\nBye." << endl;
847 // Deinstall the signal handlers
849 signal(SIGHUP, SIG_DFL);
851 signal(SIGINT, SIG_DFL);
852 signal(SIGFPE, SIG_DFL);
853 signal(SIGSEGV, SIG_DFL);
854 signal(SIGTERM, SIG_DFL);
857 if (err_sig == SIGSEGV ||
858 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
860 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
869 void LyX::printError(ErrorItem const & ei)
871 docstring tmp = _("LyX: ") + ei.error + char_type(':')
873 std::cerr << to_utf8(tmp) << std::endl;
877 void LyX::initGuiFont()
879 if (lyxrc.roman_font_name.empty())
880 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
882 if (lyxrc.sans_font_name.empty())
883 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
885 if (lyxrc.typewriter_font_name.empty())
886 lyxrc.typewriter_font_name
887 = pimpl_->application_->typewriterFontName();
894 signal(SIGHUP, error_handler);
896 signal(SIGFPE, error_handler);
897 signal(SIGSEGV, error_handler);
898 signal(SIGINT, error_handler);
899 signal(SIGTERM, error_handler);
900 // SIGPIPE can be safely ignored.
902 lyxrc.tempdir_path = package().temp_dir().absFilename();
903 lyxrc.document_path = package().document_dir().absFilename();
905 if (lyxrc.template_path.empty()) {
906 lyxrc.template_path = addPath(package().system_support().absFilename(),
911 // Read configuration files
914 // This one may have been distributed along with LyX.
915 if (!readRcFile("lyxrc.dist"))
918 // Set the language defined by the distributor.
919 //setGuiLanguage(lyxrc.gui_language);
921 // Set the PATH correctly.
922 #if !defined (USE_POSIX_PACKAGING)
923 // Add the directory containing the LyX executable to the path
924 // so that LyX can find things like tex2lyx.
925 if (package().build_support().empty())
926 prependEnvPath("PATH", package().binary_dir().absFilename());
928 if (!lyxrc.path_prefix.empty())
929 prependEnvPath("PATH", lyxrc.path_prefix);
931 // Check that user LyX directory is ok.
932 if (queryUserLyXDir(package().explicit_user_support()))
933 reconfigureUserLyXDir();
935 // no need for a splash when there is no GUI
940 // This one is generated in user_support directory by lib/configure.py.
941 if (!readRcFile("lyxrc.defaults"))
944 // Query the OS to know what formats are viewed natively
945 formats.setAutoOpen();
947 // Read lyxrc.dist again to be able to override viewer auto-detection.
948 readRcFile("lyxrc.dist");
950 system_lyxrc = lyxrc;
951 system_formats = formats;
952 pimpl_->system_converters_ = pimpl_->converters_;
953 pimpl_->system_movers_ = pimpl_->movers_;
954 system_lcolor = lcolor;
956 // This one is edited through the preferences dialog.
957 if (!readRcFile("preferences"))
960 if (!readEncodingsFile("encodings", "unicodesymbols"))
962 if (!readLanguagesFile("languages"))
966 LYXERR(Debug::INIT) << "Reading layouts..." << endl;
972 // read keymap and ui files in batch mode as well
973 // because InsetInfo needs to know these to produce
974 // the correct output
976 // Set the language defined by the user.
977 //setGuiLanguage(lyxrc.gui_language);
979 // Set up command definitions
980 pimpl_->toplevel_cmddef_.reset(new CmdDef);
981 pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
984 pimpl_->toplevel_keymap_.reset(new KeyMap);
985 pimpl_->toplevel_keymap_->read("site");
986 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
987 // load user bind file user.bind
988 pimpl_->toplevel_keymap_->read("user");
990 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
993 if (!readUIFile(lyxrc.ui_file))
996 if (lyxerr.debugging(Debug::LYXRC))
999 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
1000 if (!lyxrc.path_prefix.empty())
1001 prependEnvPath("PATH", lyxrc.path_prefix);
1003 FileName const document_path(lyxrc.document_path);
1004 if (document_path.exists() && document_path.isDirectory())
1005 package().document_dir() = document_path;
1007 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
1008 if (package().temp_dir().empty()) {
1009 Alert::error(_("Could not create temporary directory"),
1010 bformat(_("Could not create a temporary directory in\n"
1011 "%1$s. Make sure that this\n"
1012 "path exists and is writable and try again."),
1013 from_utf8(lyxrc.tempdir_path)));
1014 // createLyXTmpDir() tries sufficiently hard to create a
1015 // usable temp dir, so the probability to come here is
1016 // close to zero. We therefore don't try to overcome this
1017 // problem with e.g. asking the user for a new path and
1018 // trying again but simply exit.
1022 LYXERR(Debug::INIT) << "LyX tmp dir: `"
1023 << package().temp_dir().absFilename()
1026 LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
1027 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
1029 // This must happen after package initialization and after lyxrc is
1030 // read, therefore it can't be done by a static object.
1031 ConverterCache::init();
1037 void LyX::emergencyCleanup() const
1039 // what to do about tmpfiles is non-obvious. we would
1040 // like to delete any we find, but our lyxdir might
1041 // contain documents etc. which might be helpful on
1044 pimpl_->buffer_list_.emergencyWriteAll();
1046 if (pimpl_->lyx_server_)
1047 pimpl_->lyx_server_->emergencyCleanup();
1048 pimpl_->lyx_server_.reset();
1049 pimpl_->lyx_socket_.reset();
1054 void LyX::deadKeyBindings(KeyMap * kbmap)
1056 // bindKeyings for transparent handling of deadkeys
1057 // The keysyms are gotten from XFree86 X11R6
1058 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1059 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1060 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1061 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1062 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1063 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1064 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1065 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1066 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1067 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1068 // nothing with this name
1069 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1070 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1071 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1072 // nothing with this name either...
1073 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1074 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1075 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1076 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1080 // return true if file does not exist or is older than configure.py.
1081 static bool needsUpdate(string const & file)
1083 // We cannot initialize configure_script directly because the package
1084 // is not initialized yet when static objects are constructed.
1085 static FileName configure_script;
1086 static bool firstrun = true;
1089 FileName(addName(package().system_support().absFilename(),
1095 FileName(addName(package().user_support().absFilename(), file));
1096 return !absfile.exists()
1097 || configure_script.lastModified() > absfile.lastModified();
1101 bool LyX::queryUserLyXDir(bool explicit_userdir)
1103 // Does user directory exist?
1104 FileName const sup = package().user_support();
1105 if (sup.exists() && sup.isDirectory()) {
1106 first_start = false;
1108 return needsUpdate("lyxrc.defaults")
1109 || needsUpdate("lyxmodules.lst")
1110 || needsUpdate("textclass.lst")
1111 || needsUpdate("packages.lst");
1114 first_start = !explicit_userdir;
1116 // If the user specified explicitly a directory, ask whether
1117 // to create it. If the user says "no", then exit.
1118 if (explicit_userdir &&
1120 _("Missing user LyX directory"),
1121 bformat(_("You have specified a non-existent user "
1122 "LyX directory, %1$s.\n"
1123 "It is needed to keep your own configuration."),
1124 from_utf8(package().user_support().absFilename())),
1126 _("&Create directory"),
1128 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1129 earlyExit(EXIT_FAILURE);
1132 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1133 from_utf8(sup.absFilename()))) << endl;
1135 if (!sup.createDirectory(0755)) {
1136 // Failed, so let's exit.
1137 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1139 earlyExit(EXIT_FAILURE);
1146 bool LyX::readRcFile(string const & name)
1148 LYXERR(Debug::INIT) << "About to read " << name << "... ";
1150 FileName const lyxrc_path = libFileSearch(string(), name);
1151 if (!lyxrc_path.empty()) {
1153 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1155 if (lyxrc.read(lyxrc_path) < 0) {
1156 showFileError(name);
1160 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1166 // Read the ui file `name'
1167 bool LyX::readUIFile(string const & name, bool include)
1177 struct keyword_item uitags[ui_last - 1] = {
1178 { "include", ui_include },
1179 { "menuset", ui_menuset },
1180 { "toolbars", ui_toolbars },
1181 { "toolbarset", ui_toolbarset }
1184 // Ensure that a file is read only once (prevents include loops)
1185 static std::list<string> uifiles;
1186 std::list<string>::const_iterator it = uifiles.begin();
1187 std::list<string>::const_iterator end = uifiles.end();
1188 it = std::find(it, end, name);
1190 LYXERR(Debug::INIT) << "UI file '" << name
1191 << "' has been read already. "
1192 << "Is this an include loop?"
1197 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1202 ui_path = libFileSearch("ui", name, "inc");
1203 if (ui_path.empty())
1204 ui_path = libFileSearch("ui",
1205 changeExtension(name, "inc"));
1208 ui_path = libFileSearch("ui", name, "ui");
1210 if (ui_path.empty()) {
1211 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1212 showFileError(name);
1216 uifiles.push_back(name);
1218 LYXERR(Debug::INIT) << "Found " << name
1219 << " in " << ui_path << endl;
1220 Lexer lex(uitags, ui_last - 1);
1221 lex.setFile(ui_path);
1223 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1227 if (lyxerr.debugging(Debug::PARSER))
1228 lex.printTable(lyxerr);
1230 while (lex.isOK()) {
1231 switch (lex.lex()) {
1234 string const file = lex.getString();
1235 if (!readUIFile(file, true))
1240 menubackend.read(lex);
1244 toolbarbackend.readToolbars(lex);
1248 toolbarbackend.readToolbarSettings(lex);
1252 if (!rtrim(lex.getString()).empty())
1253 lex.printError("LyX::ReadUIFile: "
1254 "Unknown menu tag: `$$Token'");
1262 // Read the languages file `name'
1263 bool LyX::readLanguagesFile(string const & name)
1265 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1267 FileName const lang_path = libFileSearch(string(), name);
1268 if (lang_path.empty()) {
1269 showFileError(name);
1272 languages.read(lang_path);
1277 // Read the encodings file `name'
1278 bool LyX::readEncodingsFile(string const & enc_name,
1279 string const & symbols_name)
1281 LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1282 << symbols_name << "..." << endl;
1284 FileName const symbols_path = libFileSearch(string(), symbols_name);
1285 if (symbols_path.empty()) {
1286 showFileError(symbols_name);
1290 FileName const enc_path = libFileSearch(string(), enc_name);
1291 if (enc_path.empty()) {
1292 showFileError(enc_name);
1295 encodings.read(enc_path, symbols_path);
1304 /// return the the number of arguments consumed
1305 typedef boost::function<int(string const &, string const &)> cmd_helper;
1307 int parse_dbg(string const & arg, string const &)
1310 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1311 Debug::showTags(lyxerr);
1314 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1316 lyxerr.level(Debug::value(arg));
1317 Debug::showLevel(lyxerr, lyxerr.level());
1322 int parse_help(string const &, string const &)
1325 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1326 "Command line switches (case sensitive):\n"
1327 "\t-help summarize LyX usage\n"
1328 "\t-userdir dir set user directory to dir\n"
1329 "\t-sysdir dir set system directory to dir\n"
1330 "\t-geometry WxH+X+Y set geometry of the main window\n"
1331 "\t-dbg feature[,feature]...\n"
1332 " select the features to debug.\n"
1333 " Type `lyx -dbg' to see the list of features\n"
1334 "\t-x [--execute] command\n"
1335 " where command is a lyx command.\n"
1336 "\t-e [--export] fmt\n"
1337 " where fmt is the export format of choice.\n"
1338 "\t-i [--import] fmt file.xxx\n"
1339 " where fmt is the import format of choice\n"
1340 " and file.xxx is the file to be imported.\n"
1341 "\t-version summarize version and build info\n"
1342 "Check the LyX man page for more details.")) << endl;
1348 int parse_version(string const &, string const &)
1350 lyxerr << "LyX " << lyx_version
1351 << " (" << lyx_release_date << ")" << endl;
1352 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1354 lyxerr << lyx_version_info << endl;
1360 int parse_sysdir(string const & arg, string const &)
1363 Alert::error(_("No system directory"),
1364 _("Missing directory for -sysdir switch"));
1367 cl_system_support = arg;
1372 int parse_userdir(string const & arg, string const &)
1375 Alert::error(_("No user directory"),
1376 _("Missing directory for -userdir switch"));
1379 cl_user_support = arg;
1384 int parse_execute(string const & arg, string const &)
1387 Alert::error(_("Incomplete command"),
1388 _("Missing command string after --execute switch"));
1396 int parse_export(string const & type, string const &)
1399 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1400 "--export switch")) << endl;
1403 batch = "buffer-export " + type;
1409 int parse_import(string const & type, string const & file)
1412 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1413 "--import switch")) << endl;
1417 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1421 batch = "buffer-import " + type + ' ' + file;
1426 int parse_geometry(string const & arg1, string const &)
1429 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1430 // remove also the arg
1433 // don't remove "-geometry"
1442 void LyX::easyParse(int & argc, char * argv[])
1444 std::map<string, cmd_helper> cmdmap;
1446 cmdmap["-dbg"] = parse_dbg;
1447 cmdmap["-help"] = parse_help;
1448 cmdmap["--help"] = parse_help;
1449 cmdmap["-version"] = parse_version;
1450 cmdmap["--version"] = parse_version;
1451 cmdmap["-sysdir"] = parse_sysdir;
1452 cmdmap["-userdir"] = parse_userdir;
1453 cmdmap["-x"] = parse_execute;
1454 cmdmap["--execute"] = parse_execute;
1455 cmdmap["-e"] = parse_export;
1456 cmdmap["--export"] = parse_export;
1457 cmdmap["-i"] = parse_import;
1458 cmdmap["--import"] = parse_import;
1459 cmdmap["-geometry"] = parse_geometry;
1461 for (int i = 1; i < argc; ++i) {
1462 std::map<string, cmd_helper>::const_iterator it
1463 = cmdmap.find(argv[i]);
1465 // don't complain if not found - may be parsed later
1466 if (it == cmdmap.end())
1470 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1472 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1474 int const remove = 1 + it->second(arg, arg2);
1476 // Now, remove used arguments by shifting
1477 // the following ones remove places down.
1480 for (int j = i; j < argc; ++j)
1481 argv[j] = argv[j + remove];
1486 batch_command = batch;
1490 FuncStatus getStatus(FuncRequest const & action)
1492 return LyX::ref().lyxFunc().getStatus(action);
1496 void dispatch(FuncRequest const & action)
1498 LyX::ref().lyxFunc().dispatch(action);
1502 BufferList & theBufferList()
1504 return LyX::ref().bufferList();
1508 LyXFunc & theLyXFunc()
1510 return LyX::ref().lyxFunc();
1514 Server & theServer()
1516 // FIXME: this should not be use_gui dependent
1517 BOOST_ASSERT(use_gui);
1518 return LyX::ref().server();
1522 ServerSocket & theServerSocket()
1524 // FIXME: this should not be use_gui dependent
1525 BOOST_ASSERT(use_gui);
1526 return LyX::ref().socket();
1530 KeyMap & theTopLevelKeymap()
1532 return LyX::ref().topLevelKeymap();
1536 Converters & theConverters()
1538 return LyX::ref().converters();
1542 Converters & theSystemConverters()
1544 return LyX::ref().systemConverters();
1548 Movers & theMovers()
1550 return LyX::ref().pimpl_->movers_;
1554 Mover const & getMover(std::string const & fmt)
1556 return LyX::ref().pimpl_->movers_(fmt);
1560 void setMover(std::string const & fmt, std::string const & command)
1562 LyX::ref().pimpl_->movers_.set(fmt, command);
1566 Movers & theSystemMovers()
1568 return LyX::ref().pimpl_->system_movers_;
1572 Messages & getMessages(std::string const & language)
1574 return LyX::ref().getMessages(language);
1578 Messages & getGuiMessages()
1580 return LyX::ref().getGuiMessages();