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 BufferList::iterator I = theBufferList().begin();
629 BufferList::iterator end = theBufferList().end();
630 for (; I != end; ++I) {
632 if (buf != buf->masterBuffer())
637 // Execute batch commands if available
638 if (pimpl_->batch_command.empty())
641 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
643 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
650 The SIGHUP signal does not exist on Windows and does not need to be handled.
652 Windows handles SIGFPE and SIGSEGV signals as expected.
654 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
655 cause a new thread to be spawned. This may well result in unexpected
656 behaviour by the single-threaded LyX.
658 SIGTERM signals will come only from another process actually sending
659 that signal using 'raise' in Windows' POSIX compatability layer. It will
660 not come from the general "terminate process" methods that everyone
661 actually uses (and which can't be trapped). Killing an app 'politely' on
662 Windows involves first sending a WM_CLOSE message, something that is
663 caught already by the Qt frontend.
665 For more information see:
667 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
668 ...signals are mostly useless on Windows for a variety of reasons that are
671 'UNIX Application Migration Guide, Chapter 9'
672 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
674 'How To Terminate an Application "Cleanly" in Win32'
675 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
679 static void error_handler(int err_sig)
681 // Throw away any signals other than the first one received.
682 static sig_atomic_t handling_error = false;
685 handling_error = true;
687 // We have received a signal indicating a fatal error, so
688 // try and save the data ASAP.
689 LyX::cref().emergencyCleanup();
691 // These lyxerr calls may or may not work:
693 // Signals are asynchronous, so the main program may be in a very
694 // fragile state when a signal is processed and thus while a signal
695 // handler function executes.
696 // In general, therefore, we should avoid performing any
697 // I/O operations or calling most library and system functions from
700 // This shouldn't matter here, however, as we've already invoked
705 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
709 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
712 lyxerr << "\nlyx: SIGSEGV signal caught\n"
713 "Sorry, you have found a bug in LyX. "
714 "Please read the bug-reporting instructions "
715 "in Help->Introduction and send us a bug report, "
716 "if necessary. Thanks !\nBye." << endl;
724 // Deinstall the signal handlers
726 signal(SIGHUP, SIG_DFL);
728 signal(SIGINT, SIG_DFL);
729 signal(SIGFPE, SIG_DFL);
730 signal(SIGSEGV, SIG_DFL);
731 signal(SIGTERM, SIG_DFL);
734 if (err_sig == SIGSEGV ||
735 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
737 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
746 void LyX::printError(ErrorItem const & ei)
748 docstring tmp = _("LyX: ") + ei.error + char_type(':')
750 cerr << to_utf8(tmp) << endl;
757 signal(SIGHUP, error_handler);
759 signal(SIGFPE, error_handler);
760 signal(SIGSEGV, error_handler);
761 signal(SIGINT, error_handler);
762 signal(SIGTERM, error_handler);
763 // SIGPIPE can be safely ignored.
765 lyxrc.tempdir_path = package().temp_dir().absFilename();
766 lyxrc.document_path = package().document_dir().absFilename();
768 if (lyxrc.example_path.empty()) {
769 lyxrc.example_path = addPath(package().system_support().absFilename(),
772 if (lyxrc.template_path.empty()) {
773 lyxrc.template_path = addPath(package().system_support().absFilename(),
778 // Read configuration files
781 // This one may have been distributed along with LyX.
782 if (!readRcFile("lyxrc.dist"))
785 // Set the language defined by the distributor.
786 //setGuiLanguage(lyxrc.gui_language);
788 // Set the PATH correctly.
789 #if !defined (USE_POSIX_PACKAGING)
790 // Add the directory containing the LyX executable to the path
791 // so that LyX can find things like tex2lyx.
792 if (package().build_support().empty())
793 prependEnvPath("PATH", package().binary_dir().absFilename());
795 if (!lyxrc.path_prefix.empty())
796 prependEnvPath("PATH", lyxrc.path_prefix);
798 // Check that user LyX directory is ok.
799 if (queryUserLyXDir(package().explicit_user_support()))
800 reconfigureUserLyXDir();
802 // no need for a splash when there is no GUI
807 // This one is generated in user_support directory by lib/configure.py.
808 if (!readRcFile("lyxrc.defaults"))
811 // Query the OS to know what formats are viewed natively
812 formats.setAutoOpen();
814 // Read lyxrc.dist again to be able to override viewer auto-detection.
815 readRcFile("lyxrc.dist");
817 system_lyxrc = lyxrc;
818 system_formats = formats;
819 pimpl_->system_converters_ = pimpl_->converters_;
820 pimpl_->system_movers_ = pimpl_->movers_;
821 system_lcolor = lcolor;
823 // This one is edited through the preferences dialog.
824 if (!readRcFile("preferences"))
827 if (!readEncodingsFile("encodings", "unicodesymbols"))
829 if (!readLanguagesFile("languages"))
833 LYXERR(Debug::INIT, "Reading layouts...");
839 // read keymap and ui files in batch mode as well
840 // because InsetInfo needs to know these to produce
841 // the correct output
843 // Set the language defined by the user.
844 //setGuiLanguage(lyxrc.gui_language);
846 // Set up command definitions
847 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
850 pimpl_->toplevel_keymap_.read("site");
851 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
852 // load user bind file user.bind
853 pimpl_->toplevel_keymap_.read("user");
855 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
858 if (!readUIFile(lyxrc.ui_file))
861 if (lyxerr.debugging(Debug::LYXRC))
864 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
865 if (!lyxrc.path_prefix.empty())
866 prependEnvPath("PATH", lyxrc.path_prefix);
868 FileName const document_path(lyxrc.document_path);
869 if (document_path.exists() && document_path.isDirectory())
870 package().document_dir() = document_path;
872 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
873 if (package().temp_dir().empty()) {
874 Alert::error(_("Could not create temporary directory"),
875 bformat(_("Could not create a temporary directory in\n"
876 "%1$s. Make sure that this\n"
877 "path exists and is writable and try again."),
878 from_utf8(lyxrc.tempdir_path)));
879 // createLyXTmpDir() tries sufficiently hard to create a
880 // usable temp dir, so the probability to come here is
881 // close to zero. We therefore don't try to overcome this
882 // problem with e.g. asking the user for a new path and
883 // trying again but simply exit.
887 LYXERR(Debug::INIT, "LyX tmp dir: `"
888 << package().temp_dir().absFilename() << '\'');
890 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
891 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
893 // This must happen after package initialization and after lyxrc is
894 // read, therefore it can't be done by a static object.
895 ConverterCache::init();
901 void LyX::emergencyCleanup() const
903 // what to do about tmpfiles is non-obvious. we would
904 // like to delete any we find, but our lyxdir might
905 // contain documents etc. which might be helpful on
908 pimpl_->buffer_list_.emergencyWriteAll();
910 if (pimpl_->lyx_server_)
911 pimpl_->lyx_server_->emergencyCleanup();
912 pimpl_->lyx_server_.reset();
913 pimpl_->lyx_socket_.reset();
918 void LyX::deadKeyBindings(KeyMap * kbmap)
920 // bindKeyings for transparent handling of deadkeys
921 // The keysyms are gotten from XFree86 X11R6
922 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
923 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
924 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
925 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
926 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
927 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
928 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
929 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
930 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
931 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
932 // nothing with this name
933 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
934 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
935 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
936 // nothing with this name either...
937 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
938 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
939 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
940 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
944 // return true if file does not exist or is older than configure.py.
945 static bool needsUpdate(string const & file)
947 // We cannot initialize configure_script directly because the package
948 // is not initialized yet when static objects are constructed.
949 static FileName configure_script;
950 static bool firstrun = true;
953 FileName(addName(package().system_support().absFilename(),
959 FileName(addName(package().user_support().absFilename(), file));
960 return !absfile.exists()
961 || configure_script.lastModified() > absfile.lastModified();
965 bool LyX::queryUserLyXDir(bool explicit_userdir)
967 // Does user directory exist?
968 FileName const sup = package().user_support();
969 if (sup.exists() && sup.isDirectory()) {
972 return needsUpdate("lyxrc.defaults")
973 || needsUpdate("lyxmodules.lst")
974 || needsUpdate("textclass.lst")
975 || needsUpdate("packages.lst");
978 first_start = !explicit_userdir;
980 // If the user specified explicitly a directory, ask whether
981 // to create it. If the user says "no", then exit.
982 if (explicit_userdir &&
984 _("Missing user LyX directory"),
985 bformat(_("You have specified a non-existent user "
986 "LyX directory, %1$s.\n"
987 "It is needed to keep your own configuration."),
988 from_utf8(package().user_support().absFilename())),
990 _("&Create directory"),
992 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
993 earlyExit(EXIT_FAILURE);
996 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
997 from_utf8(sup.absFilename()))) << endl;
999 if (!sup.createDirectory(0755)) {
1000 // Failed, so let's exit.
1001 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1003 earlyExit(EXIT_FAILURE);
1010 bool LyX::readRcFile(string const & name)
1012 LYXERR(Debug::INIT, "About to read " << name << "... ");
1014 FileName const lyxrc_path = libFileSearch(string(), name);
1015 if (!lyxrc_path.empty()) {
1016 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1017 if (lyxrc.read(lyxrc_path) < 0) {
1018 showFileError(name);
1022 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1028 // Read the ui file `name'
1029 bool LyX::readUIFile(string const & name, bool include)
1039 struct keyword_item uitags[ui_last - 1] = {
1040 { "include", ui_include },
1041 { "menuset", ui_menuset },
1042 { "toolbars", ui_toolbars },
1043 { "toolbarset", ui_toolbarset }
1046 // Ensure that a file is read only once (prevents include loops)
1047 static list<string> uifiles;
1048 list<string>::const_iterator it = uifiles.begin();
1049 list<string>::const_iterator end = uifiles.end();
1050 it = find(it, end, name);
1052 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1053 << "Is this an include loop?");
1057 LYXERR(Debug::INIT, "About to read " << name << "...");
1062 ui_path = libFileSearch("ui", name, "inc");
1063 if (ui_path.empty())
1064 ui_path = libFileSearch("ui",
1065 changeExtension(name, "inc"));
1068 ui_path = libFileSearch("ui", name, "ui");
1070 if (ui_path.empty()) {
1071 LYXERR(Debug::INIT, "Could not find " << name);
1072 showFileError(name);
1076 uifiles.push_back(name);
1078 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1079 Lexer lex(uitags, ui_last - 1);
1080 lex.setFile(ui_path);
1082 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1086 if (lyxerr.debugging(Debug::PARSER))
1087 lex.printTable(lyxerr);
1089 while (lex.isOK()) {
1090 switch (lex.lex()) {
1093 string const file = lex.getString();
1094 if (!readUIFile(file, true))
1099 theApp()->menuBackend().read(lex);
1103 toolbarbackend.readToolbars(lex);
1107 toolbarbackend.readToolbarSettings(lex);
1111 if (!rtrim(lex.getString()).empty())
1112 lex.printError("LyX::ReadUIFile: "
1113 "Unknown menu tag: `$$Token'");
1121 // Read the languages file `name'
1122 bool LyX::readLanguagesFile(string const & name)
1124 LYXERR(Debug::INIT, "About to read " << name << "...");
1126 FileName const lang_path = libFileSearch(string(), name);
1127 if (lang_path.empty()) {
1128 showFileError(name);
1131 languages.read(lang_path);
1136 // Read the encodings file `name'
1137 bool LyX::readEncodingsFile(string const & enc_name,
1138 string const & symbols_name)
1140 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1141 << symbols_name << "...");
1143 FileName const symbols_path = libFileSearch(string(), symbols_name);
1144 if (symbols_path.empty()) {
1145 showFileError(symbols_name);
1149 FileName const enc_path = libFileSearch(string(), enc_name);
1150 if (enc_path.empty()) {
1151 showFileError(enc_name);
1154 encodings.read(enc_path, symbols_path);
1163 /// return the the number of arguments consumed
1164 typedef boost::function<int(string const &, string const &)> cmd_helper;
1166 int parse_dbg(string const & arg, string const &)
1169 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1170 Debug::showTags(lyxerr);
1173 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1175 lyxerr.level(Debug::value(arg));
1176 Debug::showLevel(lyxerr, lyxerr.level());
1181 int parse_help(string const &, string const &)
1184 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1185 "Command line switches (case sensitive):\n"
1186 "\t-help summarize LyX usage\n"
1187 "\t-userdir dir set user directory to dir\n"
1188 "\t-sysdir dir set system directory to dir\n"
1189 "\t-geometry WxH+X+Y set geometry of the main window\n"
1190 "\t-dbg feature[,feature]...\n"
1191 " select the features to debug.\n"
1192 " Type `lyx -dbg' to see the list of features\n"
1193 "\t-x [--execute] command\n"
1194 " where command is a lyx command.\n"
1195 "\t-e [--export] fmt\n"
1196 " where fmt is the export format of choice.\n"
1197 " Look on Tools->Preferences->File formats->Format\n"
1198 " to get an idea which parameters should be passed.\n"
1199 "\t-i [--import] fmt file.xxx\n"
1200 " where fmt is the import format of choice\n"
1201 " and file.xxx is the file to be imported.\n"
1202 "\t-version summarize version and build info\n"
1203 "Check the LyX man page for more details.")) << endl;
1209 int parse_version(string const &, string const &)
1211 lyxerr << "LyX " << lyx_version
1212 << " (" << lyx_release_date << ")" << endl;
1213 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1215 lyxerr << lyx_version_info << endl;
1221 int parse_sysdir(string const & arg, string const &)
1224 Alert::error(_("No system directory"),
1225 _("Missing directory for -sysdir switch"));
1228 cl_system_support = arg;
1233 int parse_userdir(string const & arg, string const &)
1236 Alert::error(_("No user directory"),
1237 _("Missing directory for -userdir switch"));
1240 cl_user_support = arg;
1245 int parse_execute(string const & arg, string const &)
1248 Alert::error(_("Incomplete command"),
1249 _("Missing command string after --execute switch"));
1257 int parse_export(string const & type, string const &)
1260 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1261 "--export switch")) << endl;
1264 batch = "buffer-export " + type;
1270 int parse_import(string const & type, string const & file)
1273 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1274 "--import switch")) << endl;
1278 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1282 batch = "buffer-import " + type + ' ' + file;
1287 int parse_geometry(string const & arg1, string const &)
1290 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1291 // remove also the arg
1294 // don't remove "-geometry"
1303 void LyX::easyParse(int & argc, char * argv[])
1305 map<string, cmd_helper> cmdmap;
1307 cmdmap["-dbg"] = parse_dbg;
1308 cmdmap["-help"] = parse_help;
1309 cmdmap["--help"] = parse_help;
1310 cmdmap["-version"] = parse_version;
1311 cmdmap["--version"] = parse_version;
1312 cmdmap["-sysdir"] = parse_sysdir;
1313 cmdmap["-userdir"] = parse_userdir;
1314 cmdmap["-x"] = parse_execute;
1315 cmdmap["--execute"] = parse_execute;
1316 cmdmap["-e"] = parse_export;
1317 cmdmap["--export"] = parse_export;
1318 cmdmap["-i"] = parse_import;
1319 cmdmap["--import"] = parse_import;
1320 cmdmap["-geometry"] = parse_geometry;
1322 for (int i = 1; i < argc; ++i) {
1323 map<string, cmd_helper>::const_iterator it
1324 = cmdmap.find(argv[i]);
1326 // don't complain if not found - may be parsed later
1327 if (it == cmdmap.end())
1331 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1333 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1335 int const remove = 1 + it->second(arg, arg2);
1337 // Now, remove used arguments by shifting
1338 // the following ones remove places down.
1341 for (int j = i; j < argc; ++j)
1342 argv[j] = argv[j + remove];
1347 pimpl_->batch_command = batch;
1351 FuncStatus getStatus(FuncRequest const & action)
1353 return LyX::ref().lyxFunc().getStatus(action);
1357 void dispatch(FuncRequest const & action)
1359 LyX::ref().lyxFunc().dispatch(action);
1363 BufferList & theBufferList()
1365 return LyX::ref().bufferList();
1369 LyXFunc & theLyXFunc()
1371 return LyX::ref().lyxFunc();
1375 Server & theServer()
1377 // FIXME: this should not be use_gui dependent
1378 BOOST_ASSERT(use_gui);
1379 return LyX::ref().server();
1383 ServerSocket & theServerSocket()
1385 // FIXME: this should not be use_gui dependent
1386 BOOST_ASSERT(use_gui);
1387 return LyX::ref().socket();
1391 KeyMap & theTopLevelKeymap()
1393 return LyX::ref().topLevelKeymap();
1397 Converters & theConverters()
1399 return LyX::ref().converters();
1403 Converters & theSystemConverters()
1405 return LyX::ref().systemConverters();
1409 Movers & theMovers()
1411 return LyX::ref().pimpl_->movers_;
1415 Mover const & getMover(string const & fmt)
1417 return LyX::ref().pimpl_->movers_(fmt);
1421 void setMover(string const & fmt, string const & command)
1423 LyX::ref().pimpl_->movers_.set(fmt, command);
1427 Movers & theSystemMovers()
1429 return LyX::ref().pimpl_->system_movers_;
1433 Messages & getMessages(string const & language)
1435 return LyX::ref().getMessages(language);
1439 Messages & getGuiMessages()
1441 return LyX::ref().getGuiMessages();