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/assert.h"
49 #include "support/debug.h"
50 #include "support/environment.h"
51 #include "support/ExceptionMessage.h"
52 #include "support/filetools.h"
53 #include "support/gettext.h"
54 #include "support/lstrings.h"
55 #include "support/Messages.h"
56 #include "support/os.h"
57 #include "support/Package.h"
58 #include "support/Path.h"
59 #include "support/Systemcall.h"
61 #include <boost/bind.hpp>
62 #include <boost/scoped_ptr.hpp>
73 using namespace lyx::support;
77 namespace Alert = frontend::Alert;
78 namespace os = support::os;
82 // Are we using the GUI at all? We default to true and this is changed
83 // to false when the export feature is used.
89 // Filled with the command line arguments "foo" of "-sysdir foo" or
91 string cl_system_support;
92 string cl_user_support;
98 void showFileError(string const & error)
100 Alert::warning(_("Could not read configuration file"),
101 bformat(_("Error while reading the configuration file\n%1$s.\n"
102 "Please check your installation."), from_utf8(error)));
106 void reconfigureUserLyXDir()
108 string const configure_command = package().configure_command();
110 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
111 PathChanger p(package().user_support());
113 one.startscript(Systemcall::Wait, configure_command);
114 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
120 /// The main application class private implementation.
125 // Set the default User Interface language as soon as possible.
126 // The language used will be derived from the environment
128 messages_["GUI"] = Messages();
130 /// our function handler
133 BufferList buffer_list_;
135 KeyMap toplevel_keymap_;
137 CmdDef toplevel_cmddef_;
139 boost::scoped_ptr<Server> lyx_server_;
141 boost::scoped_ptr<ServerSocket> lyx_socket_;
143 boost::scoped_ptr<frontend::Application> application_;
144 /// lyx session, containing lastfiles, lastfilepos, and lastopened
145 boost::scoped_ptr<Session> session_;
147 /// Files to load at start.
148 vector<string> files_to_load_;
150 /// The messages translators.
151 map<string, Messages> messages_;
153 /// The file converters.
154 Converters converters_;
156 // The system converters copy after reading lyxrc.defaults.
157 Converters system_converters_;
162 Movers system_movers_;
164 /// has this user started lyx for the first time?
166 /// the parsed command line batch command if any
167 string batch_command;
171 frontend::Application * theApp()
174 return singleton_->pimpl_->application_.get();
186 void LyX::exit(int exit_code) const
189 // Something wrong happened so better save everything, just in
194 // Properly crash in debug mode in order to get a useful backtrace.
198 // In release mode, try to exit gracefully.
200 theApp()->exit(exit_code);
208 LASSERT(singleton_, /**/);
213 LyX const & LyX::cref()
215 LASSERT(singleton_, /**/);
228 BufferList & LyX::bufferList()
230 return pimpl_->buffer_list_;
234 BufferList const & LyX::bufferList() const
236 return pimpl_->buffer_list_;
240 Session & LyX::session()
242 LASSERT(pimpl_->session_.get(), /**/);
243 return *pimpl_->session_.get();
247 Session const & LyX::session() const
249 LASSERT(pimpl_->session_.get(), /**/);
250 return *pimpl_->session_.get();
254 LyXFunc & LyX::lyxFunc()
256 return pimpl_->lyxfunc_;
260 LyXFunc const & LyX::lyxFunc() const
262 return pimpl_->lyxfunc_;
266 Server & LyX::server()
268 LASSERT(pimpl_->lyx_server_.get(), /**/);
269 return *pimpl_->lyx_server_.get();
273 Server const & LyX::server() const
275 LASSERT(pimpl_->lyx_server_.get(), /**/);
276 return *pimpl_->lyx_server_.get();
280 ServerSocket & LyX::socket()
282 LASSERT(pimpl_->lyx_socket_.get(), /**/);
283 return *pimpl_->lyx_socket_.get();
287 ServerSocket const & LyX::socket() const
289 LASSERT(pimpl_->lyx_socket_.get(), /**/);
290 return *pimpl_->lyx_socket_.get();
294 frontend::Application & LyX::application()
296 LASSERT(pimpl_->application_.get(), /**/);
297 return *pimpl_->application_.get();
301 frontend::Application const & LyX::application() const
303 LASSERT(pimpl_->application_.get(), /**/);
304 return *pimpl_->application_.get();
308 CmdDef & LyX::topLevelCmdDef()
310 return pimpl_->toplevel_cmddef_;
314 Converters & LyX::converters()
316 return pimpl_->converters_;
320 Converters & LyX::systemConverters()
322 return pimpl_->system_converters_;
326 Messages & LyX::getMessages(string const & language)
328 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
330 if (it != pimpl_->messages_.end())
333 pair<map<string, Messages>::iterator, bool> result =
334 pimpl_->messages_.insert(make_pair(language, Messages(language)));
336 LASSERT(result.second, /**/);
337 return result.first->second;
341 Messages & LyX::getGuiMessages()
343 return pimpl_->messages_["GUI"];
347 void LyX::setGuiLanguage(string const & language)
349 pimpl_->messages_["GUI"] = Messages(language);
353 int LyX::exec(int & argc, char * argv[])
355 // Here we need to parse the command line. At least
356 // we need to parse for "-dbg" and "-help"
357 easyParse(argc, argv);
360 init_package(to_utf8(from_local8bit(argv[0])),
361 cl_system_support, cl_user_support,
362 top_build_dir_is_one_level_up);
363 } catch (ExceptionMessage const & message) {
364 if (message.type_ == ErrorException) {
365 Alert::error(message.title_, message.details_);
367 } else if (message.type_ == WarningException) {
368 Alert::warning(message.title_, message.details_);
372 // Reinit the messages machinery in case package() knows
373 // something interesting about the locale directory.
377 // FIXME: create a ConsoleApplication
378 int exit_status = init(argc, argv);
386 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
391 BufferList::iterator begin = pimpl_->buffer_list_.begin();
393 bool final_success = false;
394 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
396 if (buf != buf->masterBuffer())
398 bool success = false;
399 buf->dispatch(pimpl_->batch_command, &success);
400 final_success |= success;
403 return !final_success;
406 // Let the frontend parse and remove all arguments that it knows
407 pimpl_->application_.reset(createApplication(argc, argv));
409 // Parse and remove all known arguments in the LyX singleton
410 // Give an error for all remaining ones.
411 int exit_status = init(argc, argv);
413 // Kill the application object before exiting.
414 pimpl_->application_.reset();
421 /* Create a CoreApplication class that will provide the main event loop
422 * and the socket callback registering. With Qt4, only QtCore
423 * library would be needed.
424 * When this is done, a server_mode could be created and the following two
425 * line would be moved out from here.
427 // Note: socket callback must be registered after init(argc, argv)
428 // such that package().temp_dir() is properly initialized.
429 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
430 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
431 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
433 // Start the real execution loop.
434 exit_status = pimpl_->application_->exec();
442 void LyX::prepareExit()
444 // Clear the clipboard and selection stack:
445 cap::clearCutStack();
446 cap::clearSelection();
448 // close buffers first
449 pimpl_->buffer_list_.closeAll();
451 // register session changes and shutdown server and socket
453 if (pimpl_->session_)
454 pimpl_->session_->writeFile();
455 pimpl_->session_.reset();
456 pimpl_->lyx_server_.reset();
457 pimpl_->lyx_socket_.reset();
460 // do any other cleanup procedures now
461 if (package().temp_dir() != package().system_temp_dir()) {
462 LYXERR(Debug::INFO, "Deleting tmp dir "
463 << package().temp_dir().absFilename());
465 if (!package().temp_dir().destroyDirectory()) {
466 docstring const msg =
467 bformat(_("Unable to remove the temporary directory %1$s"),
468 from_utf8(package().temp_dir().absFilename()));
469 Alert::warning(_("Unable to remove temporary directory"), msg);
473 // Kill the application object before exiting. This avoids crashes
474 // when exiting on Linux.
475 if (pimpl_->application_)
476 pimpl_->application_.reset();
480 void LyX::earlyExit(int status)
482 LASSERT(pimpl_->application_.get(), /**/);
483 // LyX::pimpl_::application_ is not initialised at this
484 // point so it's safe to just exit after some cleanup.
490 int LyX::init(int & argc, char * argv[])
492 // check for any spurious extra arguments
493 // other than documents
494 for (int argi = 1; argi < argc ; ++argi) {
495 if (argv[argi][0] == '-') {
497 bformat(_("Wrong command line option `%1$s'. Exiting."),
498 from_utf8(argv[argi]))) << endl;
503 // Initialization of LyX (reads lyxrc and more)
504 LYXERR(Debug::INIT, "Initializing LyX::init...");
505 bool success = init();
506 LYXERR(Debug::INIT, "Initializing LyX::init...done");
510 // Remaining arguments are assumed to be files to load.
511 for (int argi = argc - 1; argi >= 1; --argi)
512 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
515 pimpl_->files_to_load_.push_back(
516 i18nLibFileSearch("examples", "splash.lyx").absFilename());
523 void LyX::addFileToLoad(string const & fname)
525 vector<string>::const_iterator cit = find(
526 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
529 if (cit == pimpl_->files_to_load_.end())
530 pimpl_->files_to_load_.push_back(fname);
534 void LyX::loadFiles()
536 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
537 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
539 for (; it != end; ++it) {
540 // get absolute path of file and add ".lyx" to
541 // the filename if necessary
542 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
548 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
549 if (buf->loadLyXFile(fname)) {
550 ErrorList const & el = buf->errorList("Parse");
552 for_each(el.begin(), el.end(),
553 boost::bind(&LyX::printError, this, _1));
556 pimpl_->buffer_list_.release(buf);
561 void LyX::execBatchCommands()
563 // The advantage of doing this here is that the event loop
564 // is already started. So any need for interaction will be
567 // if reconfiguration is needed.
568 while (LayoutFileList::get().empty()) {
569 switch (Alert::prompt(
570 _("No textclass is found"),
571 _("LyX cannot continue because no textclass is found. "
572 "You can either reconfigure normally, or reconfigure using "
573 "default textclasses, or quit LyX."),
580 // regular reconfigure
581 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
584 // reconfigure --without-latex-config
585 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
586 " --without-latex-config"));
589 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
594 // create the first main window
595 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
597 if (!pimpl_->files_to_load_.empty()) {
598 // if some files were specified at command-line we assume that the
599 // user wants to edit *these* files and not to restore the session.
600 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
601 pimpl_->lyxfunc_.dispatch(
602 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
604 // clear this list to save a few bytes of RAM
605 pimpl_->files_to_load_.clear();
608 pimpl_->application_->restoreGuiSession();
610 // Execute batch commands if available
611 if (pimpl_->batch_command.empty())
614 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
616 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
623 The SIGHUP signal does not exist on Windows and does not need to be handled.
625 Windows handles SIGFPE and SIGSEGV signals as expected.
627 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
628 cause a new thread to be spawned. This may well result in unexpected
629 behaviour by the single-threaded LyX.
631 SIGTERM signals will come only from another process actually sending
632 that signal using 'raise' in Windows' POSIX compatability layer. It will
633 not come from the general "terminate process" methods that everyone
634 actually uses (and which can't be trapped). Killing an app 'politely' on
635 Windows involves first sending a WM_CLOSE message, something that is
636 caught already by the Qt frontend.
638 For more information see:
640 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
641 ...signals are mostly useless on Windows for a variety of reasons that are
644 'UNIX Application Migration Guide, Chapter 9'
645 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
647 'How To Terminate an Application "Cleanly" in Win32'
648 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
652 static void error_handler(int err_sig)
654 // Throw away any signals other than the first one received.
655 static sig_atomic_t handling_error = false;
658 handling_error = true;
660 // We have received a signal indicating a fatal error, so
661 // try and save the data ASAP.
662 LyX::cref().emergencyCleanup();
664 // These lyxerr calls may or may not work:
666 // Signals are asynchronous, so the main program may be in a very
667 // fragile state when a signal is processed and thus while a signal
668 // handler function executes.
669 // In general, therefore, we should avoid performing any
670 // I/O operations or calling most library and system functions from
673 // This shouldn't matter here, however, as we've already invoked
678 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
682 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
685 lyxerr << "\nlyx: SIGSEGV signal caught\n"
686 "Sorry, you have found a bug in LyX. "
687 "Please read the bug-reporting instructions "
688 "in Help->Introduction and send us a bug report, "
689 "if necessary. Thanks !\nBye." << endl;
697 // Deinstall the signal handlers
699 signal(SIGHUP, SIG_DFL);
701 signal(SIGINT, SIG_DFL);
702 signal(SIGFPE, SIG_DFL);
703 signal(SIGSEGV, SIG_DFL);
704 signal(SIGTERM, SIG_DFL);
707 if (err_sig == SIGSEGV ||
708 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
710 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
719 void LyX::printError(ErrorItem const & ei)
721 docstring tmp = _("LyX: ") + ei.error + char_type(':')
723 cerr << to_utf8(tmp) << endl;
730 signal(SIGHUP, error_handler);
732 signal(SIGFPE, error_handler);
733 signal(SIGSEGV, error_handler);
734 signal(SIGINT, error_handler);
735 signal(SIGTERM, error_handler);
736 // SIGPIPE can be safely ignored.
738 lyxrc.tempdir_path = package().temp_dir().absFilename();
739 lyxrc.document_path = package().document_dir().absFilename();
741 if (lyxrc.example_path.empty()) {
742 lyxrc.example_path = addPath(package().system_support().absFilename(),
745 if (lyxrc.template_path.empty()) {
746 lyxrc.template_path = addPath(package().system_support().absFilename(),
751 // Read configuration files
754 // This one may have been distributed along with LyX.
755 if (!readRcFile("lyxrc.dist"))
758 // Set the language defined by the distributor.
759 //setGuiLanguage(lyxrc.gui_language);
761 // Set the PATH correctly.
762 #if !defined (USE_POSIX_PACKAGING)
763 // Add the directory containing the LyX executable to the path
764 // so that LyX can find things like tex2lyx.
765 if (package().build_support().empty())
766 prependEnvPath("PATH", package().binary_dir().absFilename());
768 if (!lyxrc.path_prefix.empty())
769 prependEnvPath("PATH", lyxrc.path_prefix);
771 // Check that user LyX directory is ok.
772 if (queryUserLyXDir(package().explicit_user_support()))
773 reconfigureUserLyXDir();
775 // no need for a splash when there is no GUI
780 // This one is generated in user_support directory by lib/configure.py.
781 if (!readRcFile("lyxrc.defaults"))
784 // Query the OS to know what formats are viewed natively
785 formats.setAutoOpen();
787 // Read lyxrc.dist again to be able to override viewer auto-detection.
788 readRcFile("lyxrc.dist");
790 system_lyxrc = lyxrc;
791 system_formats = formats;
792 pimpl_->system_converters_ = pimpl_->converters_;
793 pimpl_->system_movers_ = pimpl_->movers_;
794 system_lcolor = lcolor;
796 // This one is edited through the preferences dialog.
797 if (!readRcFile("preferences"))
800 if (!readEncodingsFile("encodings", "unicodesymbols"))
802 if (!readLanguagesFile("languages"))
806 LYXERR(Debug::INIT, "Reading layouts...");
812 // read keymap and ui files in batch mode as well
813 // because InsetInfo needs to know these to produce
814 // the correct output
816 // Set the language defined by the user.
817 //setGuiLanguage(lyxrc.gui_language);
819 // Set up command definitions
820 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
823 pimpl_->toplevel_keymap_.read("site");
824 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
825 // load user bind file user.bind
826 pimpl_->toplevel_keymap_.read("user");
828 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
831 if (use_gui && !readUIFile(lyxrc.ui_file))
834 if (lyxerr.debugging(Debug::LYXRC))
837 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
838 if (!lyxrc.path_prefix.empty())
839 prependEnvPath("PATH", lyxrc.path_prefix);
841 FileName const document_path(lyxrc.document_path);
842 if (document_path.exists() && document_path.isDirectory())
843 package().document_dir() = document_path;
845 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
846 if (package().temp_dir().empty()) {
847 Alert::error(_("Could not create temporary directory"),
848 bformat(_("Could not create a temporary directory in\n"
849 "%1$s. Make sure that this\n"
850 "path exists and is writable and try again."),
851 from_utf8(lyxrc.tempdir_path)));
852 // createLyXTmpDir() tries sufficiently hard to create a
853 // usable temp dir, so the probability to come here is
854 // close to zero. We therefore don't try to overcome this
855 // problem with e.g. asking the user for a new path and
856 // trying again but simply exit.
860 LYXERR(Debug::INIT, "LyX tmp dir: `"
861 << package().temp_dir().absFilename() << '\'');
863 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
864 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
866 // This must happen after package initialization and after lyxrc is
867 // read, therefore it can't be done by a static object.
868 ConverterCache::init();
870 // init the global menubar on Mac. This must be done after the session
871 // was recovered to know the "last files".
873 theApp()->initGlobalMenu();
879 void LyX::emergencyCleanup() const
881 // what to do about tmpfiles is non-obvious. we would
882 // like to delete any we find, but our lyxdir might
883 // contain documents etc. which might be helpful on
886 pimpl_->buffer_list_.emergencyWriteAll();
888 if (pimpl_->lyx_server_)
889 pimpl_->lyx_server_->emergencyCleanup();
890 pimpl_->lyx_server_.reset();
891 pimpl_->lyx_socket_.reset();
896 // return true if file does not exist or is older than configure.py.
897 static bool needsUpdate(string const & file)
899 // We cannot initialize configure_script directly because the package
900 // is not initialized yet when static objects are constructed.
901 static FileName configure_script;
902 static bool firstrun = true;
905 FileName(addName(package().system_support().absFilename(),
911 FileName(addName(package().user_support().absFilename(), file));
912 return !absfile.exists()
913 || configure_script.lastModified() > absfile.lastModified();
917 bool LyX::queryUserLyXDir(bool explicit_userdir)
919 // Does user directory exist?
920 FileName const sup = package().user_support();
921 if (sup.exists() && sup.isDirectory()) {
924 return needsUpdate("lyxrc.defaults")
925 || needsUpdate("lyxmodules.lst")
926 || needsUpdate("textclass.lst")
927 || needsUpdate("packages.lst");
930 first_start = !explicit_userdir;
932 // If the user specified explicitly a directory, ask whether
933 // to create it. If the user says "no", then exit.
934 if (explicit_userdir &&
936 _("Missing user LyX directory"),
937 bformat(_("You have specified a non-existent user "
938 "LyX directory, %1$s.\n"
939 "It is needed to keep your own configuration."),
940 from_utf8(package().user_support().absFilename())),
942 _("&Create directory"),
944 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
945 earlyExit(EXIT_FAILURE);
948 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
949 from_utf8(sup.absFilename()))) << endl;
951 if (!sup.createDirectory(0755)) {
952 // Failed, so let's exit.
953 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
955 earlyExit(EXIT_FAILURE);
962 bool LyX::readRcFile(string const & name)
964 LYXERR(Debug::INIT, "About to read " << name << "... ");
966 FileName const lyxrc_path = libFileSearch(string(), name);
967 if (!lyxrc_path.empty()) {
968 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
969 if (lyxrc.read(lyxrc_path) < 0) {
974 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
980 // Read the ui file `name'
981 bool LyX::readUIFile(string const & name, bool include)
991 LexerKeyword uitags[] = {
992 { "include", ui_include },
993 { "menuset", ui_menuset },
994 { "toolbars", ui_toolbars },
995 { "toolbarset", ui_toolbarset }
998 // Ensure that a file is read only once (prevents include loops)
999 static list<string> uifiles;
1000 list<string>::const_iterator it = uifiles.begin();
1001 list<string>::const_iterator end = uifiles.end();
1002 it = find(it, end, name);
1004 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1005 << "Is this an include loop?");
1009 LYXERR(Debug::INIT, "About to read " << name << "...");
1014 ui_path = libFileSearch("ui", name, "inc");
1015 if (ui_path.empty())
1016 ui_path = libFileSearch("ui",
1017 changeExtension(name, "inc"));
1020 ui_path = libFileSearch("ui", name, "ui");
1022 if (ui_path.empty()) {
1023 LYXERR(Debug::INIT, "Could not find " << name);
1024 showFileError(name);
1028 uifiles.push_back(name);
1030 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1032 lex.setFile(ui_path);
1034 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1038 if (lyxerr.debugging(Debug::PARSER))
1039 lex.printTable(lyxerr);
1041 while (lex.isOK()) {
1042 switch (lex.lex()) {
1045 string const file = lex.getString();
1046 if (!readUIFile(file, true))
1051 theApp()->readMenus(lex);
1055 toolbarbackend.readToolbars(lex);
1059 toolbarbackend.readToolbarSettings(lex);
1063 if (!rtrim(lex.getString()).empty())
1064 lex.printError("LyX::ReadUIFile: "
1065 "Unknown menu tag: `$$Token'");
1073 // Read the languages file `name'
1074 bool LyX::readLanguagesFile(string const & name)
1076 LYXERR(Debug::INIT, "About to read " << name << "...");
1078 FileName const lang_path = libFileSearch(string(), name);
1079 if (lang_path.empty()) {
1080 showFileError(name);
1083 languages.read(lang_path);
1088 // Read the encodings file `name'
1089 bool LyX::readEncodingsFile(string const & enc_name,
1090 string const & symbols_name)
1092 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1093 << symbols_name << "...");
1095 FileName const symbols_path = libFileSearch(string(), symbols_name);
1096 if (symbols_path.empty()) {
1097 showFileError(symbols_name);
1101 FileName const enc_path = libFileSearch(string(), enc_name);
1102 if (enc_path.empty()) {
1103 showFileError(enc_name);
1106 encodings.read(enc_path, symbols_path);
1115 /// return the the number of arguments consumed
1116 typedef boost::function<int(string const &, string const &)> cmd_helper;
1118 int parse_dbg(string const & arg, string const &)
1121 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1122 Debug::showTags(lyxerr);
1125 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1127 lyxerr.level(Debug::value(arg));
1128 Debug::showLevel(lyxerr, lyxerr.level());
1133 int parse_help(string const &, string const &)
1136 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1137 "Command line switches (case sensitive):\n"
1138 "\t-help summarize LyX usage\n"
1139 "\t-userdir dir set user directory to dir\n"
1140 "\t-sysdir dir set system directory to dir\n"
1141 "\t-geometry WxH+X+Y set geometry of the main window\n"
1142 "\t-dbg feature[,feature]...\n"
1143 " select the features to debug.\n"
1144 " Type `lyx -dbg' to see the list of features\n"
1145 "\t-x [--execute] command\n"
1146 " where command is a lyx command.\n"
1147 "\t-e [--export] fmt\n"
1148 " where fmt is the export format of choice.\n"
1149 " Look on Tools->Preferences->File formats->Format\n"
1150 " to get an idea which parameters should be passed.\n"
1151 "\t-i [--import] fmt file.xxx\n"
1152 " where fmt is the import format of choice\n"
1153 " and file.xxx is the file to be imported.\n"
1154 "\t-version summarize version and build info\n"
1155 "Check the LyX man page for more details.")) << endl;
1161 int parse_version(string const &, string const &)
1163 lyxerr << "LyX " << lyx_version
1164 << " (" << lyx_release_date << ")" << endl;
1165 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1167 lyxerr << lyx_version_info << endl;
1173 int parse_sysdir(string const & arg, string const &)
1176 Alert::error(_("No system directory"),
1177 _("Missing directory for -sysdir switch"));
1180 cl_system_support = arg;
1185 int parse_userdir(string const & arg, string const &)
1188 Alert::error(_("No user directory"),
1189 _("Missing directory for -userdir switch"));
1192 cl_user_support = arg;
1197 int parse_execute(string const & arg, string const &)
1200 Alert::error(_("Incomplete command"),
1201 _("Missing command string after --execute switch"));
1209 int parse_export(string const & type, string const &)
1212 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1213 "--export switch")) << endl;
1216 batch = "buffer-export " + type;
1222 int parse_import(string const & type, string const & file)
1225 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1226 "--import switch")) << endl;
1230 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1234 batch = "buffer-import " + type + ' ' + file;
1239 int parse_geometry(string const & arg1, string const &)
1242 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1243 // remove also the arg
1246 // don't remove "-geometry"
1255 void LyX::easyParse(int & argc, char * argv[])
1257 map<string, cmd_helper> cmdmap;
1259 cmdmap["-dbg"] = parse_dbg;
1260 cmdmap["-help"] = parse_help;
1261 cmdmap["--help"] = parse_help;
1262 cmdmap["-version"] = parse_version;
1263 cmdmap["--version"] = parse_version;
1264 cmdmap["-sysdir"] = parse_sysdir;
1265 cmdmap["-userdir"] = parse_userdir;
1266 cmdmap["-x"] = parse_execute;
1267 cmdmap["--execute"] = parse_execute;
1268 cmdmap["-e"] = parse_export;
1269 cmdmap["--export"] = parse_export;
1270 cmdmap["-i"] = parse_import;
1271 cmdmap["--import"] = parse_import;
1272 cmdmap["-geometry"] = parse_geometry;
1274 for (int i = 1; i < argc; ++i) {
1275 map<string, cmd_helper>::const_iterator it
1276 = cmdmap.find(argv[i]);
1278 // don't complain if not found - may be parsed later
1279 if (it == cmdmap.end())
1283 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1285 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1287 int const remove = 1 + it->second(arg, arg2);
1289 // Now, remove used arguments by shifting
1290 // the following ones remove places down.
1293 for (int j = i; j < argc; ++j)
1294 argv[j] = argv[j + remove];
1299 pimpl_->batch_command = batch;
1303 FuncStatus getStatus(FuncRequest const & action)
1305 return LyX::ref().lyxFunc().getStatus(action);
1309 void dispatch(FuncRequest const & action)
1311 LyX::ref().lyxFunc().dispatch(action);
1315 BufferList & theBufferList()
1317 return LyX::ref().bufferList();
1321 LyXFunc & theLyXFunc()
1323 return LyX::ref().lyxFunc();
1327 Server & theServer()
1329 // FIXME: this should not be use_gui dependent
1330 LASSERT(use_gui, /**/);
1331 return LyX::ref().server();
1335 ServerSocket & theServerSocket()
1337 // FIXME: this should not be use_gui dependent
1338 LASSERT(use_gui, /**/);
1339 return LyX::ref().socket();
1343 KeyMap & theTopLevelKeymap()
1345 return LyX::ref().pimpl_->toplevel_keymap_;
1349 Converters & theConverters()
1351 return LyX::ref().converters();
1355 Converters & theSystemConverters()
1357 return LyX::ref().systemConverters();
1361 Movers & theMovers()
1363 return LyX::ref().pimpl_->movers_;
1367 Mover const & getMover(string const & fmt)
1369 return LyX::ref().pimpl_->movers_(fmt);
1373 void setMover(string const & fmt, string const & command)
1375 LyX::ref().pimpl_->movers_.set(fmt, command);
1379 Movers & theSystemMovers()
1381 return LyX::ref().pimpl_->system_movers_;
1385 Messages & getMessages(string const & language)
1387 return LyX::ref().getMessages(language);
1391 Messages & getGuiMessages()
1393 return LyX::ref().getGuiMessages();