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 "buffer_funcs.h"
22 #include "BufferList.h"
25 #include "ConverterCache.h"
26 #include "Converter.h"
27 #include "CutAndPaste.h"
29 #include "ErrorList.h"
34 #include "LyXAction.h"
37 #include "MenuBackend.h"
38 #include "ModuleList.h"
41 #include "ServerSocket.h"
43 #include "TextClassList.h"
44 #include "ToolbarBackend.h"
46 #include "frontends/alert.h"
47 #include "frontends/Application.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.
87 bool quitting; // flag, that we are quitting the program
91 // Filled with the command line arguments "foo" of "-sysdir foo" or
93 string cl_system_support;
94 string cl_user_support;
100 void showFileError(string const & error)
102 Alert::warning(_("Could not read configuration file"),
103 bformat(_("Error while reading the configuration file\n%1$s.\n"
104 "Please check your installation."), from_utf8(error)));
108 void reconfigureUserLyXDir()
110 string const configure_command = package().configure_command();
112 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
113 PathChanger p(package().user_support());
115 one.startscript(Systemcall::Wait, configure_command);
116 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
122 /// The main application class private implementation.
127 // Set the default User Interface language as soon as possible.
128 // The language used will be derived from the environment
130 messages_["GUI"] = Messages();
132 /// our function handler
135 BufferList buffer_list_;
137 KeyMap toplevel_keymap_;
139 CmdDef toplevel_cmddef_;
141 boost::scoped_ptr<Server> lyx_server_;
143 boost::scoped_ptr<ServerSocket> lyx_socket_;
145 boost::scoped_ptr<frontend::Application> application_;
146 /// lyx session, containing lastfiles, lastfilepos, and lastopened
147 boost::scoped_ptr<Session> session_;
149 /// Files to load at start.
150 vector<string> files_to_load_;
152 /// The messages translators.
153 map<string, Messages> messages_;
155 /// The file converters.
156 Converters converters_;
158 // The system converters copy after reading lyxrc.defaults.
159 Converters system_converters_;
164 Movers system_movers_;
166 /// has this user started lyx for the first time?
168 /// the parsed command line batch command if any
169 string batch_command;
173 frontend::Application * theApp()
176 return singleton_->pimpl_->application_.get();
188 void LyX::exit(int exit_code) const
191 // Something wrong happened so better save everything, just in
196 // Properly crash in debug mode in order to get a useful backtrace.
200 // In release mode, try to exit gracefully.
202 theApp()->exit(exit_code);
210 BOOST_ASSERT(singleton_);
215 LyX const & LyX::cref()
217 BOOST_ASSERT(singleton_);
230 BufferList & LyX::bufferList()
232 return pimpl_->buffer_list_;
236 BufferList const & LyX::bufferList() const
238 return pimpl_->buffer_list_;
242 Session & LyX::session()
244 BOOST_ASSERT(pimpl_->session_.get());
245 return *pimpl_->session_.get();
249 Session const & LyX::session() const
251 BOOST_ASSERT(pimpl_->session_.get());
252 return *pimpl_->session_.get();
256 LyXFunc & LyX::lyxFunc()
258 return pimpl_->lyxfunc_;
262 LyXFunc const & LyX::lyxFunc() const
264 return pimpl_->lyxfunc_;
268 Server & LyX::server()
270 BOOST_ASSERT(pimpl_->lyx_server_.get());
271 return *pimpl_->lyx_server_.get();
275 Server const & LyX::server() const
277 BOOST_ASSERT(pimpl_->lyx_server_.get());
278 return *pimpl_->lyx_server_.get();
282 ServerSocket & LyX::socket()
284 BOOST_ASSERT(pimpl_->lyx_socket_.get());
285 return *pimpl_->lyx_socket_.get();
289 ServerSocket const & LyX::socket() const
291 BOOST_ASSERT(pimpl_->lyx_socket_.get());
292 return *pimpl_->lyx_socket_.get();
296 frontend::Application & LyX::application()
298 BOOST_ASSERT(pimpl_->application_.get());
299 return *pimpl_->application_.get();
303 frontend::Application const & LyX::application() const
305 BOOST_ASSERT(pimpl_->application_.get());
306 return *pimpl_->application_.get();
310 KeyMap & LyX::topLevelKeymap()
312 return pimpl_->toplevel_keymap_;
316 CmdDef & LyX::topLevelCmdDef()
318 return pimpl_->toplevel_cmddef_;
322 Converters & LyX::converters()
324 return pimpl_->converters_;
328 Converters & LyX::systemConverters()
330 return pimpl_->system_converters_;
334 KeyMap const & LyX::topLevelKeymap() const
336 return pimpl_->toplevel_keymap_;
340 Messages & LyX::getMessages(string const & language)
342 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
344 if (it != pimpl_->messages_.end())
347 pair<map<string, Messages>::iterator, bool> result =
348 pimpl_->messages_.insert(make_pair(language, Messages(language)));
350 BOOST_ASSERT(result.second);
351 return result.first->second;
355 Messages & LyX::getGuiMessages()
357 return pimpl_->messages_["GUI"];
361 void LyX::setGuiLanguage(string const & language)
363 pimpl_->messages_["GUI"] = Messages(language);
367 int LyX::exec(int & argc, char * argv[])
369 // Here we need to parse the command line. At least
370 // we need to parse for "-dbg" and "-help"
371 easyParse(argc, argv);
374 init_package(to_utf8(from_local8bit(argv[0])),
375 cl_system_support, cl_user_support,
376 top_build_dir_is_one_level_up);
377 } catch (ExceptionMessage const & message) {
378 if (message.type_ == ErrorException) {
379 Alert::error(message.title_, message.details_);
381 } else if (message.type_ == WarningException) {
382 Alert::warning(message.title_, message.details_);
386 // Reinit the messages machinery in case package() knows
387 // something interesting about the locale directory.
391 // FIXME: create a ConsoleApplication
392 int exit_status = init(argc, argv);
400 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
405 BufferList::iterator begin = pimpl_->buffer_list_.begin();
407 bool final_success = false;
408 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
410 if (buf != buf->masterBuffer())
412 bool success = false;
413 buf->dispatch(pimpl_->batch_command, &success);
414 final_success |= success;
417 return !final_success;
420 // Let the frontend parse and remove all arguments that it knows
421 pimpl_->application_.reset(createApplication(argc, argv));
423 // Parse and remove all known arguments in the LyX singleton
424 // Give an error for all remaining ones.
425 int exit_status = init(argc, argv);
427 // Kill the application object before exiting.
428 pimpl_->application_.reset();
435 /* Create a CoreApplication class that will provide the main event loop
436 * and the socket callback registering. With Qt4, only QtCore
437 * library would be needed.
438 * When this is done, a server_mode could be created and the following two
439 * line would be moved out from here.
441 // Note: socket callback must be registered after init(argc, argv)
442 // such that package().temp_dir() is properly initialized.
443 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
444 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
445 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
447 // Start the real execution loop.
448 exit_status = pimpl_->application_->exec();
456 void LyX::prepareExit()
458 // Clear the clipboard and selection stack:
459 cap::clearCutStack();
460 cap::clearSelection();
462 // Set a flag that we do quitting from the program,
463 // so no refreshes are necessary.
466 // close buffers first
467 pimpl_->buffer_list_.closeAll();
469 // register session changes and shutdown server and socket
471 if (pimpl_->session_)
472 pimpl_->session_->writeFile();
473 pimpl_->session_.reset();
474 pimpl_->lyx_server_.reset();
475 pimpl_->lyx_socket_.reset();
478 // do any other cleanup procedures now
479 if (package().temp_dir() != package().system_temp_dir()) {
480 LYXERR(Debug::INFO, "Deleting tmp dir "
481 << package().temp_dir().absFilename());
483 if (!package().temp_dir().destroyDirectory()) {
484 docstring const msg =
485 bformat(_("Unable to remove the temporary directory %1$s"),
486 from_utf8(package().temp_dir().absFilename()));
487 Alert::warning(_("Unable to remove temporary directory"), msg);
491 // Kill the application object before exiting. This avoids crashes
492 // when exiting on Linux.
493 if (pimpl_->application_)
494 pimpl_->application_.reset();
498 void LyX::earlyExit(int status)
500 BOOST_ASSERT(pimpl_->application_.get());
501 // LyX::pimpl_::application_ is not initialised at this
502 // point so it's safe to just exit after some cleanup.
508 int LyX::init(int & argc, char * argv[])
510 // check for any spurious extra arguments
511 // other than documents
512 for (int argi = 1; argi < argc ; ++argi) {
513 if (argv[argi][0] == '-') {
515 bformat(_("Wrong command line option `%1$s'. Exiting."),
516 from_utf8(argv[argi]))) << endl;
521 // Initialization of LyX (reads lyxrc and more)
522 LYXERR(Debug::INIT, "Initializing LyX::init...");
523 bool success = init();
524 LYXERR(Debug::INIT, "Initializing LyX::init...done");
528 // Remaining arguments are assumed to be files to load.
529 for (int argi = argc - 1; argi >= 1; --argi)
530 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
533 pimpl_->files_to_load_.push_back(
534 i18nLibFileSearch("examples", "splash.lyx").absFilename());
541 void LyX::addFileToLoad(string const & fname)
543 vector<string>::const_iterator cit = find(
544 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
547 if (cit == pimpl_->files_to_load_.end())
548 pimpl_->files_to_load_.push_back(fname);
552 void LyX::loadFiles()
554 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
555 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
557 for (; it != end; ++it) {
558 // get absolute path of file and add ".lyx" to
559 // the filename if necessary
560 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
566 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
567 if (buf->loadLyXFile(fname)) {
568 ErrorList const & el = buf->errorList("Parse");
570 for_each(el.begin(), el.end(),
571 boost::bind(&LyX::printError, this, _1));
574 pimpl_->buffer_list_.release(buf);
579 void LyX::execBatchCommands()
581 // The advantage of doing this here is that the event loop
582 // is already started. So any need for interaction will be
585 // if reconfiguration is needed.
586 while (textclasslist.empty()) {
587 switch (Alert::prompt(
588 _("No textclass is found"),
589 _("LyX cannot continue because no textclass is found. "
590 "You can either reconfigure normally, or reconfigure using "
591 "default textclasses, or quit LyX."),
598 // regular reconfigure
599 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
602 // reconfigure --without-latex-config
603 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
604 " --without-latex-config"));
607 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
612 // create the first main window
613 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
615 if (!pimpl_->files_to_load_.empty()) {
616 // if some files were specified at command-line we assume that the
617 // user wants to edit *these* files and not to restore the session.
618 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
619 pimpl_->lyxfunc_.dispatch(
620 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
622 // clear this list to save a few bytes of RAM
623 pimpl_->files_to_load_.clear();
626 pimpl_->application_->restoreGuiSession();
628 // Execute batch commands if available
629 if (pimpl_->batch_command.empty())
632 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
634 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
641 The SIGHUP signal does not exist on Windows and does not need to be handled.
643 Windows handles SIGFPE and SIGSEGV signals as expected.
645 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
646 cause a new thread to be spawned. This may well result in unexpected
647 behaviour by the single-threaded LyX.
649 SIGTERM signals will come only from another process actually sending
650 that signal using 'raise' in Windows' POSIX compatability layer. It will
651 not come from the general "terminate process" methods that everyone
652 actually uses (and which can't be trapped). Killing an app 'politely' on
653 Windows involves first sending a WM_CLOSE message, something that is
654 caught already by the Qt frontend.
656 For more information see:
658 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
659 ...signals are mostly useless on Windows for a variety of reasons that are
662 'UNIX Application Migration Guide, Chapter 9'
663 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
665 'How To Terminate an Application "Cleanly" in Win32'
666 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
670 static void error_handler(int err_sig)
672 // Throw away any signals other than the first one received.
673 static sig_atomic_t handling_error = false;
676 handling_error = true;
678 // We have received a signal indicating a fatal error, so
679 // try and save the data ASAP.
680 LyX::cref().emergencyCleanup();
682 // These lyxerr calls may or may not work:
684 // Signals are asynchronous, so the main program may be in a very
685 // fragile state when a signal is processed and thus while a signal
686 // handler function executes.
687 // In general, therefore, we should avoid performing any
688 // I/O operations or calling most library and system functions from
691 // This shouldn't matter here, however, as we've already invoked
696 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
700 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
703 lyxerr << "\nlyx: SIGSEGV signal caught\n"
704 "Sorry, you have found a bug in LyX. "
705 "Please read the bug-reporting instructions "
706 "in Help->Introduction and send us a bug report, "
707 "if necessary. Thanks !\nBye." << endl;
715 // Deinstall the signal handlers
717 signal(SIGHUP, SIG_DFL);
719 signal(SIGINT, SIG_DFL);
720 signal(SIGFPE, SIG_DFL);
721 signal(SIGSEGV, SIG_DFL);
722 signal(SIGTERM, SIG_DFL);
725 if (err_sig == SIGSEGV ||
726 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
728 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
737 void LyX::printError(ErrorItem const & ei)
739 docstring tmp = _("LyX: ") + ei.error + char_type(':')
741 cerr << to_utf8(tmp) << endl;
748 signal(SIGHUP, error_handler);
750 signal(SIGFPE, error_handler);
751 signal(SIGSEGV, error_handler);
752 signal(SIGINT, error_handler);
753 signal(SIGTERM, error_handler);
754 // SIGPIPE can be safely ignored.
756 lyxrc.tempdir_path = package().temp_dir().absFilename();
757 lyxrc.document_path = package().document_dir().absFilename();
759 if (lyxrc.example_path.empty()) {
760 lyxrc.example_path = addPath(package().system_support().absFilename(),
763 if (lyxrc.template_path.empty()) {
764 lyxrc.template_path = addPath(package().system_support().absFilename(),
769 // Read configuration files
772 // This one may have been distributed along with LyX.
773 if (!readRcFile("lyxrc.dist"))
776 // Set the language defined by the distributor.
777 //setGuiLanguage(lyxrc.gui_language);
779 // Set the PATH correctly.
780 #if !defined (USE_POSIX_PACKAGING)
781 // Add the directory containing the LyX executable to the path
782 // so that LyX can find things like tex2lyx.
783 if (package().build_support().empty())
784 prependEnvPath("PATH", package().binary_dir().absFilename());
786 if (!lyxrc.path_prefix.empty())
787 prependEnvPath("PATH", lyxrc.path_prefix);
789 // Check that user LyX directory is ok.
790 if (queryUserLyXDir(package().explicit_user_support()))
791 reconfigureUserLyXDir();
793 // no need for a splash when there is no GUI
798 // This one is generated in user_support directory by lib/configure.py.
799 if (!readRcFile("lyxrc.defaults"))
802 // Query the OS to know what formats are viewed natively
803 formats.setAutoOpen();
805 // Read lyxrc.dist again to be able to override viewer auto-detection.
806 readRcFile("lyxrc.dist");
808 system_lyxrc = lyxrc;
809 system_formats = formats;
810 pimpl_->system_converters_ = pimpl_->converters_;
811 pimpl_->system_movers_ = pimpl_->movers_;
812 system_lcolor = lcolor;
814 // This one is edited through the preferences dialog.
815 if (!readRcFile("preferences"))
818 if (!readEncodingsFile("encodings", "unicodesymbols"))
820 if (!readLanguagesFile("languages"))
824 LYXERR(Debug::INIT, "Reading layouts...");
830 // read keymap and ui files in batch mode as well
831 // because InsetInfo needs to know these to produce
832 // the correct output
834 // Set the language defined by the user.
835 //setGuiLanguage(lyxrc.gui_language);
837 // Set up command definitions
838 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
841 pimpl_->toplevel_keymap_.read("site");
842 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
843 // load user bind file user.bind
844 pimpl_->toplevel_keymap_.read("user");
846 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
849 if (!readUIFile(lyxrc.ui_file))
852 if (lyxerr.debugging(Debug::LYXRC))
855 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
856 if (!lyxrc.path_prefix.empty())
857 prependEnvPath("PATH", lyxrc.path_prefix);
859 FileName const document_path(lyxrc.document_path);
860 if (document_path.exists() && document_path.isDirectory())
861 package().document_dir() = document_path;
863 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
864 if (package().temp_dir().empty()) {
865 Alert::error(_("Could not create temporary directory"),
866 bformat(_("Could not create a temporary directory in\n"
867 "%1$s. Make sure that this\n"
868 "path exists and is writable and try again."),
869 from_utf8(lyxrc.tempdir_path)));
870 // createLyXTmpDir() tries sufficiently hard to create a
871 // usable temp dir, so the probability to come here is
872 // close to zero. We therefore don't try to overcome this
873 // problem with e.g. asking the user for a new path and
874 // trying again but simply exit.
878 LYXERR(Debug::INIT, "LyX tmp dir: `"
879 << package().temp_dir().absFilename() << '\'');
881 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
882 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
884 // This must happen after package initialization and after lyxrc is
885 // read, therefore it can't be done by a static object.
886 ConverterCache::init();
892 void LyX::emergencyCleanup() const
894 // what to do about tmpfiles is non-obvious. we would
895 // like to delete any we find, but our lyxdir might
896 // contain documents etc. which might be helpful on
899 pimpl_->buffer_list_.emergencyWriteAll();
901 if (pimpl_->lyx_server_)
902 pimpl_->lyx_server_->emergencyCleanup();
903 pimpl_->lyx_server_.reset();
904 pimpl_->lyx_socket_.reset();
909 void LyX::deadKeyBindings(KeyMap * kbmap)
911 // bindKeyings for transparent handling of deadkeys
912 // The keysyms are gotten from XFree86 X11R6
913 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
914 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
915 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
916 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
917 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
918 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
919 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
920 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
921 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
922 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
923 // nothing with this name
924 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
925 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
926 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
927 // nothing with this name either...
928 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
929 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
930 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
931 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
935 // return true if file does not exist or is older than configure.py.
936 static bool needsUpdate(string const & file)
938 // We cannot initialize configure_script directly because the package
939 // is not initialized yet when static objects are constructed.
940 static FileName configure_script;
941 static bool firstrun = true;
944 FileName(addName(package().system_support().absFilename(),
950 FileName(addName(package().user_support().absFilename(), file));
951 return !absfile.exists()
952 || configure_script.lastModified() > absfile.lastModified();
956 bool LyX::queryUserLyXDir(bool explicit_userdir)
958 // Does user directory exist?
959 FileName const sup = package().user_support();
960 if (sup.exists() && sup.isDirectory()) {
963 return needsUpdate("lyxrc.defaults")
964 || needsUpdate("lyxmodules.lst")
965 || needsUpdate("textclass.lst")
966 || needsUpdate("packages.lst");
969 first_start = !explicit_userdir;
971 // If the user specified explicitly a directory, ask whether
972 // to create it. If the user says "no", then exit.
973 if (explicit_userdir &&
975 _("Missing user LyX directory"),
976 bformat(_("You have specified a non-existent user "
977 "LyX directory, %1$s.\n"
978 "It is needed to keep your own configuration."),
979 from_utf8(package().user_support().absFilename())),
981 _("&Create directory"),
983 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
984 earlyExit(EXIT_FAILURE);
987 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
988 from_utf8(sup.absFilename()))) << endl;
990 if (!sup.createDirectory(0755)) {
991 // Failed, so let's exit.
992 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
994 earlyExit(EXIT_FAILURE);
1001 bool LyX::readRcFile(string const & name)
1003 LYXERR(Debug::INIT, "About to read " << name << "... ");
1005 FileName const lyxrc_path = libFileSearch(string(), name);
1006 if (!lyxrc_path.empty()) {
1007 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1008 if (lyxrc.read(lyxrc_path) < 0) {
1009 showFileError(name);
1013 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1019 // Read the ui file `name'
1020 bool LyX::readUIFile(string const & name, bool include)
1030 struct keyword_item uitags[ui_last - 1] = {
1031 { "include", ui_include },
1032 { "menuset", ui_menuset },
1033 { "toolbars", ui_toolbars },
1034 { "toolbarset", ui_toolbarset }
1037 // Ensure that a file is read only once (prevents include loops)
1038 static list<string> uifiles;
1039 list<string>::const_iterator it = uifiles.begin();
1040 list<string>::const_iterator end = uifiles.end();
1041 it = find(it, end, name);
1043 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1044 << "Is this an include loop?");
1048 LYXERR(Debug::INIT, "About to read " << name << "...");
1053 ui_path = libFileSearch("ui", name, "inc");
1054 if (ui_path.empty())
1055 ui_path = libFileSearch("ui",
1056 changeExtension(name, "inc"));
1059 ui_path = libFileSearch("ui", name, "ui");
1061 if (ui_path.empty()) {
1062 LYXERR(Debug::INIT, "Could not find " << name);
1063 showFileError(name);
1067 uifiles.push_back(name);
1069 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1070 Lexer lex(uitags, ui_last - 1);
1071 lex.setFile(ui_path);
1073 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1077 if (lyxerr.debugging(Debug::PARSER))
1078 lex.printTable(lyxerr);
1080 while (lex.isOK()) {
1081 switch (lex.lex()) {
1084 string const file = lex.getString();
1085 if (!readUIFile(file, true))
1090 theApp()->menuBackend().read(lex);
1094 toolbarbackend.readToolbars(lex);
1098 toolbarbackend.readToolbarSettings(lex);
1102 if (!rtrim(lex.getString()).empty())
1103 lex.printError("LyX::ReadUIFile: "
1104 "Unknown menu tag: `$$Token'");
1112 // Read the languages file `name'
1113 bool LyX::readLanguagesFile(string const & name)
1115 LYXERR(Debug::INIT, "About to read " << name << "...");
1117 FileName const lang_path = libFileSearch(string(), name);
1118 if (lang_path.empty()) {
1119 showFileError(name);
1122 languages.read(lang_path);
1127 // Read the encodings file `name'
1128 bool LyX::readEncodingsFile(string const & enc_name,
1129 string const & symbols_name)
1131 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1132 << symbols_name << "...");
1134 FileName const symbols_path = libFileSearch(string(), symbols_name);
1135 if (symbols_path.empty()) {
1136 showFileError(symbols_name);
1140 FileName const enc_path = libFileSearch(string(), enc_name);
1141 if (enc_path.empty()) {
1142 showFileError(enc_name);
1145 encodings.read(enc_path, symbols_path);
1154 /// return the the number of arguments consumed
1155 typedef boost::function<int(string const &, string const &)> cmd_helper;
1157 int parse_dbg(string const & arg, string const &)
1160 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1161 Debug::showTags(lyxerr);
1164 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1166 lyxerr.level(Debug::value(arg));
1167 Debug::showLevel(lyxerr, lyxerr.level());
1172 int parse_help(string const &, string const &)
1175 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1176 "Command line switches (case sensitive):\n"
1177 "\t-help summarize LyX usage\n"
1178 "\t-userdir dir set user directory to dir\n"
1179 "\t-sysdir dir set system directory to dir\n"
1180 "\t-geometry WxH+X+Y set geometry of the main window\n"
1181 "\t-dbg feature[,feature]...\n"
1182 " select the features to debug.\n"
1183 " Type `lyx -dbg' to see the list of features\n"
1184 "\t-x [--execute] command\n"
1185 " where command is a lyx command.\n"
1186 "\t-e [--export] fmt\n"
1187 " where fmt is the export format of choice.\n"
1188 " Look on Tools->Preferences->File formats->Format\n"
1189 " to get an idea which parameters should be passed.\n"
1190 "\t-i [--import] fmt file.xxx\n"
1191 " where fmt is the import format of choice\n"
1192 " and file.xxx is the file to be imported.\n"
1193 "\t-version summarize version and build info\n"
1194 "Check the LyX man page for more details.")) << endl;
1200 int parse_version(string const &, string const &)
1202 lyxerr << "LyX " << lyx_version
1203 << " (" << lyx_release_date << ")" << endl;
1204 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1206 lyxerr << lyx_version_info << endl;
1212 int parse_sysdir(string const & arg, string const &)
1215 Alert::error(_("No system directory"),
1216 _("Missing directory for -sysdir switch"));
1219 cl_system_support = arg;
1224 int parse_userdir(string const & arg, string const &)
1227 Alert::error(_("No user directory"),
1228 _("Missing directory for -userdir switch"));
1231 cl_user_support = arg;
1236 int parse_execute(string const & arg, string const &)
1239 Alert::error(_("Incomplete command"),
1240 _("Missing command string after --execute switch"));
1248 int parse_export(string const & type, string const &)
1251 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1252 "--export switch")) << endl;
1255 batch = "buffer-export " + type;
1261 int parse_import(string const & type, string const & file)
1264 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1265 "--import switch")) << endl;
1269 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1273 batch = "buffer-import " + type + ' ' + file;
1278 int parse_geometry(string const & arg1, string const &)
1281 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1282 // remove also the arg
1285 // don't remove "-geometry"
1294 void LyX::easyParse(int & argc, char * argv[])
1296 map<string, cmd_helper> cmdmap;
1298 cmdmap["-dbg"] = parse_dbg;
1299 cmdmap["-help"] = parse_help;
1300 cmdmap["--help"] = parse_help;
1301 cmdmap["-version"] = parse_version;
1302 cmdmap["--version"] = parse_version;
1303 cmdmap["-sysdir"] = parse_sysdir;
1304 cmdmap["-userdir"] = parse_userdir;
1305 cmdmap["-x"] = parse_execute;
1306 cmdmap["--execute"] = parse_execute;
1307 cmdmap["-e"] = parse_export;
1308 cmdmap["--export"] = parse_export;
1309 cmdmap["-i"] = parse_import;
1310 cmdmap["--import"] = parse_import;
1311 cmdmap["-geometry"] = parse_geometry;
1313 for (int i = 1; i < argc; ++i) {
1314 map<string, cmd_helper>::const_iterator it
1315 = cmdmap.find(argv[i]);
1317 // don't complain if not found - may be parsed later
1318 if (it == cmdmap.end())
1322 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1324 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1326 int const remove = 1 + it->second(arg, arg2);
1328 // Now, remove used arguments by shifting
1329 // the following ones remove places down.
1332 for (int j = i; j < argc; ++j)
1333 argv[j] = argv[j + remove];
1338 pimpl_->batch_command = batch;
1342 FuncStatus getStatus(FuncRequest const & action)
1344 return LyX::ref().lyxFunc().getStatus(action);
1348 void dispatch(FuncRequest const & action)
1350 LyX::ref().lyxFunc().dispatch(action);
1354 BufferList & theBufferList()
1356 return LyX::ref().bufferList();
1360 LyXFunc & theLyXFunc()
1362 return LyX::ref().lyxFunc();
1366 Server & theServer()
1368 // FIXME: this should not be use_gui dependent
1369 BOOST_ASSERT(use_gui);
1370 return LyX::ref().server();
1374 ServerSocket & theServerSocket()
1376 // FIXME: this should not be use_gui dependent
1377 BOOST_ASSERT(use_gui);
1378 return LyX::ref().socket();
1382 KeyMap & theTopLevelKeymap()
1384 return LyX::ref().topLevelKeymap();
1388 Converters & theConverters()
1390 return LyX::ref().converters();
1394 Converters & theSystemConverters()
1396 return LyX::ref().systemConverters();
1400 Movers & theMovers()
1402 return LyX::ref().pimpl_->movers_;
1406 Mover const & getMover(string const & fmt)
1408 return LyX::ref().pimpl_->movers_(fmt);
1412 void setMover(string const & fmt, string const & command)
1414 LyX::ref().pimpl_->movers_.set(fmt, command);
1418 Movers & theSystemMovers()
1420 return LyX::ref().pimpl_->system_movers_;
1424 Messages & getMessages(string const & language)
1426 return LyX::ref().getMessages(language);
1430 Messages & getGuiMessages()
1432 return LyX::ref().getGuiMessages();