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.
20 #include "LayoutFile.h"
22 #include "BufferList.h"
25 #include "ConverterCache.h"
26 #include "Converter.h"
27 #include "CutAndPaste.h"
29 #include "ErrorList.h"
31 #include "FuncStatus.h"
35 #include "LyXAction.h"
38 #include "ModuleList.h"
41 #include "ServerSocket.h"
43 #include "ToolbarBackend.h"
45 #include "frontends/alert.h"
46 #include "frontends/Application.h"
48 #include "support/debug.h"
49 #include "support/environment.h"
50 #include "support/ExceptionMessage.h"
51 #include "support/filetools.h"
52 #include "support/gettext.h"
53 #include "support/lstrings.h"
54 #include "support/Messages.h"
55 #include "support/os.h"
56 #include "support/Package.h"
57 #include "support/Path.h"
58 #include "support/Systemcall.h"
60 #include <boost/bind.hpp>
61 #include <boost/scoped_ptr.hpp>
72 using namespace lyx::support;
76 namespace Alert = frontend::Alert;
77 namespace os = support::os;
81 // Are we using the GUI at all? We default to true and this is changed
82 // to false when the export feature is used.
88 // Filled with the command line arguments "foo" of "-sysdir foo" or
90 string cl_system_support;
91 string cl_user_support;
97 void showFileError(string const & error)
99 Alert::warning(_("Could not read configuration file"),
100 bformat(_("Error while reading the configuration file\n%1$s.\n"
101 "Please check your installation."), from_utf8(error)));
105 void reconfigureUserLyXDir()
107 string const configure_command = package().configure_command();
109 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
110 PathChanger p(package().user_support());
112 one.startscript(Systemcall::Wait, configure_command);
113 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
119 /// The main application class private implementation.
124 // Set the default User Interface language as soon as possible.
125 // The language used will be derived from the environment
127 messages_["GUI"] = Messages();
129 /// our function handler
132 BufferList buffer_list_;
134 KeyMap toplevel_keymap_;
136 CmdDef toplevel_cmddef_;
138 boost::scoped_ptr<Server> lyx_server_;
140 boost::scoped_ptr<ServerSocket> lyx_socket_;
142 boost::scoped_ptr<frontend::Application> application_;
143 /// lyx session, containing lastfiles, lastfilepos, and lastopened
144 boost::scoped_ptr<Session> session_;
146 /// Files to load at start.
147 vector<string> files_to_load_;
149 /// The messages translators.
150 map<string, Messages> messages_;
152 /// The file converters.
153 Converters converters_;
155 // The system converters copy after reading lyxrc.defaults.
156 Converters system_converters_;
161 Movers system_movers_;
163 /// has this user started lyx for the first time?
165 /// the parsed command line batch command if any
166 string batch_command;
170 frontend::Application * theApp()
173 return singleton_->pimpl_->application_.get();
185 void LyX::exit(int exit_code) const
188 // Something wrong happened so better save everything, just in
193 // Properly crash in debug mode in order to get a useful backtrace.
197 // In release mode, try to exit gracefully.
199 theApp()->exit(exit_code);
207 BOOST_ASSERT(singleton_);
212 LyX const & LyX::cref()
214 BOOST_ASSERT(singleton_);
227 BufferList & LyX::bufferList()
229 return pimpl_->buffer_list_;
233 BufferList const & LyX::bufferList() const
235 return pimpl_->buffer_list_;
239 Session & LyX::session()
241 BOOST_ASSERT(pimpl_->session_.get());
242 return *pimpl_->session_.get();
246 Session const & LyX::session() const
248 BOOST_ASSERT(pimpl_->session_.get());
249 return *pimpl_->session_.get();
253 LyXFunc & LyX::lyxFunc()
255 return pimpl_->lyxfunc_;
259 LyXFunc const & LyX::lyxFunc() const
261 return pimpl_->lyxfunc_;
265 Server & LyX::server()
267 BOOST_ASSERT(pimpl_->lyx_server_.get());
268 return *pimpl_->lyx_server_.get();
272 Server const & LyX::server() const
274 BOOST_ASSERT(pimpl_->lyx_server_.get());
275 return *pimpl_->lyx_server_.get();
279 ServerSocket & LyX::socket()
281 BOOST_ASSERT(pimpl_->lyx_socket_.get());
282 return *pimpl_->lyx_socket_.get();
286 ServerSocket const & LyX::socket() const
288 BOOST_ASSERT(pimpl_->lyx_socket_.get());
289 return *pimpl_->lyx_socket_.get();
293 frontend::Application & LyX::application()
295 BOOST_ASSERT(pimpl_->application_.get());
296 return *pimpl_->application_.get();
300 frontend::Application const & LyX::application() const
302 BOOST_ASSERT(pimpl_->application_.get());
303 return *pimpl_->application_.get();
307 CmdDef & LyX::topLevelCmdDef()
309 return pimpl_->toplevel_cmddef_;
313 Converters & LyX::converters()
315 return pimpl_->converters_;
319 Converters & LyX::systemConverters()
321 return pimpl_->system_converters_;
325 Messages & LyX::getMessages(string const & language)
327 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
329 if (it != pimpl_->messages_.end())
332 pair<map<string, Messages>::iterator, bool> result =
333 pimpl_->messages_.insert(make_pair(language, Messages(language)));
335 BOOST_ASSERT(result.second);
336 return result.first->second;
340 Messages & LyX::getGuiMessages()
342 return pimpl_->messages_["GUI"];
346 void LyX::setGuiLanguage(string const & language)
348 pimpl_->messages_["GUI"] = Messages(language);
352 int LyX::exec(int & argc, char * argv[])
354 // Here we need to parse the command line. At least
355 // we need to parse for "-dbg" and "-help"
356 easyParse(argc, argv);
359 init_package(to_utf8(from_local8bit(argv[0])),
360 cl_system_support, cl_user_support,
361 top_build_dir_is_one_level_up);
362 } catch (ExceptionMessage const & message) {
363 if (message.type_ == ErrorException) {
364 Alert::error(message.title_, message.details_);
366 } else if (message.type_ == WarningException) {
367 Alert::warning(message.title_, message.details_);
371 // Reinit the messages machinery in case package() knows
372 // something interesting about the locale directory.
376 // FIXME: create a ConsoleApplication
377 int exit_status = init(argc, argv);
385 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
390 BufferList::iterator begin = pimpl_->buffer_list_.begin();
392 bool final_success = false;
393 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
395 if (buf != buf->masterBuffer())
397 bool success = false;
398 buf->dispatch(pimpl_->batch_command, &success);
399 final_success |= success;
402 return !final_success;
405 // Let the frontend parse and remove all arguments that it knows
406 pimpl_->application_.reset(createApplication(argc, argv));
408 // Parse and remove all known arguments in the LyX singleton
409 // Give an error for all remaining ones.
410 int exit_status = init(argc, argv);
412 // Kill the application object before exiting.
413 pimpl_->application_.reset();
420 /* Create a CoreApplication class that will provide the main event loop
421 * and the socket callback registering. With Qt4, only QtCore
422 * library would be needed.
423 * When this is done, a server_mode could be created and the following two
424 * line would be moved out from here.
426 // Note: socket callback must be registered after init(argc, argv)
427 // such that package().temp_dir() is properly initialized.
428 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
429 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
430 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
432 // Start the real execution loop.
433 exit_status = pimpl_->application_->exec();
441 void LyX::prepareExit()
443 // Clear the clipboard and selection stack:
444 cap::clearCutStack();
445 cap::clearSelection();
447 // close buffers first
448 pimpl_->buffer_list_.closeAll();
450 // register session changes and shutdown server and socket
452 if (pimpl_->session_)
453 pimpl_->session_->writeFile();
454 pimpl_->session_.reset();
455 pimpl_->lyx_server_.reset();
456 pimpl_->lyx_socket_.reset();
459 // do any other cleanup procedures now
460 if (package().temp_dir() != package().system_temp_dir()) {
461 LYXERR(Debug::INFO, "Deleting tmp dir "
462 << package().temp_dir().absFilename());
464 if (!package().temp_dir().destroyDirectory()) {
465 docstring const msg =
466 bformat(_("Unable to remove the temporary directory %1$s"),
467 from_utf8(package().temp_dir().absFilename()));
468 Alert::warning(_("Unable to remove temporary directory"), msg);
472 // Kill the application object before exiting. This avoids crashes
473 // when exiting on Linux.
474 if (pimpl_->application_)
475 pimpl_->application_.reset();
479 void LyX::earlyExit(int status)
481 BOOST_ASSERT(pimpl_->application_.get());
482 // LyX::pimpl_::application_ is not initialised at this
483 // point so it's safe to just exit after some cleanup.
489 int LyX::init(int & argc, char * argv[])
491 // check for any spurious extra arguments
492 // other than documents
493 for (int argi = 1; argi < argc ; ++argi) {
494 if (argv[argi][0] == '-') {
496 bformat(_("Wrong command line option `%1$s'. Exiting."),
497 from_utf8(argv[argi]))) << endl;
502 // Initialization of LyX (reads lyxrc and more)
503 LYXERR(Debug::INIT, "Initializing LyX::init...");
504 bool success = init();
505 LYXERR(Debug::INIT, "Initializing LyX::init...done");
509 // Remaining arguments are assumed to be files to load.
510 for (int argi = argc - 1; argi >= 1; --argi)
511 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
514 pimpl_->files_to_load_.push_back(
515 i18nLibFileSearch("examples", "splash.lyx").absFilename());
522 void LyX::addFileToLoad(string const & fname)
524 vector<string>::const_iterator cit = find(
525 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
528 if (cit == pimpl_->files_to_load_.end())
529 pimpl_->files_to_load_.push_back(fname);
533 void LyX::loadFiles()
535 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
536 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
538 for (; it != end; ++it) {
539 // get absolute path of file and add ".lyx" to
540 // the filename if necessary
541 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
547 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
548 if (buf->loadLyXFile(fname)) {
549 ErrorList const & el = buf->errorList("Parse");
551 for_each(el.begin(), el.end(),
552 boost::bind(&LyX::printError, this, _1));
555 pimpl_->buffer_list_.release(buf);
560 void LyX::execBatchCommands()
562 // The advantage of doing this here is that the event loop
563 // is already started. So any need for interaction will be
566 // if reconfiguration is needed.
567 while (LayoutFileList::get().empty()) {
568 switch (Alert::prompt(
569 _("No textclass is found"),
570 _("LyX cannot continue because no textclass is found. "
571 "You can either reconfigure normally, or reconfigure using "
572 "default textclasses, or quit LyX."),
579 // regular reconfigure
580 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
583 // reconfigure --without-latex-config
584 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
585 " --without-latex-config"));
588 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
593 // create the first main window
594 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
596 if (!pimpl_->files_to_load_.empty()) {
597 // if some files were specified at command-line we assume that the
598 // user wants to edit *these* files and not to restore the session.
599 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
600 pimpl_->lyxfunc_.dispatch(
601 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
603 // clear this list to save a few bytes of RAM
604 pimpl_->files_to_load_.clear();
607 pimpl_->application_->restoreGuiSession();
609 // Execute batch commands if available
610 if (pimpl_->batch_command.empty())
613 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
615 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
622 The SIGHUP signal does not exist on Windows and does not need to be handled.
624 Windows handles SIGFPE and SIGSEGV signals as expected.
626 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
627 cause a new thread to be spawned. This may well result in unexpected
628 behaviour by the single-threaded LyX.
630 SIGTERM signals will come only from another process actually sending
631 that signal using 'raise' in Windows' POSIX compatability layer. It will
632 not come from the general "terminate process" methods that everyone
633 actually uses (and which can't be trapped). Killing an app 'politely' on
634 Windows involves first sending a WM_CLOSE message, something that is
635 caught already by the Qt frontend.
637 For more information see:
639 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
640 ...signals are mostly useless on Windows for a variety of reasons that are
643 'UNIX Application Migration Guide, Chapter 9'
644 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
646 'How To Terminate an Application "Cleanly" in Win32'
647 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
651 static void error_handler(int err_sig)
653 // Throw away any signals other than the first one received.
654 static sig_atomic_t handling_error = false;
657 handling_error = true;
659 // We have received a signal indicating a fatal error, so
660 // try and save the data ASAP.
661 LyX::cref().emergencyCleanup();
663 // These lyxerr calls may or may not work:
665 // Signals are asynchronous, so the main program may be in a very
666 // fragile state when a signal is processed and thus while a signal
667 // handler function executes.
668 // In general, therefore, we should avoid performing any
669 // I/O operations or calling most library and system functions from
672 // This shouldn't matter here, however, as we've already invoked
677 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
681 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
684 lyxerr << "\nlyx: SIGSEGV signal caught\n"
685 "Sorry, you have found a bug in LyX. "
686 "Please read the bug-reporting instructions "
687 "in Help->Introduction and send us a bug report, "
688 "if necessary. Thanks !\nBye." << endl;
696 // Deinstall the signal handlers
698 signal(SIGHUP, SIG_DFL);
700 signal(SIGINT, SIG_DFL);
701 signal(SIGFPE, SIG_DFL);
702 signal(SIGSEGV, SIG_DFL);
703 signal(SIGTERM, SIG_DFL);
706 if (err_sig == SIGSEGV ||
707 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
709 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
718 void LyX::printError(ErrorItem const & ei)
720 docstring tmp = _("LyX: ") + ei.error + char_type(':')
722 cerr << to_utf8(tmp) << endl;
729 signal(SIGHUP, error_handler);
731 signal(SIGFPE, error_handler);
732 signal(SIGSEGV, error_handler);
733 signal(SIGINT, error_handler);
734 signal(SIGTERM, error_handler);
735 // SIGPIPE can be safely ignored.
737 lyxrc.tempdir_path = package().temp_dir().absFilename();
738 lyxrc.document_path = package().document_dir().absFilename();
740 if (lyxrc.example_path.empty()) {
741 lyxrc.example_path = addPath(package().system_support().absFilename(),
744 if (lyxrc.template_path.empty()) {
745 lyxrc.template_path = addPath(package().system_support().absFilename(),
750 // Read configuration files
753 // This one may have been distributed along with LyX.
754 if (!readRcFile("lyxrc.dist"))
757 // Set the language defined by the distributor.
758 //setGuiLanguage(lyxrc.gui_language);
760 // Set the PATH correctly.
761 #if !defined (USE_POSIX_PACKAGING)
762 // Add the directory containing the LyX executable to the path
763 // so that LyX can find things like tex2lyx.
764 if (package().build_support().empty())
765 prependEnvPath("PATH", package().binary_dir().absFilename());
767 if (!lyxrc.path_prefix.empty())
768 prependEnvPath("PATH", lyxrc.path_prefix);
770 // Check that user LyX directory is ok.
771 if (queryUserLyXDir(package().explicit_user_support()))
772 reconfigureUserLyXDir();
774 // no need for a splash when there is no GUI
779 // This one is generated in user_support directory by lib/configure.py.
780 if (!readRcFile("lyxrc.defaults"))
783 // Query the OS to know what formats are viewed natively
784 formats.setAutoOpen();
786 // Read lyxrc.dist again to be able to override viewer auto-detection.
787 readRcFile("lyxrc.dist");
789 system_lyxrc = lyxrc;
790 system_formats = formats;
791 pimpl_->system_converters_ = pimpl_->converters_;
792 pimpl_->system_movers_ = pimpl_->movers_;
793 system_lcolor = lcolor;
795 // This one is edited through the preferences dialog.
796 if (!readRcFile("preferences"))
799 if (!readEncodingsFile("encodings", "unicodesymbols"))
801 if (!readLanguagesFile("languages"))
805 LYXERR(Debug::INIT, "Reading layouts...");
811 // read keymap and ui files in batch mode as well
812 // because InsetInfo needs to know these to produce
813 // the correct output
815 // Set the language defined by the user.
816 //setGuiLanguage(lyxrc.gui_language);
818 // Set up command definitions
819 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
822 pimpl_->toplevel_keymap_.read("site");
823 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
824 // load user bind file user.bind
825 pimpl_->toplevel_keymap_.read("user");
827 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
830 if (use_gui && !readUIFile(lyxrc.ui_file))
833 if (lyxerr.debugging(Debug::LYXRC))
836 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
837 if (!lyxrc.path_prefix.empty())
838 prependEnvPath("PATH", lyxrc.path_prefix);
840 FileName const document_path(lyxrc.document_path);
841 if (document_path.exists() && document_path.isDirectory())
842 package().document_dir() = document_path;
844 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
845 if (package().temp_dir().empty()) {
846 Alert::error(_("Could not create temporary directory"),
847 bformat(_("Could not create a temporary directory in\n"
848 "%1$s. Make sure that this\n"
849 "path exists and is writable and try again."),
850 from_utf8(lyxrc.tempdir_path)));
851 // createLyXTmpDir() tries sufficiently hard to create a
852 // usable temp dir, so the probability to come here is
853 // close to zero. We therefore don't try to overcome this
854 // problem with e.g. asking the user for a new path and
855 // trying again but simply exit.
859 LYXERR(Debug::INIT, "LyX tmp dir: `"
860 << package().temp_dir().absFilename() << '\'');
862 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
863 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
865 // This must happen after package initialization and after lyxrc is
866 // read, therefore it can't be done by a static object.
867 ConverterCache::init();
869 // init the global menubar on Mac. This must be done after the session
870 // was recovered to know the "last files".
872 theApp()->initGlobalMenu();
878 void LyX::emergencyCleanup() const
880 // what to do about tmpfiles is non-obvious. we would
881 // like to delete any we find, but our lyxdir might
882 // contain documents etc. which might be helpful on
885 pimpl_->buffer_list_.emergencyWriteAll();
887 if (pimpl_->lyx_server_)
888 pimpl_->lyx_server_->emergencyCleanup();
889 pimpl_->lyx_server_.reset();
890 pimpl_->lyx_socket_.reset();
895 // return true if file does not exist or is older than configure.py.
896 static bool needsUpdate(string const & file)
898 // We cannot initialize configure_script directly because the package
899 // is not initialized yet when static objects are constructed.
900 static FileName configure_script;
901 static bool firstrun = true;
904 FileName(addName(package().system_support().absFilename(),
910 FileName(addName(package().user_support().absFilename(), file));
911 return !absfile.exists()
912 || configure_script.lastModified() > absfile.lastModified();
916 bool LyX::queryUserLyXDir(bool explicit_userdir)
918 // Does user directory exist?
919 FileName const sup = package().user_support();
920 if (sup.exists() && sup.isDirectory()) {
923 return needsUpdate("lyxrc.defaults")
924 || needsUpdate("lyxmodules.lst")
925 || needsUpdate("textclass.lst")
926 || needsUpdate("packages.lst");
929 first_start = !explicit_userdir;
931 // If the user specified explicitly a directory, ask whether
932 // to create it. If the user says "no", then exit.
933 if (explicit_userdir &&
935 _("Missing user LyX directory"),
936 bformat(_("You have specified a non-existent user "
937 "LyX directory, %1$s.\n"
938 "It is needed to keep your own configuration."),
939 from_utf8(package().user_support().absFilename())),
941 _("&Create directory"),
943 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
944 earlyExit(EXIT_FAILURE);
947 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
948 from_utf8(sup.absFilename()))) << endl;
950 if (!sup.createDirectory(0755)) {
951 // Failed, so let's exit.
952 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
954 earlyExit(EXIT_FAILURE);
961 bool LyX::readRcFile(string const & name)
963 LYXERR(Debug::INIT, "About to read " << name << "... ");
965 FileName const lyxrc_path = libFileSearch(string(), name);
966 if (!lyxrc_path.empty()) {
967 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
968 if (lyxrc.read(lyxrc_path) < 0) {
973 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
979 // Read the ui file `name'
980 bool LyX::readUIFile(string const & name, bool include)
990 struct keyword_item uitags[ui_last - 1] = {
991 { "include", ui_include },
992 { "menuset", ui_menuset },
993 { "toolbars", ui_toolbars },
994 { "toolbarset", ui_toolbarset }
997 // Ensure that a file is read only once (prevents include loops)
998 static list<string> uifiles;
999 list<string>::const_iterator it = uifiles.begin();
1000 list<string>::const_iterator end = uifiles.end();
1001 it = find(it, end, name);
1003 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1004 << "Is this an include loop?");
1008 LYXERR(Debug::INIT, "About to read " << name << "...");
1013 ui_path = libFileSearch("ui", name, "inc");
1014 if (ui_path.empty())
1015 ui_path = libFileSearch("ui",
1016 changeExtension(name, "inc"));
1019 ui_path = libFileSearch("ui", name, "ui");
1021 if (ui_path.empty()) {
1022 LYXERR(Debug::INIT, "Could not find " << name);
1023 showFileError(name);
1027 uifiles.push_back(name);
1029 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1030 Lexer lex(uitags, ui_last - 1);
1031 lex.setFile(ui_path);
1033 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1037 if (lyxerr.debugging(Debug::PARSER))
1038 lex.printTable(lyxerr);
1040 while (lex.isOK()) {
1041 switch (lex.lex()) {
1044 string const file = lex.getString();
1045 if (!readUIFile(file, true))
1050 theApp()->readMenus(lex);
1054 toolbarbackend.readToolbars(lex);
1058 toolbarbackend.readToolbarSettings(lex);
1062 if (!rtrim(lex.getString()).empty())
1063 lex.printError("LyX::ReadUIFile: "
1064 "Unknown menu tag: `$$Token'");
1072 // Read the languages file `name'
1073 bool LyX::readLanguagesFile(string const & name)
1075 LYXERR(Debug::INIT, "About to read " << name << "...");
1077 FileName const lang_path = libFileSearch(string(), name);
1078 if (lang_path.empty()) {
1079 showFileError(name);
1082 languages.read(lang_path);
1087 // Read the encodings file `name'
1088 bool LyX::readEncodingsFile(string const & enc_name,
1089 string const & symbols_name)
1091 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1092 << symbols_name << "...");
1094 FileName const symbols_path = libFileSearch(string(), symbols_name);
1095 if (symbols_path.empty()) {
1096 showFileError(symbols_name);
1100 FileName const enc_path = libFileSearch(string(), enc_name);
1101 if (enc_path.empty()) {
1102 showFileError(enc_name);
1105 encodings.read(enc_path, symbols_path);
1114 /// return the the number of arguments consumed
1115 typedef boost::function<int(string const &, string const &)> cmd_helper;
1117 int parse_dbg(string const & arg, string const &)
1120 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1121 Debug::showTags(lyxerr);
1124 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1126 lyxerr.level(Debug::value(arg));
1127 Debug::showLevel(lyxerr, lyxerr.level());
1132 int parse_help(string const &, string const &)
1135 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1136 "Command line switches (case sensitive):\n"
1137 "\t-help summarize LyX usage\n"
1138 "\t-userdir dir set user directory to dir\n"
1139 "\t-sysdir dir set system directory to dir\n"
1140 "\t-geometry WxH+X+Y set geometry of the main window\n"
1141 "\t-dbg feature[,feature]...\n"
1142 " select the features to debug.\n"
1143 " Type `lyx -dbg' to see the list of features\n"
1144 "\t-x [--execute] command\n"
1145 " where command is a lyx command.\n"
1146 "\t-e [--export] fmt\n"
1147 " where fmt is the export format of choice.\n"
1148 " Look on Tools->Preferences->File formats->Format\n"
1149 " to get an idea which parameters should be passed.\n"
1150 "\t-i [--import] fmt file.xxx\n"
1151 " where fmt is the import format of choice\n"
1152 " and file.xxx is the file to be imported.\n"
1153 "\t-version summarize version and build info\n"
1154 "Check the LyX man page for more details.")) << endl;
1160 int parse_version(string const &, string const &)
1162 lyxerr << "LyX " << lyx_version
1163 << " (" << lyx_release_date << ")" << endl;
1164 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1166 lyxerr << lyx_version_info << endl;
1172 int parse_sysdir(string const & arg, string const &)
1175 Alert::error(_("No system directory"),
1176 _("Missing directory for -sysdir switch"));
1179 cl_system_support = arg;
1184 int parse_userdir(string const & arg, string const &)
1187 Alert::error(_("No user directory"),
1188 _("Missing directory for -userdir switch"));
1191 cl_user_support = arg;
1196 int parse_execute(string const & arg, string const &)
1199 Alert::error(_("Incomplete command"),
1200 _("Missing command string after --execute switch"));
1208 int parse_export(string const & type, string const &)
1211 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1212 "--export switch")) << endl;
1215 batch = "buffer-export " + type;
1221 int parse_import(string const & type, string const & file)
1224 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1225 "--import switch")) << endl;
1229 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1233 batch = "buffer-import " + type + ' ' + file;
1238 int parse_geometry(string const & arg1, string const &)
1241 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1242 // remove also the arg
1245 // don't remove "-geometry"
1254 void LyX::easyParse(int & argc, char * argv[])
1256 map<string, cmd_helper> cmdmap;
1258 cmdmap["-dbg"] = parse_dbg;
1259 cmdmap["-help"] = parse_help;
1260 cmdmap["--help"] = parse_help;
1261 cmdmap["-version"] = parse_version;
1262 cmdmap["--version"] = parse_version;
1263 cmdmap["-sysdir"] = parse_sysdir;
1264 cmdmap["-userdir"] = parse_userdir;
1265 cmdmap["-x"] = parse_execute;
1266 cmdmap["--execute"] = parse_execute;
1267 cmdmap["-e"] = parse_export;
1268 cmdmap["--export"] = parse_export;
1269 cmdmap["-i"] = parse_import;
1270 cmdmap["--import"] = parse_import;
1271 cmdmap["-geometry"] = parse_geometry;
1273 for (int i = 1; i < argc; ++i) {
1274 map<string, cmd_helper>::const_iterator it
1275 = cmdmap.find(argv[i]);
1277 // don't complain if not found - may be parsed later
1278 if (it == cmdmap.end())
1282 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1284 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1286 int const remove = 1 + it->second(arg, arg2);
1288 // Now, remove used arguments by shifting
1289 // the following ones remove places down.
1292 for (int j = i; j < argc; ++j)
1293 argv[j] = argv[j + remove];
1298 pimpl_->batch_command = batch;
1302 FuncStatus getStatus(FuncRequest const & action)
1304 return LyX::ref().lyxFunc().getStatus(action);
1308 void dispatch(FuncRequest const & action)
1310 LyX::ref().lyxFunc().dispatch(action);
1314 BufferList & theBufferList()
1316 return LyX::ref().bufferList();
1320 LyXFunc & theLyXFunc()
1322 return LyX::ref().lyxFunc();
1326 Server & theServer()
1328 // FIXME: this should not be use_gui dependent
1329 BOOST_ASSERT(use_gui);
1330 return LyX::ref().server();
1334 ServerSocket & theServerSocket()
1336 // FIXME: this should not be use_gui dependent
1337 BOOST_ASSERT(use_gui);
1338 return LyX::ref().socket();
1342 KeyMap & theTopLevelKeymap()
1344 return LyX::ref().pimpl_->toplevel_keymap_;
1348 Converters & theConverters()
1350 return LyX::ref().converters();
1354 Converters & theSystemConverters()
1356 return LyX::ref().systemConverters();
1360 Movers & theMovers()
1362 return LyX::ref().pimpl_->movers_;
1366 Mover const & getMover(string const & fmt)
1368 return LyX::ref().pimpl_->movers_(fmt);
1372 void setMover(string const & fmt, string const & command)
1374 LyX::ref().pimpl_->movers_.set(fmt, command);
1378 Movers & theSystemMovers()
1380 return LyX::ref().pimpl_->system_movers_;
1384 Messages & getMessages(string const & language)
1386 return LyX::ref().getMessages(language);
1390 Messages & getGuiMessages()
1392 return LyX::ref().getGuiMessages();